diff --git a/.gitignore b/.gitignore index a7f32ddf..c83d5c9c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,4 @@ fastlane/report.xml fastlane/test_output # SwiftPM -swiftpm/ - -# Mac -.DS_Store \ No newline at end of file +swiftpm/ \ No newline at end of file diff --git a/FlexLayout.xcodeproj/project.pbxproj b/FlexLayout.xcodeproj/project.pbxproj index ae361dae..f2af5127 100644 --- a/FlexLayout.xcodeproj/project.pbxproj +++ b/FlexLayout.xcodeproj/project.pbxproj @@ -19,42 +19,30 @@ 24AE97411FEAF30A00995987 /* UIView+FlexLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24AE97321FEAF30A00995987 /* UIView+FlexLayout.swift */; }; 24AE97421FEAF30A00995987 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24AE97331FEAF30A00995987 /* Percent.swift */; }; 24AE97431FEAF30A00995987 /* FlexLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 24AE97351FEAF30A00995987 /* FlexLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 24AE97451FEAF30A00995987 /* UIView+Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 24AE97381FEAF30A00995987 /* UIView+Yoga.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 24AE97461FEAF30A00995987 /* UIView+Yoga.mm in Sources */ = {isa = PBXBuildFile; fileRef = 24AE97391FEAF30A00995987 /* UIView+Yoga.mm */; }; + 24AE97471FEAF30A00995987 /* YGLayout+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 24AE973A1FEAF30A00995987 /* YGLayout+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 24AE97491FEAF30A00995987 /* YGLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 24AE973C1FEAF30A00995987 /* YGLayout.mm */; }; 24AE974A1FEAF30A00995987 /* YGLayoutExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24AE973D1FEAF30A00995987 /* YGLayoutExtensions.swift */; }; 24DA37691EF843C500D1AB2F /* FlexLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24DA37681EF843C500D1AB2F /* FlexLayoutTests.swift */; }; 24FB88591F5ED2B800615D33 /* JustifyContentSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FB88581F5ED2B800615D33 /* JustifyContentSpec.swift */; }; - 715C61502ABEDE1900D5A2E0 /* YGFloatOptional.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61312ABEDE1900D5A2E0 /* YGFloatOptional.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61512ABEDE1900D5A2E0 /* Utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61322ABEDE1900D5A2E0 /* Utils.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61522ABEDE1900D5A2E0 /* CompactValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61332ABEDE1900D5A2E0 /* CompactValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61532ABEDE1900D5A2E0 /* Yoga-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61342ABEDE1900D5A2E0 /* Yoga-internal.h */; }; - 715C61542ABEDE1900D5A2E0 /* YGLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61352ABEDE1900D5A2E0 /* YGLayout.h */; }; - 715C61552ABEDE1900D5A2E0 /* log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C61362ABEDE1900D5A2E0 /* log.cpp */; }; - 715C61562ABEDE1900D5A2E0 /* Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C61372ABEDE1900D5A2E0 /* Utils.cpp */; }; - 715C61572ABEDE1900D5A2E0 /* CMakeLists.txt in Resources */ = {isa = PBXBuildFile; fileRef = 715C61382ABEDE1900D5A2E0 /* CMakeLists.txt */; }; - 715C61582ABEDE1900D5A2E0 /* YGNodePrint.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61392ABEDE1900D5A2E0 /* YGNodePrint.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61592ABEDE1900D5A2E0 /* YGLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C613A2ABEDE1900D5A2E0 /* YGLayout.cpp */; }; - 715C615A2ABEDE1900D5A2E0 /* YGNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C613B2ABEDE1900D5A2E0 /* YGNode.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C615B2ABEDE1900D5A2E0 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C613C2ABEDE1900D5A2E0 /* Yoga.cpp */; }; - 715C615C2ABEDE1900D5A2E0 /* YGStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C613D2ABEDE1900D5A2E0 /* YGStyle.cpp */; }; - 715C615D2ABEDE1900D5A2E0 /* YGEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61402ABEDE1900D5A2E0 /* YGEnums.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C615E2ABEDE1900D5A2E0 /* YGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61412ABEDE1900D5A2E0 /* YGMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C615F2ABEDE1900D5A2E0 /* Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61422ABEDE1900D5A2E0 /* Yoga.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C61602ABEDE1900D5A2E0 /* YGValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61432ABEDE1900D5A2E0 /* YGValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C61612ABEDE1900D5A2E0 /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C61442ABEDE1900D5A2E0 /* YGNodePrint.cpp */; }; - 715C61622ABEDE1900D5A2E0 /* YGStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61452ABEDE1900D5A2E0 /* YGStyle.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61632ABEDE1900D5A2E0 /* YGEnums.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C61462ABEDE1900D5A2E0 /* YGEnums.cpp */; }; - 715C61642ABEDE1900D5A2E0 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61472ABEDE1900D5A2E0 /* log.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61652ABEDE1900D5A2E0 /* YGValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C61482ABEDE1900D5A2E0 /* YGValue.cpp */; }; - 715C61662ABEDE1900D5A2E0 /* BitUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C61492ABEDE1900D5A2E0 /* BitUtils.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61672ABEDE1900D5A2E0 /* YGConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C614A2ABEDE1900D5A2E0 /* YGConfig.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C61682ABEDE1900D5A2E0 /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C614B2ABEDE1900D5A2E0 /* YGConfig.cpp */; }; - 715C61692ABEDE1900D5A2E0 /* YGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C614C2ABEDE1900D5A2E0 /* YGNode.cpp */; }; - 715C616A2ABEDE1900D5A2E0 /* event.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C614E2ABEDE1900D5A2E0 /* event.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 715C616B2ABEDE1900D5A2E0 /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 715C614F2ABEDE1900D5A2E0 /* event.cpp */; }; - 715C61812ABEE4B600D5A2E0 /* UIView+Yoga.mm in Sources */ = {isa = PBXBuildFile; fileRef = 715C617A2ABEE4B600D5A2E0 /* UIView+Yoga.mm */; }; - 715C61822ABEE4B600D5A2E0 /* YGLayout+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C617D2ABEE4B600D5A2E0 /* YGLayout+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C61832ABEE4B600D5A2E0 /* YGLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C617E2ABEE4B600D5A2E0 /* YGLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C61842ABEE4B600D5A2E0 /* UIView+Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 715C617F2ABEE4B600D5A2E0 /* UIView+Yoga.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 715C61852ABEE4B600D5A2E0 /* YGLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 715C61802ABEE4B600D5A2E0 /* YGLayout.mm */; }; + B9EAD884238896C50058E0CB /* Yoga-internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B9EAD883238896C50058E0CB /* Yoga-internal.h */; }; + B9EAD888238947B00058E0CB /* YGLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = B9EAD887238947B00058E0CB /* YGLayout.h */; }; + B9EAD88A238947C70058E0CB /* YGLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = B9EAD889238947C70058E0CB /* YGLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C07B09F32045303000E03251 /* YGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09E32045302F00E03251 /* YGNode.cpp */; }; + C07B09F42045303000E03251 /* YGStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09E42045303000E03251 /* YGStyle.cpp */; }; + C07B09F52045303000E03251 /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09E52045303000E03251 /* Yoga.cpp */; }; + C07B09F62045303000E03251 /* YGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09E62045303000E03251 /* YGMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C07B09F72045303000E03251 /* YGEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09E72045303000E03251 /* YGEnums.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C07B09F82045303000E03251 /* Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09E82045303000E03251 /* Utils.cpp */; }; + C07B09F92045303000E03251 /* YGNode.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09E92045303000E03251 /* YGNode.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C07B09FB2045303000E03251 /* YGLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09EB2045303000E03251 /* YGLayout.cpp */; }; + C07B09FC2045303000E03251 /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09EC2045303000E03251 /* YGNodePrint.cpp */; }; + C07B09FD2045303000E03251 /* Utils.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09ED2045303000E03251 /* Utils.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C07B09FF2045303000E03251 /* Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09EF2045303000E03251 /* Yoga.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C07B0A002045303000E03251 /* YGEnums.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C07B09F02045303000E03251 /* YGEnums.cpp */; }; + C07B0A012045303000E03251 /* YGStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09F12045303000E03251 /* YGStyle.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C07B0A022045303000E03251 /* YGNodePrint.h in Headers */ = {isa = PBXBuildFile; fileRef = C07B09F22045303000E03251 /* YGNodePrint.h */; settings = {ATTRIBUTES = (Private, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -95,6 +83,10 @@ 24AE97331FEAF30A00995987 /* Percent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Percent.swift; sourceTree = ""; }; 24AE97351FEAF30A00995987 /* FlexLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlexLayout.h; sourceTree = ""; }; 24AE97361FEAF30A00995987 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 24AE97381FEAF30A00995987 /* UIView+Yoga.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Yoga.h"; sourceTree = ""; }; + 24AE97391FEAF30A00995987 /* UIView+Yoga.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIView+Yoga.mm"; sourceTree = ""; tabWidth = 2; }; + 24AE973A1FEAF30A00995987 /* YGLayout+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YGLayout+Private.h"; sourceTree = ""; }; + 24AE973C1FEAF30A00995987 /* YGLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = YGLayout.mm; sourceTree = ""; tabWidth = 2; }; 24AE973D1FEAF30A00995987 /* YGLayoutExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YGLayoutExtensions.swift; sourceTree = ""; }; 24DA375A1EF843C500D1AB2F /* FlexLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FlexLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24DA37631EF843C500D1AB2F /* FlexLayoutTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FlexLayoutTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -102,39 +94,23 @@ 24FB88581F5ED2B800615D33 /* JustifyContentSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JustifyContentSpec.swift; sourceTree = ""; }; 2B210ECFE9D7665DACB8E8A7 /* Pods-FlexLayoutTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlexLayoutTests.debug.xcconfig"; path = "Target Support Files/Pods-FlexLayoutTests/Pods-FlexLayoutTests.debug.xcconfig"; sourceTree = ""; }; 38E690AA4AF8EDFC95DB6626 /* Pods-FlexLayoutTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlexLayoutTests.release.xcconfig"; path = "Target Support Files/Pods-FlexLayoutTests/Pods-FlexLayoutTests.release.xcconfig"; sourceTree = ""; }; - 715C61312ABEDE1900D5A2E0 /* YGFloatOptional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGFloatOptional.h; sourceTree = ""; }; - 715C61322ABEDE1900D5A2E0 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; }; - 715C61332ABEDE1900D5A2E0 /* CompactValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompactValue.h; sourceTree = ""; }; - 715C61342ABEDE1900D5A2E0 /* Yoga-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Yoga-internal.h"; sourceTree = ""; }; - 715C61352ABEDE1900D5A2E0 /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGLayout.h; sourceTree = ""; }; - 715C61362ABEDE1900D5A2E0 /* log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = log.cpp; sourceTree = ""; }; - 715C61372ABEDE1900D5A2E0 /* Utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utils.cpp; sourceTree = ""; }; - 715C61382ABEDE1900D5A2E0 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; - 715C61392ABEDE1900D5A2E0 /* YGNodePrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNodePrint.h; sourceTree = ""; }; - 715C613A2ABEDE1900D5A2E0 /* YGLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGLayout.cpp; sourceTree = ""; }; - 715C613B2ABEDE1900D5A2E0 /* YGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNode.h; sourceTree = ""; }; - 715C613C2ABEDE1900D5A2E0 /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Yoga.cpp; sourceTree = ""; }; - 715C613D2ABEDE1900D5A2E0 /* YGStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGStyle.cpp; sourceTree = ""; }; - 715C61402ABEDE1900D5A2E0 /* YGEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGEnums.h; sourceTree = ""; }; - 715C61412ABEDE1900D5A2E0 /* YGMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGMacros.h; sourceTree = ""; }; - 715C61422ABEDE1900D5A2E0 /* Yoga.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Yoga.h; sourceTree = ""; }; - 715C61432ABEDE1900D5A2E0 /* YGValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGValue.h; sourceTree = ""; }; - 715C61442ABEDE1900D5A2E0 /* YGNodePrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNodePrint.cpp; sourceTree = ""; }; - 715C61452ABEDE1900D5A2E0 /* YGStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGStyle.h; sourceTree = ""; }; - 715C61462ABEDE1900D5A2E0 /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGEnums.cpp; sourceTree = ""; }; - 715C61472ABEDE1900D5A2E0 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = ""; }; - 715C61482ABEDE1900D5A2E0 /* YGValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGValue.cpp; sourceTree = ""; }; - 715C61492ABEDE1900D5A2E0 /* BitUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitUtils.h; sourceTree = ""; }; - 715C614A2ABEDE1900D5A2E0 /* YGConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGConfig.h; sourceTree = ""; }; - 715C614B2ABEDE1900D5A2E0 /* YGConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGConfig.cpp; sourceTree = ""; }; - 715C614C2ABEDE1900D5A2E0 /* YGNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNode.cpp; sourceTree = ""; }; - 715C614E2ABEDE1900D5A2E0 /* event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = event.h; sourceTree = ""; }; - 715C614F2ABEDE1900D5A2E0 /* event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = event.cpp; sourceTree = ""; }; - 715C617A2ABEE4B600D5A2E0 /* UIView+Yoga.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIView+Yoga.mm"; sourceTree = ""; }; - 715C617D2ABEE4B600D5A2E0 /* YGLayout+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YGLayout+Private.h"; sourceTree = ""; }; - 715C617E2ABEE4B600D5A2E0 /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGLayout.h; sourceTree = ""; }; - 715C617F2ABEE4B600D5A2E0 /* UIView+Yoga.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Yoga.h"; sourceTree = ""; }; - 715C61802ABEE4B600D5A2E0 /* YGLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = YGLayout.mm; sourceTree = ""; tabWidth = 2; }; + B9EAD883238896C50058E0CB /* Yoga-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Yoga-internal.h"; sourceTree = ""; }; + B9EAD887238947B00058E0CB /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGLayout.h; sourceTree = ""; }; + B9EAD889238947C70058E0CB /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGLayout.h; sourceTree = ""; }; + C07B09E32045302F00E03251 /* YGNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNode.cpp; sourceTree = ""; }; + C07B09E42045303000E03251 /* YGStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGStyle.cpp; sourceTree = ""; }; + C07B09E52045303000E03251 /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Yoga.cpp; sourceTree = ""; }; + C07B09E62045303000E03251 /* YGMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGMacros.h; sourceTree = ""; }; + C07B09E72045303000E03251 /* YGEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGEnums.h; sourceTree = ""; }; + C07B09E82045303000E03251 /* Utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utils.cpp; sourceTree = ""; }; + C07B09E92045303000E03251 /* YGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNode.h; sourceTree = ""; }; + C07B09EB2045303000E03251 /* YGLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGLayout.cpp; sourceTree = ""; }; + C07B09EC2045303000E03251 /* YGNodePrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGNodePrint.cpp; sourceTree = ""; }; + C07B09ED2045303000E03251 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; }; + C07B09EF2045303000E03251 /* Yoga.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Yoga.h; sourceTree = ""; }; + C07B09F02045303000E03251 /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YGEnums.cpp; sourceTree = ""; }; + C07B09F12045303000E03251 /* YGStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGStyle.h; sourceTree = ""; }; + C07B09F22045303000E03251 /* YGNodePrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGNodePrint.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -170,8 +146,8 @@ children = ( 24AE97341FEAF30A00995987 /* SupportingFiles */, B9EAD87E238884C90058E0CB /* Swift */, - 715C61302ABEDE1900D5A2E0 /* yoga */, - 715C61792ABEE4B600D5A2E0 /* YogaKit */, + DFAD4C3820409165008F79CD /* yoga */, + 24AE97371FEAF30A00995987 /* YogaKit */, ); path = Sources; sourceTree = ""; @@ -195,6 +171,16 @@ path = SupportingFiles; sourceTree = ""; }; + 24AE97371FEAF30A00995987 /* YogaKit */ = { + isa = PBXGroup; + children = ( + B9EAD87C2388849D0058E0CB /* include */, + 24AE97391FEAF30A00995987 /* UIView+Yoga.mm */, + 24AE973C1FEAF30A00995987 /* YGLayout.mm */, + ); + path = YogaKit; + sourceTree = ""; + }; 24DA37501EF843C500D1AB2F = { isa = PBXGroup; children = ( @@ -229,103 +215,52 @@ path = FlexLayoutTests; sourceTree = ""; }; - 715C61302ABEDE1900D5A2E0 /* yoga */ = { + B5403C6F81C3814B69C05D0B /* Frameworks */ = { isa = PBXGroup; children = ( - 715C61492ABEDE1900D5A2E0 /* BitUtils.h */, - 715C61382ABEDE1900D5A2E0 /* CMakeLists.txt */, - 715C61332ABEDE1900D5A2E0 /* CompactValue.h */, - 715C614D2ABEDE1900D5A2E0 /* event */, - 715C613E2ABEDE1900D5A2E0 /* include */, - 715C61362ABEDE1900D5A2E0 /* log.cpp */, - 715C61472ABEDE1900D5A2E0 /* log.h */, - 715C61372ABEDE1900D5A2E0 /* Utils.cpp */, - 715C61322ABEDE1900D5A2E0 /* Utils.h */, - 715C614B2ABEDE1900D5A2E0 /* YGConfig.cpp */, - 715C614A2ABEDE1900D5A2E0 /* YGConfig.h */, - 715C61462ABEDE1900D5A2E0 /* YGEnums.cpp */, - 715C61312ABEDE1900D5A2E0 /* YGFloatOptional.h */, - 715C613A2ABEDE1900D5A2E0 /* YGLayout.cpp */, - 715C61352ABEDE1900D5A2E0 /* YGLayout.h */, - 715C614C2ABEDE1900D5A2E0 /* YGNode.cpp */, - 715C613B2ABEDE1900D5A2E0 /* YGNode.h */, - 715C61442ABEDE1900D5A2E0 /* YGNodePrint.cpp */, - 715C61392ABEDE1900D5A2E0 /* YGNodePrint.h */, - 715C613D2ABEDE1900D5A2E0 /* YGStyle.cpp */, - 715C61452ABEDE1900D5A2E0 /* YGStyle.h */, - 715C61482ABEDE1900D5A2E0 /* YGValue.cpp */, - 715C61342ABEDE1900D5A2E0 /* Yoga-internal.h */, - 715C613C2ABEDE1900D5A2E0 /* Yoga.cpp */, + 2491CC5E1FCB932B00F3A61C /* Quick.framework */, + 2491CC5C1FCB931F00F3A61C /* Nimble.framework */, + 1F69C581A2C68BBBD1B64F21 /* Pods_FlexLayoutTests.framework */, ); - path = yoga; + name = Frameworks; sourceTree = ""; }; - 715C613E2ABEDE1900D5A2E0 /* include */ = { + B9EAD87A238884680058E0CB /* include */ = { isa = PBXGroup; children = ( - 715C613F2ABEDE1900D5A2E0 /* yoga */, + B9EAD87B2388846F0058E0CB /* yoga */, ); path = include; sourceTree = ""; }; - 715C613F2ABEDE1900D5A2E0 /* yoga */ = { + B9EAD87B2388846F0058E0CB /* yoga */ = { isa = PBXGroup; children = ( - 715C61402ABEDE1900D5A2E0 /* YGEnums.h */, - 715C61412ABEDE1900D5A2E0 /* YGMacros.h */, - 715C61432ABEDE1900D5A2E0 /* YGValue.h */, - 715C61422ABEDE1900D5A2E0 /* Yoga.h */, + C07B09E72045303000E03251 /* YGEnums.h */, + C07B09E62045303000E03251 /* YGMacros.h */, + C07B09EF2045303000E03251 /* Yoga.h */, ); path = yoga; sourceTree = ""; }; - 715C614D2ABEDE1900D5A2E0 /* event */ = { - isa = PBXGroup; - children = ( - 715C614E2ABEDE1900D5A2E0 /* event.h */, - 715C614F2ABEDE1900D5A2E0 /* event.cpp */, - ); - path = event; - sourceTree = ""; - }; - 715C61792ABEE4B600D5A2E0 /* YogaKit */ = { - isa = PBXGroup; - children = ( - 715C617B2ABEE4B600D5A2E0 /* include */, - 715C617A2ABEE4B600D5A2E0 /* UIView+Yoga.mm */, - 715C61802ABEE4B600D5A2E0 /* YGLayout.mm */, - ); - path = YogaKit; - sourceTree = ""; - }; - 715C617B2ABEE4B600D5A2E0 /* include */ = { + B9EAD87C2388849D0058E0CB /* include */ = { isa = PBXGroup; children = ( - 715C617C2ABEE4B600D5A2E0 /* YogaKit */, + B9EAD87D238884A20058E0CB /* YogaKit */, ); path = include; sourceTree = ""; }; - 715C617C2ABEE4B600D5A2E0 /* YogaKit */ = { + B9EAD87D238884A20058E0CB /* YogaKit */ = { isa = PBXGroup; children = ( - 715C617F2ABEE4B600D5A2E0 /* UIView+Yoga.h */, - 715C617E2ABEE4B600D5A2E0 /* YGLayout.h */, - 715C617D2ABEE4B600D5A2E0 /* YGLayout+Private.h */, + 24AE97381FEAF30A00995987 /* UIView+Yoga.h */, + B9EAD889238947C70058E0CB /* YGLayout.h */, + 24AE973A1FEAF30A00995987 /* YGLayout+Private.h */, ); path = YogaKit; sourceTree = ""; }; - B5403C6F81C3814B69C05D0B /* Frameworks */ = { - isa = PBXGroup; - children = ( - 2491CC5E1FCB932B00F3A61C /* Quick.framework */, - 2491CC5C1FCB931F00F3A61C /* Nimble.framework */, - 1F69C581A2C68BBBD1B64F21 /* Pods_FlexLayoutTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; B9EAD87E238884C90058E0CB /* Swift */ = { isa = PBXGroup; children = ( @@ -337,6 +272,28 @@ path = Swift; sourceTree = ""; }; + DFAD4C3820409165008F79CD /* yoga */ = { + isa = PBXGroup; + children = ( + B9EAD87A238884680058E0CB /* include */, + C07B09E82045303000E03251 /* Utils.cpp */, + C07B09ED2045303000E03251 /* Utils.h */, + C07B09F02045303000E03251 /* YGEnums.cpp */, + B9EAD887238947B00058E0CB /* YGLayout.h */, + C07B09EB2045303000E03251 /* YGLayout.cpp */, + C07B09E92045303000E03251 /* YGNode.h */, + C07B09E32045302F00E03251 /* YGNode.cpp */, + C07B09F22045303000E03251 /* YGNodePrint.h */, + C07B09EC2045303000E03251 /* YGNodePrint.cpp */, + C07B09F12045303000E03251 /* YGStyle.h */, + C07B09E42045303000E03251 /* YGStyle.cpp */, + B9EAD883238896C50058E0CB /* Yoga-internal.h */, + C07B09E52045303000E03251 /* Yoga.cpp */, + ); + name = yoga; + path = Sources/yoga; + sourceTree = SOURCE_ROOT; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -344,26 +301,19 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 715C615F2ABEDE1900D5A2E0 /* Yoga.h in Headers */, - 715C615E2ABEDE1900D5A2E0 /* YGMacros.h in Headers */, - 715C61832ABEE4B600D5A2E0 /* YGLayout.h in Headers */, - 715C61602ABEDE1900D5A2E0 /* YGValue.h in Headers */, - 715C61842ABEE4B600D5A2E0 /* UIView+Yoga.h in Headers */, - 715C615D2ABEDE1900D5A2E0 /* YGEnums.h in Headers */, - 715C61822ABEE4B600D5A2E0 /* YGLayout+Private.h in Headers */, - 715C61622ABEDE1900D5A2E0 /* YGStyle.h in Headers */, - 715C61672ABEDE1900D5A2E0 /* YGConfig.h in Headers */, - 715C61512ABEDE1900D5A2E0 /* Utils.h in Headers */, - 715C61582ABEDE1900D5A2E0 /* YGNodePrint.h in Headers */, - 715C61642ABEDE1900D5A2E0 /* log.h in Headers */, - 715C61662ABEDE1900D5A2E0 /* BitUtils.h in Headers */, - 715C61522ABEDE1900D5A2E0 /* CompactValue.h in Headers */, - 715C61502ABEDE1900D5A2E0 /* YGFloatOptional.h in Headers */, - 715C615A2ABEDE1900D5A2E0 /* YGNode.h in Headers */, - 715C616A2ABEDE1900D5A2E0 /* event.h in Headers */, + C07B09F92045303000E03251 /* YGNode.h in Headers */, 24AE97431FEAF30A00995987 /* FlexLayout.h in Headers */, - 715C61542ABEDE1900D5A2E0 /* YGLayout.h in Headers */, - 715C61532ABEDE1900D5A2E0 /* Yoga-internal.h in Headers */, + B9EAD888238947B00058E0CB /* YGLayout.h in Headers */, + 24AE97471FEAF30A00995987 /* YGLayout+Private.h in Headers */, + C07B09FD2045303000E03251 /* Utils.h in Headers */, + 24AE97451FEAF30A00995987 /* UIView+Yoga.h in Headers */, + C07B09F62045303000E03251 /* YGMacros.h in Headers */, + B9EAD884238896C50058E0CB /* Yoga-internal.h in Headers */, + C07B0A012045303000E03251 /* YGStyle.h in Headers */, + C07B09F72045303000E03251 /* YGEnums.h in Headers */, + B9EAD88A238947C70058E0CB /* YGLayout.h in Headers */, + C07B09FF2045303000E03251 /* Yoga.h in Headers */, + C07B0A022045303000E03251 /* YGNodePrint.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -455,7 +405,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 715C61572ABEDE1900D5A2E0 /* CMakeLists.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -513,24 +462,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 715C61552ABEDE1900D5A2E0 /* log.cpp in Sources */, 24AE974A1FEAF30A00995987 /* YGLayoutExtensions.swift in Sources */, + C07B09F42045303000E03251 /* YGStyle.cpp in Sources */, 24AE97411FEAF30A00995987 /* UIView+FlexLayout.swift in Sources */, - 715C615C2ABEDE1900D5A2E0 /* YGStyle.cpp in Sources */, - 715C61562ABEDE1900D5A2E0 /* Utils.cpp in Sources */, 24AE97421FEAF30A00995987 /* Percent.swift in Sources */, - 715C61852ABEE4B600D5A2E0 /* YGLayout.mm in Sources */, - 715C616B2ABEDE1900D5A2E0 /* event.cpp in Sources */, 24AE97401FEAF30A00995987 /* FlexLayout+Private.swift in Sources */, - 715C61692ABEDE1900D5A2E0 /* YGNode.cpp in Sources */, + C07B09F52045303000E03251 /* Yoga.cpp in Sources */, 24AE973F1FEAF30A00995987 /* FlexLayout+Enum.swift in Sources */, - 715C61812ABEE4B600D5A2E0 /* UIView+Yoga.mm in Sources */, - 715C61652ABEDE1900D5A2E0 /* YGValue.cpp in Sources */, - 715C61682ABEDE1900D5A2E0 /* YGConfig.cpp in Sources */, - 715C61632ABEDE1900D5A2E0 /* YGEnums.cpp in Sources */, - 715C615B2ABEDE1900D5A2E0 /* Yoga.cpp in Sources */, - 715C61612ABEDE1900D5A2E0 /* YGNodePrint.cpp in Sources */, - 715C61592ABEDE1900D5A2E0 /* YGLayout.cpp in Sources */, + C07B09F82045303000E03251 /* Utils.cpp in Sources */, + C07B09FB2045303000E03251 /* YGLayout.cpp in Sources */, + 24AE97491FEAF30A00995987 /* YGLayout.mm in Sources */, + C07B0A002045303000E03251 /* YGEnums.cpp in Sources */, + 24AE97461FEAF30A00995987 /* UIView+Yoga.mm in Sources */, + C07B09FC2045303000E03251 /* YGNodePrint.cpp in Sources */, + C07B09F32045303000E03251 /* YGNode.cpp in Sources */, 24AE973E1FEAF30A00995987 /* FlexLayout.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/FlexLayoutTests/RectNimbleMatcher.swift b/FlexLayoutTests/RectNimbleMatcher.swift index 0dbe09fe..6843cff3 100644 --- a/FlexLayoutTests/RectNimbleMatcher.swift +++ b/FlexLayoutTests/RectNimbleMatcher.swift @@ -20,7 +20,7 @@ import Nimble import UIKit -public func beCloseTo(_ expectedValue: CGRect, within delta: CGFloat = 0.000_01) -> Nimble.Predicate { +public func beCloseTo(_ expectedValue: CGRect, within delta: CGFloat = 0.000_01) -> Predicate { let errorMessage = "be close to <\(stringify(expectedValue))> (each within \(stringify(delta)))" return Predicate.simple(errorMessage) { actualExpression in if let actual = try actualExpression.evaluate() { diff --git a/Podfile.lock b/Podfile.lock index 39341cb7..ea3f4301 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - FlexLayout (1.3.33) + - FlexLayout (1.3.28) - Nimble (9.2.1) - PinLayout (1.10.2) - Quick (4.0.0) @@ -24,7 +24,7 @@ EXTERNAL SOURCES: :path: "./" SPEC CHECKSUMS: - FlexLayout: d515437814cc7a6b50d6d2d14da7cd8059f8d6f6 + FlexLayout: a9cd7285df8b392da70528688b3c456f49c2772c Nimble: e7e615c0335ee4bf5b0d786685451e62746117d5 PinLayout: d6b1960e4b182b4da1481b9aa6728f621e20708d Quick: 6473349e43b9271a8d43839d9ba1c442ed1b7ac4 diff --git a/Sources/SupportingFiles/FlexLayout.h b/Sources/SupportingFiles/FlexLayout.h index 20751c2a..015b82b0 100644 --- a/Sources/SupportingFiles/FlexLayout.h +++ b/Sources/SupportingFiles/FlexLayout.h @@ -27,4 +27,3 @@ FOUNDATION_EXPORT const unsigned char FlexLayoutVersionString[]; #import "Yoga.h" #import "YGEnums.h" #import "YGMacros.h" -#import "YGValue.h" diff --git a/Sources/Swift/YGLayoutExtensions.swift b/Sources/Swift/YGLayoutExtensions.swift index d34fd1cd..d51e3c12 100644 --- a/Sources/Swift/YGLayoutExtensions.swift +++ b/Sources/Swift/YGLayoutExtensions.swift @@ -1,5 +1,5 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -13,36 +13,36 @@ import FlexLayoutYoga postfix operator % extension Int { - public static postfix func %(value: Int) -> YGValue { + public static postfix func % (value: Int) -> YGValue { return YGValue(value: Float(value), unit: .percent) } } extension Float { - public static postfix func %(value: Float) -> YGValue { + public static postfix func % (value: Float) -> YGValue { return YGValue(value: value, unit: .percent) } } extension CGFloat { - public static postfix func %(value: CGFloat) -> YGValue { + public static postfix func % (value: CGFloat) -> YGValue { return YGValue(value: Float(value), unit: .percent) } } -extension YGValue : ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral { +extension YGValue: ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral { public init(integerLiteral value: Int) { self = YGValue(value: Float(value), unit: .point) } - + public init(floatLiteral value: Float) { self = YGValue(value: value, unit: .point) } - + public init(_ value: Float) { self = YGValue(value: value, unit: .point) } - + public init(_ value: CGFloat) { self = YGValue(value: Float(value), unit: .point) } diff --git a/Sources/YogaKit/UIView+Yoga.mm b/Sources/YogaKit/UIView+Yoga.mm index d64b387a..eb360a8c 100644 --- a/Sources/YogaKit/UIView+Yoga.mm +++ b/Sources/YogaKit/UIView+Yoga.mm @@ -1,34 +1,36 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -#import #import "UIView+Yoga.h" #import "YGLayout+Private.h" +#import -static const void* kYGYogaAssociatedKey = &kYGYogaAssociatedKey; +static const void *kYGYogaAssociatedKey = &kYGYogaAssociatedKey; @implementation UIView (YogaKit) -- (YGLayout*)yoga { - YGLayout* yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey); +- (YGLayout *)yoga +{ + YGLayout *yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey); if (!yoga) { yoga = [[YGLayout alloc] initWithView:self]; - objc_setAssociatedObject( - self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return yoga; } -- (BOOL)isYogaEnabled { +- (BOOL)isYogaEnabled +{ return objc_getAssociatedObject(self, kYGYogaAssociatedKey) != nil; } -- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block { +- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block +{ if (block != nil) { block(self.yoga); } diff --git a/Sources/YogaKit/YGLayout.mm b/Sources/YogaKit/YGLayout.mm index 7239bcb5..3c323cf3 100644 --- a/Sources/YogaKit/YGLayout.mm +++ b/Sources/YogaKit/YGLayout.mm @@ -1,207 +1,173 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -#import "UIView+Yoga.h" #import "YGLayout+Private.h" +#import "UIView+Yoga.h" -#define YG_PROPERTY(type, lowercased_name, capitalized_name) \ - -(type)lowercased_name { \ - return YGNodeStyleGet##capitalized_name(self.node); \ - } \ - \ - -(void)set##capitalized_name : (type)lowercased_name { \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \ - } +#define YG_PROPERTY(type, lowercased_name, capitalized_name) \ +- (type)lowercased_name \ +{ \ + return YGNodeStyleGet##capitalized_name(self.node); \ +} \ + \ +- (void)set##capitalized_name:(type)lowercased_name \ +{ \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \ +} -#define YG_VALUE_PROPERTY(lowercased_name, capitalized_name) \ - -(YGValue)lowercased_name { \ - return YGNodeStyleGet##capitalized_name(self.node); \ - } \ - \ - -(void)set##capitalized_name : (YGValue)lowercased_name { \ - switch (lowercased_name.unit) { \ - case YGUnitUndefined: \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ - break; \ - case YGUnitPoint: \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ - break; \ - case YGUnitPercent: \ - YGNodeStyleSet##capitalized_name##Percent( \ - self.node, lowercased_name.value); \ - break; \ - default: \ - NSAssert(NO, @"Not implemented"); \ - } \ - } +#define YG_VALUE_PROPERTY(lowercased_name, capitalized_name) \ +- (YGValue)lowercased_name \ +{ \ + return YGNodeStyleGet##capitalized_name(self.node); \ +} \ + \ +- (void)set##capitalized_name:(YGValue)lowercased_name \ +{ \ + switch (lowercased_name.unit) { \ + case YGUnitUndefined: \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ + break; \ + case YGUnitPoint: \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ + break; \ + case YGUnitPercent: \ + YGNodeStyleSet##capitalized_name##Percent(self.node, lowercased_name.value); \ + break; \ + default: \ + NSAssert(NO, @"Not implemented"); \ + } \ +} -#define YG_AUTO_VALUE_PROPERTY(lowercased_name, capitalized_name) \ - -(YGValue)lowercased_name { \ - return YGNodeStyleGet##capitalized_name(self.node); \ - } \ - \ - -(void)set##capitalized_name : (YGValue)lowercased_name { \ - switch (lowercased_name.unit) { \ - case YGUnitPoint: \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ - break; \ - case YGUnitPercent: \ - YGNodeStyleSet##capitalized_name##Percent( \ - self.node, lowercased_name.value); \ - break; \ - case YGUnitAuto: \ - YGNodeStyleSet##capitalized_name##Auto(self.node); \ - break; \ - default: \ - NSAssert(NO, @"Not implemented"); \ - } \ - } +#define YG_AUTO_VALUE_PROPERTY(lowercased_name, capitalized_name) \ +- (YGValue)lowercased_name \ +{ \ + return YGNodeStyleGet##capitalized_name(self.node); \ +} \ + \ +- (void)set##capitalized_name:(YGValue)lowercased_name \ +{ \ + switch (lowercased_name.unit) { \ + case YGUnitPoint: \ + YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \ + break; \ + case YGUnitPercent: \ + YGNodeStyleSet##capitalized_name##Percent(self.node, lowercased_name.value); \ + break; \ + case YGUnitAuto: \ + YGNodeStyleSet##capitalized_name##Auto(self.node); \ + break; \ + default: \ + NSAssert(NO, @"Not implemented"); \ + } \ +} -#define YG_EDGE_PROPERTY_GETTER( \ - type, lowercased_name, capitalized_name, property, edge) \ - -(type)lowercased_name { \ - return YGNodeStyleGet##property(self.node, edge); \ - } +#define YG_EDGE_PROPERTY_GETTER(type, lowercased_name, capitalized_name, property, edge) \ +- (type)lowercased_name \ +{ \ + return YGNodeStyleGet##property(self.node, edge); \ +} -#define YG_EDGE_PROPERTY_SETTER( \ - lowercased_name, capitalized_name, property, edge) \ - -(void)set##capitalized_name : (CGFloat)lowercased_name { \ - YGNodeStyleSet##property(self.node, edge, lowercased_name); \ - } +#define YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) \ +- (void)set##capitalized_name:(CGFloat)lowercased_name \ +{ \ + YGNodeStyleSet##property(self.node, edge, lowercased_name); \ +} -#define YG_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \ - YG_EDGE_PROPERTY_GETTER( \ - CGFloat, lowercased_name, capitalized_name, property, edge) \ - YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) - -#define YG_VALUE_EDGE_PROPERTY_SETTER( \ - objc_lowercased_name, objc_capitalized_name, c_name, edge) \ - -(void)set##objc_capitalized_name : (YGValue)objc_lowercased_name { \ - switch (objc_lowercased_name.unit) { \ - case YGUnitUndefined: \ - YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ - break; \ - case YGUnitPoint: \ - YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ - break; \ - case YGUnitPercent: \ - YGNodeStyleSet##c_name##Percent( \ - self.node, edge, objc_lowercased_name.value); \ - break; \ - default: \ - NSAssert(NO, @"Not implemented"); \ - } \ - } +#define YG_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \ +YG_EDGE_PROPERTY_GETTER(CGFloat, lowercased_name, capitalized_name, property, edge) \ +YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) + +#define YG_VALUE_EDGE_PROPERTY_SETTER(objc_lowercased_name, objc_capitalized_name, c_name, edge) \ +- (void)set##objc_capitalized_name:(YGValue)objc_lowercased_name \ +{ \ + switch (objc_lowercased_name.unit) { \ + case YGUnitUndefined: \ + YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ + break; \ + case YGUnitPoint: \ + YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \ + break; \ + case YGUnitPercent: \ + YGNodeStyleSet##c_name##Percent(self.node, edge, objc_lowercased_name.value); \ + break; \ + default: \ + NSAssert(NO, @"Not implemented"); \ + } \ +} + +#define YG_VALUE_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \ +YG_EDGE_PROPERTY_GETTER(YGValue, lowercased_name, capitalized_name, property, edge) \ +YG_VALUE_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) + +#define YG_VALUE_EDGES_PROPERTIES(lowercased_name, capitalized_name) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Left, capitalized_name##Left, capitalized_name, YGEdgeLeft) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Top, capitalized_name##Top, capitalized_name, YGEdgeTop) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Right, capitalized_name##Right, capitalized_name, YGEdgeRight) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Bottom, capitalized_name##Bottom, capitalized_name, YGEdgeBottom) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Start, capitalized_name##Start, capitalized_name, YGEdgeStart) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##End, capitalized_name##End, capitalized_name, YGEdgeEnd) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Horizontal, capitalized_name##Horizontal, capitalized_name, YGEdgeHorizontal) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name##Vertical, capitalized_name##Vertical, capitalized_name, YGEdgeVertical) \ +YG_VALUE_EDGE_PROPERTY(lowercased_name, capitalized_name, capitalized_name, YGEdgeAll) + +YGValue YGPointValue(CGFloat value) +{ + return (YGValue) { .value = (float) value, .unit = (YGUnit) YGUnitPoint }; +} -#define YG_VALUE_EDGE_PROPERTY( \ - lowercased_name, capitalized_name, property, edge) \ - YG_EDGE_PROPERTY_GETTER( \ - YGValue, lowercased_name, capitalized_name, property, edge) \ - YG_VALUE_EDGE_PROPERTY_SETTER( \ - lowercased_name, capitalized_name, property, edge) - -#define YG_VALUE_EDGES_PROPERTIES(lowercased_name, capitalized_name) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Left, \ - capitalized_name##Left, \ - capitalized_name, \ - YGEdgeLeft) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Top, \ - capitalized_name##Top, \ - capitalized_name, \ - YGEdgeTop) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Right, \ - capitalized_name##Right, \ - capitalized_name, \ - YGEdgeRight) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Bottom, \ - capitalized_name##Bottom, \ - capitalized_name, \ - YGEdgeBottom) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Start, \ - capitalized_name##Start, \ - capitalized_name, \ - YGEdgeStart) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##End, \ - capitalized_name##End, \ - capitalized_name, \ - YGEdgeEnd) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Horizontal, \ - capitalized_name##Horizontal, \ - capitalized_name, \ - YGEdgeHorizontal) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name##Vertical, \ - capitalized_name##Vertical, \ - capitalized_name, \ - YGEdgeVertical) \ - YG_VALUE_EDGE_PROPERTY( \ - lowercased_name, capitalized_name, capitalized_name, YGEdgeAll) - -YGValue YGPointValue(CGFloat value) { - return (YGValue){.value = (float) value, .unit = YGUnitPoint}; -} - -YGValue YGPercentValue(CGFloat value) { - return (YGValue){.value = (float) value, .unit = YGUnitPercent}; +YGValue YGPercentValue(CGFloat value) +{ + return (YGValue) { .value = (float) value, .unit = YGUnitPercent }; } static YGConfigRef globalConfig; @interface YGLayout () -@property(nonatomic, weak, readonly) UIView* view; -@property(nonatomic, assign, readonly) BOOL isUIView; +@property (nonatomic, weak, readonly) UIView *view; @end @implementation YGLayout -@synthesize isEnabled = _isEnabled; -@synthesize isIncludedInLayout = _isIncludedInLayout; -@synthesize node = _node; +@synthesize isEnabled=_isEnabled; +@synthesize isIncludedInLayout=_isIncludedInLayout; +@synthesize node=_node; -+ (void)initialize { ++ (void)initialize +{ globalConfig = YGConfigNew(); - YGConfigSetExperimentalFeatureEnabled( - globalConfig, YGExperimentalFeatureWebFlexBasis, true); - YGConfigSetErrata(globalConfig, YGErrataClassic); + YGConfigSetExperimentalFeatureEnabled(globalConfig, YGExperimentalFeatureWebFlexBasis, true); YGConfigSetPointScaleFactor(globalConfig, [UIScreen mainScreen].scale); } -- (instancetype)initWithView:(UIView*)view { +- (instancetype)initWithView:(UIView*)view +{ if (self = [super init]) { _view = view; _node = YGNodeNewWithConfig(globalConfig); - YGNodeSetContext(_node, (__bridge void*)view); + YGNodeSetContext(_node, (__bridge void *) view); _isEnabled = NO; _isIncludedInLayout = YES; - _isUIView = [view isMemberOfClass:[UIView class]]; if ([view isKindOfClass:[UILabel class]]) { - if (!YGNodeHasBaselineFunc(_node)) { + if (YGNodeGetBaselineFunc(_node) == NULL) { YGNodeSetBaselineFunc(_node, YGMeasureBaselineLabel); } } if ([view isKindOfClass:[UITextView class]]) { - if (!YGNodeHasBaselineFunc(_node)) { + if (YGNodeGetBaselineFunc(_node) == NULL) { YGNodeSetBaselineFunc(_node, YGMeasureBaselineTextView); } } if ([view isKindOfClass:[UITextField class]]) { - if (!YGNodeHasBaselineFunc(_node)) { + if (YGNodeGetBaselineFunc(_node) == NULL) { YGNodeSetBaselineFunc(_node, YGMeasureBaselineTextField); } } @@ -210,15 +176,18 @@ - (instancetype)initWithView:(UIView*)view { return self; } -- (void)dealloc { +- (void)dealloc +{ YGNodeFree(self.node); } -- (BOOL)isDirty { +- (BOOL)isDirty +{ return YGNodeIsDirty(self.node); } -- (void)markDirty { +- (void)markDirty +{ if (self.isDirty || !self.isLeaf) { return; } @@ -227,24 +196,24 @@ - (void)markDirty { // the measure function. Since we already know that this is a leaf, // this *should* be fine. Forgive me Hack Gods. const YGNodeRef node = self.node; - if (!YGNodeHasMeasureFunc(node)) { + if (YGNodeGetMeasureFunc(node) == NULL) { YGNodeSetMeasureFunc(node, YGMeasureView); } YGNodeMarkDirty(node); } -- (NSUInteger)numberOfChildren { +- (NSUInteger)numberOfChildren +{ return YGNodeGetChildCount(self.node); } -- (BOOL)isLeaf { - NSAssert( - [NSThread isMainThread], - @"This method must be called on the main thread."); +- (BOOL)isLeaf +{ + NSAssert([NSThread isMainThread], @"This method must be called on the main thread."); if (self.isEnabled) { - for (UIView* subview in self.view.subviews) { - YGLayout* const yoga = subview.yoga; + for (UIView *subview in self.view.subviews) { + YGLayout *const yoga = subview.yoga; if (yoga.isEnabled && yoga.isIncludedInLayout) { return NO; } @@ -256,11 +225,13 @@ - (BOOL)isLeaf { #pragma mark - Style -- (YGPositionType)position { +- (YGPositionType)position +{ return YGNodeStyleGetPositionType(self.node); } -- (void)setPosition:(YGPositionType)position { +- (void)setPosition:(YGPositionType)position +{ YGNodeStyleSetPositionType(self.node, position); } @@ -274,7 +245,6 @@ - (void)setPosition:(YGPositionType)position { YG_PROPERTY(YGOverflow, overflow, Overflow) YG_PROPERTY(YGDisplay, display, Display) -YG_PROPERTY(CGFloat, flex, Flex) YG_PROPERTY(CGFloat, flexGrow, FlexGrow) YG_PROPERTY(CGFloat, flexShrink, FlexShrink) YG_AUTO_VALUE_PROPERTY(flexBasis, FlexBasis) @@ -304,29 +274,27 @@ - (void)setPosition:(YGPositionType)position { YG_VALUE_PROPERTY(maxHeight, MaxHeight) YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) -YG_EDGE_PROPERTY(columnGap, ColumnGap, Gap, YGGutterColumn) -YG_EDGE_PROPERTY(rowGap, RowGap, Gap, YGGutterRow) -YG_EDGE_PROPERTY(gap, Gap, Gap, YGGutterAll) - #pragma mark - Layout and Sizing -- (YGDirection)resolvedDirection { +- (YGDirection)resolvedDirection +{ return YGNodeLayoutGetDirection(self.node); } -- (void)applyLayout { +- (void)applyLayout +{ [self calculateLayoutWithSize:self.view.bounds.size]; YGApplyLayoutToViewHierarchy(self.view, NO); } -- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin { +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin +{ [self calculateLayoutWithSize:self.view.bounds.size]; YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); } -- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin - dimensionFlexibility: - (YGDimensionFlexibility)dimensionFlexibility { +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility +{ CGSize size = self.view.bounds.size; if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) { size.width = YGUndefined; @@ -338,15 +306,22 @@ - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); } -- (CGSize)intrinsicSize { - const CGSize constrainedSize = { - .width = YGUndefined, - .height = YGUndefined, + +- (CGSize)intrinsicSize +{ + CGSize constrainedSize = { + .width = YGUndefined, + .height = YGUndefined, + }; + constrainedSize = [self calculateLayoutWithSize:constrainedSize]; + return (CGSize){ + .width = YGRoundPixelValue(constrainedSize.width), + .height = YGRoundPixelValue(constrainedSize.height), }; - return [self calculateLayoutWithSize:constrainedSize]; } -- (CGSize)calculateLayoutWithSize:(CGSize)size { +- (CGSize)calculateLayoutWithSize:(CGSize)size +{ NSAssert([NSThread isMainThread], @"Yoga calculation must be done on main."); NSAssert(self.isEnabled, @"Yoga is not enabled for this view."); @@ -354,91 +329,82 @@ - (CGSize)calculateLayoutWithSize:(CGSize)size { const YGNodeRef node = self.node; YGNodeCalculateLayout( - node, size.width, size.height, YGNodeStyleGetDirection(node)); - - return (CGSize){ - .width = YGRoundPixelValue(YGNodeLayoutGetWidth(node)), - .height = YGRoundPixelValue(YGNodeLayoutGetHeight(node)), + node, + size.width, + size.height, + YGNodeStyleGetDirection(node)); + + return (CGSize) { + .width = YGNodeLayoutGetWidth(node), + .height = YGNodeLayoutGetHeight(node), }; } #pragma mark - Private static float YGMeasureBaselineLabel( - YGNodeRef node, - const float width, - const float height) { + YGNodeRef node, + const float width, + const float height) { - UILabel* view = (__bridge UILabel*) YGNodeGetContext(node); - return view.font.ascender; // height + view.font.ascender for lastBaseline + UILabel* view = (__bridge UILabel*) YGNodeGetContext(node); + return view.font.ascender; // height + view.font.ascender for lastBaseline } static float YGMeasureBaselineTextView( - YGNodeRef node, - const float width, - const float height) { + YGNodeRef node, + const float width, + const float height) { - UITextView* view = (__bridge UITextView*) YGNodeGetContext(node); - return view.font.ascender + view.contentInset.top + view.textContainerInset.top; + UITextView* view = (__bridge UITextView*) YGNodeGetContext(node); + return view.font.ascender + view.contentInset.top + view.textContainerInset.top; } static float YGMeasureBaselineTextField( - YGNodeRef node, - const float width, - const float height) { - - UITextField* view = (__bridge UITextField*) YGNodeGetContext(node); - - switch (view.borderStyle) { - case UITextBorderStyleNone: - return view.font.ascender; - case UITextBorderStyleLine: - return view.font.ascender + 4; - case UITextBorderStyleBezel: - case UITextBorderStyleRoundedRect: - return view.font.ascender + 7; - } + YGNodeRef node, + const float width, + const float height) { + + UITextField* view = (__bridge UITextField*) YGNodeGetContext(node); + + switch (view.borderStyle) { + case UITextBorderStyleNone: + return view.font.ascender; + case UITextBorderStyleLine: + return view.font.ascender + 4; + case UITextBorderStyleBezel: + case UITextBorderStyleRoundedRect: + return view.font.ascender + 7; + } } static YGSize YGMeasureView( - YGNodeRef node, - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode) { - const CGFloat constrainedWidth = - (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width; - const CGFloat constrainedHeight = - (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : height; - - UIView* view = (__bridge UIView*)YGNodeGetContext(node); - CGSize sizeThatFits = CGSizeZero; - - // The default implementation of sizeThatFits: returns the existing size of - // the view. That means that if we want to layout an empty UIView, which - // already has got a frame set, its measured size should be CGSizeZero, but - // UIKit returns the existing size. - // - // See https://github.com/facebook/yoga/issues/606 for more information. - if (!view.yoga.isUIView || [view.subviews count] > 0) { - sizeThatFits = [view sizeThatFits:(CGSize){ - .width = constrainedWidth, - .height = constrainedHeight, - }]; - } - - return (YGSize){ - .width = (float) YGSanitizeMeasurement( - constrainedWidth, sizeThatFits.width, widthMode), - .height = (float) YGSanitizeMeasurement( - constrainedHeight, sizeThatFits.height, heightMode), + YGNodeRef node, + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode) +{ + const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width; + const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height; + + UIView *view = (__bridge UIView*) YGNodeGetContext(node); + const CGSize sizeThatFits = [view sizeThatFits:(CGSize) { + .width = constrainedWidth, + .height = constrainedHeight, + }]; + + return (YGSize) { + .width = (float) YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), + .height = (float) YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode), }; } static CGFloat YGSanitizeMeasurement( - CGFloat constrainedSize, - CGFloat measuredSize, - YGMeasureMode measureMode) { + CGFloat constrainedSize, + CGFloat measuredSize, + YGMeasureMode measureMode) +{ CGFloat result; if (measureMode == YGMeasureModeExactly) { result = constrainedSize; @@ -451,14 +417,13 @@ static CGFloat YGSanitizeMeasurement( return result; } -static BOOL YGNodeHasExactSameChildren( - const YGNodeRef node, - NSArray* subviews) { +static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray *subviews) +{ if (YGNodeGetChildCount(node) != subviews.count) { return NO; } - for (int i = 0; i < subviews.count; i++) { + for (int i=0; i* subviewsToInclude = - [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; - for (UIView* subview in view.subviews) { - if (subview.yoga.isEnabled && subview.yoga.isIncludedInLayout) { + NSMutableArray *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; + for (UIView *subview in view.subviews) { + if (subview.yoga.isIncludedInLayout) { [subviewsToInclude addObject:subview]; } } if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) { YGRemoveAllChildren(node); - for (int i = 0; i < subviewsToInclude.count; i++) { - YGNodeInsertChild(node, subviewsToInclude[i].yoga.node, i); + for (int i=0; i 0) { + YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1)); + } } -static CGFloat YGRoundPixelValue(CGFloat value) { +static CGFloat YGRoundPixelValue(CGFloat value) +{ static CGFloat scale; static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^() { + dispatch_once(&onceToken, ^(){ scale = [UIScreen mainScreen].scale; }); return roundf(value * scale) / scale; } -static void YGApplyLayoutToViewHierarchy(UIView* view, BOOL preserveOrigin) { - NSCAssert( - [NSThread isMainThread], - @"Framesetting should only be done on the main thread."); +static void YGApplyLayoutToViewHierarchy(UIView *view, BOOL preserveOrigin) +{ + NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread."); - const YGLayout* yoga = view.yoga; + const YGLayout *yoga = view.yoga; if (!yoga.isIncludedInLayout) { - return; + return; } YGNodeRef node = yoga.node; const CGPoint topLeft = { - YGNodeLayoutGetLeft(node), - YGNodeLayoutGetTop(node), + YGNodeLayoutGetLeft(node), + YGNodeLayoutGetTop(node), }; - CGPoint bottomRight = { - topLeft.x + YGNodeLayoutGetWidth(node), - topLeft.y + YGNodeLayoutGetHeight(node), + topLeft.x + YGNodeLayoutGetWidth(node), + topLeft.y + YGNodeLayoutGetHeight(node), }; - + if (isnan(bottomRight.x)) { bottomRight.x = 0; } @@ -547,21 +519,19 @@ static void YGApplyLayoutToViewHierarchy(UIView* view, BOOL preserveOrigin) { } const CGPoint origin = preserveOrigin ? view.frame.origin : CGPointZero; - view.frame = (CGRect){ - .origin = - { - .x = YGRoundPixelValue(topLeft.x + origin.x), - .y = YGRoundPixelValue(topLeft.y + origin.y), - }, - .size = - { - .width = MAX(0, YGRoundPixelValue(bottomRight.x - topLeft.x)), - .height = MAX(0, YGRoundPixelValue(bottomRight.y - topLeft.y)), - }, + view.frame = (CGRect) { + .origin = { + .x = YGRoundPixelValue(topLeft.x + origin.x), + .y = YGRoundPixelValue(topLeft.y + origin.y), + }, + .size = { + .width = MAX(0, YGRoundPixelValue(bottomRight.x - topLeft.x)), + .height = MAX(0, YGRoundPixelValue(bottomRight.y - topLeft.y)), + }, }; if (!yoga.isLeaf) { - for (NSUInteger i = 0; i < view.subviews.count; i++) { + for (NSUInteger i=0; i #import "YGLayout.h" +#import NS_ASSUME_NONNULL_BEGIN -typedef void (^YGLayoutConfigurationBlock)(YGLayout* layout); +typedef void (^YGLayoutConfigurationBlock)(YGLayout *layout); @interface UIView (Yoga) /** The YGLayout that is attached to this view. It is lazily created. */ -@property(nonatomic, readonly, strong) YGLayout* yoga; +@property (nonatomic, readonly, strong) YGLayout *yoga; /** Indicates whether or not Yoga is enabled */ -@property(nonatomic, readonly, assign) BOOL isYogaEnabled; +@property (nonatomic, readonly, assign) BOOL isYogaEnabled; /** - In ObjC land, every time you access `view.yoga.*` you are adding another - `objc_msgSend` to your code. If you plan on making multiple changes to - YGLayout, it's more performant to use this method, which uses a single - objc_msgSend call. + In ObjC land, every time you access `view.yoga.*` you are adding another `objc_msgSend` + to your code. If you plan on making multiple changes to YGLayout, it's more performant + to use this method, which uses a single objc_msgSend call. */ - (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block NS_SWIFT_NAME(configureLayout(block:)); diff --git a/Sources/YogaKit/include/YogaKit/YGLayout+Private.h b/Sources/YogaKit/include/YogaKit/YGLayout+Private.h index d0d99faf..07aad0c8 100644 --- a/Sources/YogaKit/include/YogaKit/YGLayout+Private.h +++ b/Sources/YogaKit/include/YogaKit/YGLayout+Private.h @@ -1,21 +1,21 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +#import "YGLayout.h" #if FLEXLAYOUT_SWIFT_PACKAGE #import #else #import "Yoga.h" #endif -#import "YGLayout.h" @interface YGLayout () -@property(nonatomic, assign, readonly) YGNodeRef node; +@property (nonatomic, assign, readonly) YGNodeRef node; -- (instancetype)initWithView:(UIView*)view; +- (instancetype)initWithView:(UIView *)view; @end diff --git a/Sources/YogaKit/include/YogaKit/YGLayout.h b/Sources/YogaKit/include/YogaKit/YGLayout.h index de622d3f..8faa3e82 100644 --- a/Sources/YogaKit/include/YogaKit/YGLayout.h +++ b/Sources/YogaKit/include/YogaKit/YGLayout.h @@ -1,5 +1,5 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -9,20 +9,20 @@ #if FLEXLAYOUT_SWIFT_PACKAGE #import -#import #import +#import #else #import "YGEnums.h" -#import "YGMacros.h" #import "Yoga.h" +#import "YGMacros.h" #endif YG_EXTERN_C_BEGIN -extern YGValue YGPointValue(CGFloat value) NS_SWIFT_UNAVAILABLE( - "Use the swift Int and FloatingPoint extensions instead"); -extern YGValue YGPercentValue(CGFloat value) NS_SWIFT_UNAVAILABLE( - "Use the swift Int and FloatingPoint extensions instead"); +extern YGValue YGPointValue(CGFloat value) + NS_SWIFT_UNAVAILABLE("Use the swift Int and FloatingPoint extensions instead"); +extern YGValue YGPercentValue(CGFloat value) + NS_SWIFT_UNAVAILABLE("Use the swift Int and FloatingPoint extensions instead"); YG_EXTERN_C_END @@ -40,118 +40,106 @@ typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { - (instancetype)init __attribute__((unavailable("you are not meant to initialise YGLayout"))); -/** - Make default init unavailable, as it will not initialise YGNode which is - required for the setters and getters of YGLayout's properties to work properly. - */ -+ (instancetype)new - __attribute__((unavailable("you are not meant to initialise YGLayout"))); - /** The property that decides if we should include this view when calculating layout. Defaults to YES. */ -@property(nonatomic, readwrite, assign, setter=setIncludedInLayout:) - BOOL isIncludedInLayout; +@property (nonatomic, readwrite, assign, setter=setIncludedInLayout:) BOOL isIncludedInLayout; /** - The property that decides during layout/sizing whether or not styling - properties should be applied. Defaults to NO. + The property that decides during layout/sizing whether or not styling properties should be applied. + Defaults to NO. */ -@property(nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled; - -@property(nonatomic, readwrite, assign) YGDirection direction; -@property(nonatomic, readwrite, assign) YGFlexDirection flexDirection; -@property(nonatomic, readwrite, assign) YGJustify justifyContent; -@property(nonatomic, readwrite, assign) YGAlign alignContent; -@property(nonatomic, readwrite, assign) YGAlign alignItems; -@property(nonatomic, readwrite, assign) YGAlign alignSelf; -@property(nonatomic, readwrite, assign) YGPositionType position; -@property(nonatomic, readwrite, assign) YGWrap flexWrap; -@property(nonatomic, readwrite, assign) YGOverflow overflow; -@property(nonatomic, readwrite, assign) YGDisplay display; - -@property(nonatomic, readwrite, assign) CGFloat flex; -@property(nonatomic, readwrite, assign) CGFloat flexGrow; -@property(nonatomic, readwrite, assign) CGFloat flexShrink; -@property(nonatomic, readwrite, assign) YGValue flexBasis; - -@property(nonatomic, readwrite, assign) YGValue left; -@property(nonatomic, readwrite, assign) YGValue top; -@property(nonatomic, readwrite, assign) YGValue right; -@property(nonatomic, readwrite, assign) YGValue bottom; -@property(nonatomic, readwrite, assign) YGValue start; -@property(nonatomic, readwrite, assign) YGValue end; - -@property(nonatomic, readwrite, assign) YGValue marginLeft; -@property(nonatomic, readwrite, assign) YGValue marginTop; -@property(nonatomic, readwrite, assign) YGValue marginRight; -@property(nonatomic, readwrite, assign) YGValue marginBottom; -@property(nonatomic, readwrite, assign) YGValue marginStart; -@property(nonatomic, readwrite, assign) YGValue marginEnd; -@property(nonatomic, readwrite, assign) YGValue marginHorizontal; -@property(nonatomic, readwrite, assign) YGValue marginVertical; -@property(nonatomic, readwrite, assign) YGValue margin; - -@property(nonatomic, readwrite, assign) YGValue paddingLeft; -@property(nonatomic, readwrite, assign) YGValue paddingTop; -@property(nonatomic, readwrite, assign) YGValue paddingRight; -@property(nonatomic, readwrite, assign) YGValue paddingBottom; -@property(nonatomic, readwrite, assign) YGValue paddingStart; -@property(nonatomic, readwrite, assign) YGValue paddingEnd; -@property(nonatomic, readwrite, assign) YGValue paddingHorizontal; -@property(nonatomic, readwrite, assign) YGValue paddingVertical; -@property(nonatomic, readwrite, assign) YGValue padding; - -@property(nonatomic, readwrite, assign) CGFloat borderLeftWidth; -@property(nonatomic, readwrite, assign) CGFloat borderTopWidth; -@property(nonatomic, readwrite, assign) CGFloat borderRightWidth; -@property(nonatomic, readwrite, assign) CGFloat borderBottomWidth; -@property(nonatomic, readwrite, assign) CGFloat borderStartWidth; -@property(nonatomic, readwrite, assign) CGFloat borderEndWidth; -@property(nonatomic, readwrite, assign) CGFloat borderWidth; - -@property(nonatomic, readwrite, assign) YGValue width; -@property(nonatomic, readwrite, assign) YGValue height; -@property(nonatomic, readwrite, assign) YGValue minWidth; -@property(nonatomic, readwrite, assign) YGValue minHeight; -@property(nonatomic, readwrite, assign) YGValue maxWidth; -@property(nonatomic, readwrite, assign) YGValue maxHeight; +@property (nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled; + +@property (nonatomic, readwrite, assign) YGDirection direction; +@property (nonatomic, readwrite, assign) YGFlexDirection flexDirection; +@property (nonatomic, readwrite, assign) YGJustify justifyContent; +@property (nonatomic, readwrite, assign) YGAlign alignContent; +@property (nonatomic, readwrite, assign) YGAlign alignItems; +@property (nonatomic, readwrite, assign) YGAlign alignSelf; +@property (nonatomic, readwrite, assign) YGPositionType position; +@property (nonatomic, readwrite, assign) YGWrap flexWrap; +@property (nonatomic, readwrite, assign) YGOverflow overflow; +@property (nonatomic, readwrite, assign) YGDisplay display; + +@property (nonatomic, readwrite, assign) CGFloat flexGrow; +@property (nonatomic, readwrite, assign) CGFloat flexShrink; +@property (nonatomic, readwrite, assign) YGValue flexBasis; + +@property (nonatomic, readwrite, assign) YGValue left; +@property (nonatomic, readwrite, assign) YGValue top; +@property (nonatomic, readwrite, assign) YGValue right; +@property (nonatomic, readwrite, assign) YGValue bottom; +@property (nonatomic, readwrite, assign) YGValue start; +@property (nonatomic, readwrite, assign) YGValue end; + +@property (nonatomic, readwrite, assign) YGValue marginLeft; +@property (nonatomic, readwrite, assign) YGValue marginTop; +@property (nonatomic, readwrite, assign) YGValue marginRight; +@property (nonatomic, readwrite, assign) YGValue marginBottom; +@property (nonatomic, readwrite, assign) YGValue marginStart; +@property (nonatomic, readwrite, assign) YGValue marginEnd; +@property (nonatomic, readwrite, assign) YGValue marginHorizontal; +@property (nonatomic, readwrite, assign) YGValue marginVertical; +@property (nonatomic, readwrite, assign) YGValue margin; + +@property (nonatomic, readwrite, assign) YGValue paddingLeft; +@property (nonatomic, readwrite, assign) YGValue paddingTop; +@property (nonatomic, readwrite, assign) YGValue paddingRight; +@property (nonatomic, readwrite, assign) YGValue paddingBottom; +@property (nonatomic, readwrite, assign) YGValue paddingStart; +@property (nonatomic, readwrite, assign) YGValue paddingEnd; +@property (nonatomic, readwrite, assign) YGValue paddingHorizontal; +@property (nonatomic, readwrite, assign) YGValue paddingVertical; +@property (nonatomic, readwrite, assign) YGValue padding; + +@property (nonatomic, readwrite, assign) CGFloat borderLeftWidth; +@property (nonatomic, readwrite, assign) CGFloat borderTopWidth; +@property (nonatomic, readwrite, assign) CGFloat borderRightWidth; +@property (nonatomic, readwrite, assign) CGFloat borderBottomWidth; +@property (nonatomic, readwrite, assign) CGFloat borderStartWidth; +@property (nonatomic, readwrite, assign) CGFloat borderEndWidth; +@property (nonatomic, readwrite, assign) CGFloat borderWidth; + +@property (nonatomic, readwrite, assign) YGValue width; +@property (nonatomic, readwrite, assign) YGValue height; +@property (nonatomic, readwrite, assign) YGValue minWidth; +@property (nonatomic, readwrite, assign) YGValue minHeight; +@property (nonatomic, readwrite, assign) YGValue maxWidth; +@property (nonatomic, readwrite, assign) YGValue maxHeight; // Yoga specific properties, not compatible with flexbox specification -@property(nonatomic, readwrite, assign) CGFloat aspectRatio; +@property (nonatomic, readwrite, assign) CGFloat aspectRatio; /** Get the resolved direction of this node. This won't be YGDirectionInherit */ -@property(nonatomic, readonly, assign) YGDirection resolvedDirection; +@property (nonatomic, readonly, assign) YGDirection resolvedDirection; /** - Perform a layout calculation and update the frames of the views in the - hierarchy with the results. If the origin is not preserved, the root view's - layout results will applied from {0,0}. + Perform a layout calculation and update the frames of the views in the hierarchy with the results. + If the origin is not preserved, the root view's layout results will applied from {0,0}. */ - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin NS_SWIFT_NAME(applyLayout(preservingOrigin:)); /** - Perform a layout calculation and update the frames of the views in the - hierarchy with the results. If the origin is not preserved, the root view's - layout results will applied from {0,0}. + Perform a layout calculation and update the frames of the views in the hierarchy with the results. + If the origin is not preserved, the root view's layout results will applied from {0,0}. */ - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility NS_SWIFT_NAME(applyLayout(preservingOrigin:dimensionFlexibility:)); /** - Returns the size of the view if no constraints were given. This could - equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; + Returns the size of the view if no constraints were given. This could equivalent to calling [self + sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; */ -@property(nonatomic, readonly, assign) CGSize intrinsicSize; +@property (nonatomic, readonly, assign) CGSize intrinsicSize; /** - Returns the size of the view based on provided constraints. Pass NaN for an - unconstrained dimension. + Returns the size of the view based on provided constraints. Pass NaN for an unconstrained dimension. */ - (CGSize)calculateLayoutWithSize:(CGSize)size NS_SWIFT_NAME(calculateLayout(with:)); @@ -159,19 +147,19 @@ typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { /** Returns the number of children that are using Flexbox. */ -@property(nonatomic, readonly, assign) NSUInteger numberOfChildren; +@property (nonatomic, readonly, assign) NSUInteger numberOfChildren; /** - Return a BOOL indiciating whether or not we this node contains any subviews - that are included in Yoga's layout. + Return a BOOL indiciating whether or not we this node contains any subviews that are included in + Yoga's layout. */ -@property(nonatomic, readonly, assign) BOOL isLeaf; +@property (nonatomic, readonly, assign) BOOL isLeaf; /** Return's a BOOL indicating if a view is dirty. When a node is dirty it usually indicates that it will be remeasured on the next layout pass. */ -@property(nonatomic, readonly, assign) BOOL isDirty; +@property (nonatomic, readonly, assign) BOOL isDirty; /** Mark that a view's layout needs to be recalculated. Only works for leaf views. diff --git a/Sources/yoga/BitUtils.h b/Sources/yoga/BitUtils.h deleted file mode 100644 index be2a84e9..00000000 --- a/Sources/yoga/BitUtils.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -#include "YGEnums.h" - -namespace facebook { -namespace yoga { - -namespace detail { - -// std::bitset with one bit for each option defined in YG_ENUM_SEQ_DECL -template -using EnumBitset = std::bitset()>; - -constexpr size_t log2ceilFn(size_t n) { - return n < 1 ? 0 : (1 + log2ceilFn(n / 2)); -} - -constexpr int mask(size_t bitWidth, size_t index) { - return ((1 << bitWidth) - 1) << index; -} - -// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL -template -constexpr size_t bitWidthFn() { - static_assert( - enums::count() > 0, "Enums must have at least one entries"); - return log2ceilFn(enums::count() - 1); -} - -template -constexpr Enum getEnumData(int flags, size_t index) { - return static_cast((flags & mask(bitWidthFn(), index)) >> index); -} - -template -void setEnumData(uint32_t& flags, size_t index, int newValue) { - flags = (flags & ~mask(bitWidthFn(), index)) | - ((newValue << index) & (mask(bitWidthFn(), index))); -} - -template -void setEnumData(uint8_t& flags, size_t index, int newValue) { - flags = (flags & ~static_cast(mask(bitWidthFn(), index))) | - ((newValue << index) & - (static_cast(mask(bitWidthFn(), index)))); -} - -constexpr bool getBooleanData(int flags, size_t index) { - return (flags >> index) & 1; -} - -inline void setBooleanData(uint8_t& flags, size_t index, bool value) { - if (value) { - flags |= 1 << index; - } else { - flags &= ~(1 << index); - } -} - -} // namespace detail -} // namespace yoga -} // namespace facebook diff --git a/Sources/yoga/CMakeLists.txt b/Sources/yoga/CMakeLists.txt deleted file mode 100644 index b6eca1ac..00000000 --- a/Sources/yoga/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - - -cmake_minimum_required(VERSION 3.13...3.26) -project(yogacore) -set(CMAKE_VERBOSE_MAKEFILE on) - -if(TARGET yogacore) - return() -endif() - -include(CheckIPOSupported) - -set(YOGA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..) -include(${YOGA_ROOT}/cmake/project-defaults.cmake) - - -file(GLOB SOURCES CONFIGURE_DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/**/*.cpp) - -add_library(yogacore STATIC ${SOURCES}) - -# Yoga conditionally uses when building for Android -if (ANDROID) - target_link_libraries(yogacore log) -endif() - -check_ipo_supported(RESULT result) -if(result) - set_target_properties(yogacore PROPERTIES - CMAKE_INTERPROCEDURAL_OPTIMIZATION true) -endif() - -target_include_directories(yogacore - PUBLIC - $ - $) diff --git a/Sources/yoga/CompactValue.h b/Sources/yoga/CompactValue.h deleted file mode 100644 index 1a3b49c9..00000000 --- a/Sources/yoga/CompactValue.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -#include "YGMacros.h" -#include "YGValue.h" - -#if defined(__has_include) && __has_include() -// needed to be able to evaluate defined(__cpp_lib_bit_cast) -#include -#else -// needed to be able to evaluate defined(__cpp_lib_bit_cast) -#include -#endif - -#ifdef __cpp_lib_bit_cast -#include -#else -#include -#endif - -static_assert( - std::numeric_limits::is_iec559, - "facebook::yoga::detail::CompactValue only works with IEEE754 floats"); - -#ifdef YOGA_COMPACT_VALUE_TEST -#define VISIBLE_FOR_TESTING public: -#else -#define VISIBLE_FOR_TESTING private: -#endif - -namespace facebook { -namespace yoga { -namespace detail { - -// This class stores YGValue in 32 bits. -// - The value does not matter for Undefined and Auto. NaNs are used for their -// representation. -// - To differentiate between Point and Percent, one exponent bit is used. -// Supported the range [0x40, 0xbf] (0xbf is inclusive for point, but -// exclusive for percent). -// - Value ranges: -// points: 1.08420217e-19f to 36893485948395847680 -// 0x00000000 0x3fffffff -// percent: 1.08420217e-19f to 18446742974197923840 -// 0x40000000 0x7f7fffff -// - Zero is supported, negative zero is not -// - values outside of the representable range are clamped -class YOGA_EXPORT CompactValue { - friend constexpr bool operator==(CompactValue, CompactValue) noexcept; - -public: - static constexpr auto LOWER_BOUND = 1.08420217e-19f; - static constexpr auto UPPER_BOUND_POINT = 36893485948395847680.0f; - static constexpr auto UPPER_BOUND_PERCENT = 18446742974197923840.0f; - - template - static CompactValue of(float value) noexcept { - if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) { - constexpr auto zero = - Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT; - return {zero}; - } - - constexpr auto upperBound = - Unit == YGUnitPercent ? UPPER_BOUND_PERCENT : UPPER_BOUND_POINT; - if (value > upperBound || value < -upperBound) { - value = copysignf(upperBound, value); - } - - uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0; - auto data = asU32(value); - data -= BIAS; - data |= unitBit; - return {data}; - } - - template - static CompactValue ofMaybe(float value) noexcept { - return std::isnan(value) || std::isinf(value) ? ofUndefined() - : of(value); - } - - static constexpr CompactValue ofZero() noexcept { - return CompactValue{ZERO_BITS_POINT}; - } - - static constexpr CompactValue ofUndefined() noexcept { - return CompactValue{}; - } - - static constexpr CompactValue ofAuto() noexcept { - return CompactValue{AUTO_BITS}; - } - - constexpr CompactValue() noexcept : repr_(0x7FC00000) {} - - CompactValue(const YGValue& x) noexcept : repr_(uint32_t{0}) { - switch (x.unit) { - case YGUnitUndefined: - *this = ofUndefined(); - break; - case YGUnitAuto: - *this = ofAuto(); - break; - case YGUnitPoint: - *this = of(x.value); - break; - case YGUnitPercent: - *this = of(x.value); - break; - } - } - - operator YGValue() const noexcept { - switch (repr_) { - case AUTO_BITS: - return YGValueAuto; - case ZERO_BITS_POINT: - return YGValue{0.0f, YGUnitPoint}; - case ZERO_BITS_PERCENT: - return YGValue{0.0f, YGUnitPercent}; - } - - if (std::isnan(asFloat(repr_))) { - return YGValueUndefined; - } - - auto data = repr_; - data &= ~PERCENT_BIT; - data += BIAS; - - return YGValue{ - asFloat(data), repr_ & 0x40000000 ? YGUnitPercent : YGUnitPoint}; - } - - bool isUndefined() const noexcept { - return ( - repr_ != AUTO_BITS && repr_ != ZERO_BITS_POINT && - repr_ != ZERO_BITS_PERCENT && std::isnan(asFloat(repr_))); - } - - bool isAuto() const noexcept { return repr_ == AUTO_BITS; } - -private: - uint32_t repr_; - - static constexpr uint32_t BIAS = 0x20000000; - static constexpr uint32_t PERCENT_BIT = 0x40000000; - - // these are signaling NaNs with specific bit pattern as payload they will be - // silenced whenever going through an FPU operation on ARM + x86 - static constexpr uint32_t AUTO_BITS = 0x7faaaaaa; - static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f; - static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0; - - constexpr CompactValue(uint32_t data) noexcept : repr_(data) {} - - VISIBLE_FOR_TESTING uint32_t repr() { return repr_; } - - static uint32_t asU32(float f) { -#ifdef __cpp_lib_bit_cast - return std::bit_cast(f); -#else - uint32_t u; - static_assert( - sizeof(u) == sizeof(f), "uint32_t and float must have the same size"); - std::memcpy(&u, &f, sizeof(f)); - return u; -#endif - } - - static float asFloat(uint32_t u) { -#ifdef __cpp_lib_bit_cast - return std::bit_cast(u); -#else - float f; - static_assert( - sizeof(f) == sizeof(u), "uint32_t and float must have the same size"); - std::memcpy(&f, &u, sizeof(u)); - return f; -#endif - } -}; - -template <> -CompactValue CompactValue::of(float) noexcept = delete; -template <> -CompactValue CompactValue::of(float) noexcept = delete; -template <> -CompactValue CompactValue::ofMaybe(float) noexcept = delete; -template <> -CompactValue CompactValue::ofMaybe(float) noexcept = delete; - -constexpr bool operator==(CompactValue a, CompactValue b) noexcept { - return a.repr_ == b.repr_; -} - -constexpr bool operator!=(CompactValue a, CompactValue b) noexcept { - return !(a == b); -} - -} // namespace detail -} // namespace yoga -} // namespace facebook diff --git a/Sources/yoga/Utils.cpp b/Sources/yoga/Utils.cpp index 7cc94022..110c7f0d 100644 --- a/Sources/yoga/Utils.cpp +++ b/Sources/yoga/Utils.cpp @@ -1,14 +1,11 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * 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" -#include - -using namespace facebook; YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, @@ -18,66 +15,15 @@ YGFlexDirection YGFlexDirectionCross( : 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) { +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))) { + (std::isnan(a.value) && std::isnan(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); -} - -bool YGDoubleEqual(const double a, const double b) { - if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { - return fabs(a - b) < 0.0001; - } - return yoga::isUndefined(a) && yoga::isUndefined(b); -} - -float YGFloatSanitize(const float val) { - return yoga::isUndefined(val) ? 0 : val; -} - -YGFloatOptional YGFloatOptionalMax(YGFloatOptional op1, YGFloatOptional op2) { - if (op1 >= op2) { - return op1; - } - if (op2 > op1) { - return op2; - } - return op1.isUndefined() ? op2 : op1; -} - -void yoga::throwLogicalErrorWithMessage(const char* message) { -#if defined(__cpp_exceptions) - throw std::logic_error(message); -#else // !defined(__cpp_exceptions) - std::terminate(); -#endif // defined(__cpp_exceptions) -} diff --git a/Sources/yoga/Utils.h b/Sources/yoga/Utils.h index 376c4fb5..db52acd6 100644 --- a/Sources/yoga/Utils.h +++ b/Sources/yoga/Utils.h @@ -1,96 +1,58 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * 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" -#include "CompactValue.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. +// 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. +// 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. +// 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 -// laid in the current line +// layed in the current line // // - totalFlexShrinkFactors: total flex shrink factors of flex items which are -// to be laid in the current line +// 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 including it may have caused to overshoot availableInnerDim) +// 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. +// and/or grow. struct YGCollectFlexItemsRowValues { uint32_t itemsOnLine; float sizeConsumedOnCurrentLine; float totalFlexGrowFactors; float totalFlexShrinkScaledFactors; - uint32_t endOfLineIndex; + float endOfLineIndex; std::vector 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. + // through all the rows to decide on the main axis size of parent. 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); -inline bool YGValueEqual( - facebook::yoga::detail::CompactValue a, - facebook::yoga::detail::CompactValue b) { - return YGValueEqual((YGValue) a, (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); - -bool YGDoubleEqual(const double a, const double b); - -float YGFloatMax(const float a, const float b); - -YGFloatOptional YGFloatOptionalMax( - const YGFloatOptional op1, - const YGFloatOptional op2); - -float YGFloatMin(const float a, const float b); - -// This custom float comparison function compares the array of float with -// YGFloatsEqual, as the default float comparison operator will not work(Look -// at the comments of YGFloatsEqual function). -template -bool YGFloatArrayEqual( - const std::array& val1, - const std::array& 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); +bool YGValueEqual(const YGValue a, const YGValue b); YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, @@ -101,23 +63,17 @@ inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) { flexDirection == YGFlexDirectionRowReverse; } -inline YGFloatOptional YGResolveValue( - const YGValue value, - const float ownerSize) { +inline float YGResolveValue(const YGValue value, const float parentSize) { switch (value.unit) { + case YGUnitUndefined: + case YGUnitAuto: + return YGUndefined; case YGUnitPoint: - return YGFloatOptional{value.value}; + return value.value; case YGUnitPercent: - return YGFloatOptional{value.value * ownerSize * 0.01f}; - default: - return YGFloatOptional{}; + return value.value * parentSize / 100.0f; } -} - -inline YGFloatOptional YGResolveValue( - facebook::yoga::detail::CompactValue value, - float ownerSize) { - return YGResolveValue((YGValue) value, ownerSize); + return YGUndefined; } inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) { @@ -139,8 +95,8 @@ inline YGFlexDirection YGResolveFlexDirection( return flexDirection; } -inline YGFloatOptional YGResolveValueMargin( - facebook::yoga::detail::CompactValue value, - const float ownerSize) { - return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize); +static inline float YGResolveValueMargin( + const YGValue value, + const float parentSize) { + return value.unit == YGUnitAuto ? 0 : YGResolveValue(value, parentSize); } diff --git a/Sources/yoga/YGConfig.cpp b/Sources/yoga/YGConfig.cpp deleted file mode 100644 index 5bf85f4a..00000000 --- a/Sources/yoga/YGConfig.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "YGConfig.h" - -using namespace facebook::yoga; - -namespace facebook { -namespace yoga { -bool configUpdateInvalidatesLayout(YGConfigRef a, YGConfigRef b) { - return a->getErrata() != b->getErrata() || - a->getEnabledExperiments() != b->getEnabledExperiments() || - a->getPointScaleFactor() != b->getPointScaleFactor() || - a->useWebDefaults() != b->useWebDefaults(); -} -} // namespace yoga -} // namespace facebook - -YGConfig::YGConfig(YGLogger logger) : cloneNodeCallback_{nullptr} { - setLogger(logger); -} - -void YGConfig::setUseWebDefaults(bool useWebDefaults) { - flags_.useWebDefaults = useWebDefaults; -} - -bool YGConfig::useWebDefaults() const { - return flags_.useWebDefaults; -} - -void YGConfig::setShouldPrintTree(bool printTree) { - flags_.printTree = printTree; -} - -bool YGConfig::shouldPrintTree() const { - return flags_.printTree; -} - -void YGConfig::setExperimentalFeatureEnabled( - YGExperimentalFeature feature, - bool enabled) { - experimentalFeatures_.set(feature, enabled); -} - -bool YGConfig::isExperimentalFeatureEnabled( - YGExperimentalFeature feature) const { - return experimentalFeatures_.test(feature); -} - -ExperimentalFeatureSet YGConfig::getEnabledExperiments() const { - return experimentalFeatures_; -} - -void YGConfig::setErrata(YGErrata errata) { - errata_ = errata; -} - -void YGConfig::addErrata(YGErrata errata) { - errata_ |= errata; -} - -void YGConfig::removeErrata(YGErrata errata) { - errata_ &= (~errata); -} - -YGErrata YGConfig::getErrata() const { - return errata_; -} - -bool YGConfig::hasErrata(YGErrata errata) const { - return (errata_ & errata) != YGErrataNone; -} - -void YGConfig::setPointScaleFactor(float pointScaleFactor) { - pointScaleFactor_ = pointScaleFactor; -} - -float YGConfig::getPointScaleFactor() const { - return pointScaleFactor_; -} - -void YGConfig::setContext(void* context) { - context_ = context; -} - -void* YGConfig::getContext() const { - return context_; -} - -void YGConfig::setLogger(YGLogger logger) { - logger_.noContext = logger; - flags_.loggerUsesContext = false; -} - -void YGConfig::setLogger(LogWithContextFn logger) { - logger_.withContext = logger; - flags_.loggerUsesContext = true; -} - -void YGConfig::setLogger(std::nullptr_t) { - setLogger(YGLogger{nullptr}); -} - -void YGConfig::log( - YGConfig* config, - YGNode* node, - YGLogLevel logLevel, - void* logContext, - const char* format, - va_list args) const { - if (flags_.loggerUsesContext) { - logger_.withContext(config, node, logLevel, logContext, format, args); - } else { - logger_.noContext(config, node, logLevel, format, args); - } -} - -void YGConfig::setCloneNodeCallback(YGCloneNodeFunc cloneNode) { - cloneNodeCallback_.noContext = cloneNode; - flags_.cloneNodeUsesContext = false; -} - -void YGConfig::setCloneNodeCallback(CloneWithContextFn cloneNode) { - cloneNodeCallback_.withContext = cloneNode; - flags_.cloneNodeUsesContext = true; -} - -void YGConfig::setCloneNodeCallback(std::nullptr_t) { - setCloneNodeCallback(YGCloneNodeFunc{nullptr}); -} - -YGNodeRef YGConfig::cloneNode( - YGNodeRef node, - YGNodeRef owner, - int childIndex, - void* cloneContext) const { - YGNodeRef clone = nullptr; - if (cloneNodeCallback_.noContext != nullptr) { - clone = flags_.cloneNodeUsesContext - ? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext) - : cloneNodeCallback_.noContext(node, owner, childIndex); - } - if (clone == nullptr) { - clone = YGNodeClone(node); - } - return clone; -} diff --git a/Sources/yoga/YGConfig.h b/Sources/yoga/YGConfig.h deleted file mode 100644 index eae7508a..00000000 --- a/Sources/yoga/YGConfig.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "BitUtils.h" -#include "Yoga.h" -#include "Yoga-internal.h" - -namespace facebook { -namespace yoga { - -// Whether moving a node from config "a" to config "b" should dirty previously -// calculated layout results. -bool configUpdateInvalidatesLayout(YGConfigRef a, YGConfigRef b); - -// Internal variants of log functions, currently used only by JNI bindings. -// TODO: Reconcile this with the public API -using LogWithContextFn = int (*)( - YGConfigRef config, - YGNodeRef node, - YGLogLevel level, - void* context, - const char* format, - va_list args); -using CloneWithContextFn = YGNodeRef (*)( - YGNodeRef node, - YGNodeRef owner, - int childIndex, - void* cloneContext); - -using ExperimentalFeatureSet = - facebook::yoga::detail::EnumBitset; - -#pragma pack(push) -#pragma pack(1) -// Packed structure of <32-bit options to miminize size per node. -struct YGConfigFlags { - bool useWebDefaults : 1; - bool printTree : 1; - bool cloneNodeUsesContext : 1; - bool loggerUsesContext : 1; -}; -#pragma pack(pop) - -} // namespace yoga -} // namespace facebook - -struct YOGA_EXPORT YGConfig { - YGConfig(YGLogger logger); - - void setUseWebDefaults(bool useWebDefaults); - bool useWebDefaults() const; - - void setShouldPrintTree(bool printTree); - bool shouldPrintTree() const; - - void setExperimentalFeatureEnabled( - YGExperimentalFeature feature, - bool enabled); - bool isExperimentalFeatureEnabled(YGExperimentalFeature feature) const; - facebook::yoga::ExperimentalFeatureSet getEnabledExperiments() const; - - void setErrata(YGErrata errata); - void addErrata(YGErrata errata); - void removeErrata(YGErrata errata); - YGErrata getErrata() const; - bool hasErrata(YGErrata errata) const; - - void setPointScaleFactor(float pointScaleFactor); - float getPointScaleFactor() const; - - void setContext(void* context); - void* getContext() const; - - void setLogger(YGLogger logger); - void setLogger(facebook::yoga::LogWithContextFn logger); - void setLogger(std::nullptr_t); - void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list) const; - - void setCloneNodeCallback(YGCloneNodeFunc cloneNode); - void setCloneNodeCallback(facebook::yoga::CloneWithContextFn cloneNode); - void setCloneNodeCallback(std::nullptr_t); - YGNodeRef cloneNode( - YGNodeRef node, - YGNodeRef owner, - int childIndex, - void* cloneContext) const; - -private: - union { - facebook::yoga::CloneWithContextFn withContext; - YGCloneNodeFunc noContext; - } cloneNodeCallback_; - union { - facebook::yoga::LogWithContextFn withContext; - YGLogger noContext; - } logger_; - - facebook::yoga::YGConfigFlags flags_{}; - facebook::yoga::ExperimentalFeatureSet experimentalFeatures_{}; - YGErrata errata_ = YGErrataNone; - float pointScaleFactor_ = 1.0f; - void* context_ = nullptr; -}; diff --git a/Sources/yoga/YGEnums.cpp b/Sources/yoga/YGEnums.cpp index 53629699..7f16628c 100644 --- a/Sources/yoga/YGEnums.cpp +++ b/Sources/yoga/YGEnums.cpp @@ -1,16 +1,14 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -// @generated by enums.py - #include "YGEnums.h" -const char* YGAlignToString(const YGAlign value) { - switch (value) { +const char *YGAlignToString(const YGAlign value){ + switch(value){ case YGAlignAuto: return "auto"; case YGAlignFlexStart: @@ -31,8 +29,8 @@ const char* YGAlignToString(const YGAlign value) { return "unknown"; } -const char* YGDimensionToString(const YGDimension value) { - switch (value) { +const char *YGDimensionToString(const YGDimension value){ + switch(value){ case YGDimensionWidth: return "width"; case YGDimensionHeight: @@ -41,8 +39,8 @@ const char* YGDimensionToString(const YGDimension value) { return "unknown"; } -const char* YGDirectionToString(const YGDirection value) { - switch (value) { +const char *YGDirectionToString(const YGDirection value){ + switch(value){ case YGDirectionInherit: return "inherit"; case YGDirectionLTR: @@ -53,8 +51,8 @@ const char* YGDirectionToString(const YGDirection value) { return "unknown"; } -const char* YGDisplayToString(const YGDisplay value) { - switch (value) { +const char *YGDisplayToString(const YGDisplay value){ + switch(value){ case YGDisplayFlex: return "flex"; case YGDisplayNone: @@ -63,8 +61,8 @@ const char* YGDisplayToString(const YGDisplay value) { return "unknown"; } -const char* YGEdgeToString(const YGEdge value) { - switch (value) { +const char *YGEdgeToString(const YGEdge value){ + switch(value){ case YGEdgeLeft: return "left"; case YGEdgeTop: @@ -87,34 +85,16 @@ const char* YGEdgeToString(const YGEdge value) { return "unknown"; } -const char* YGErrataToString(const YGErrata value) { - switch (value) { - case YGErrataNone: - return "none"; - case YGErrataStretchFlexBasis: - return "stretch-flex-basis"; - case YGErrataAll: - return "all"; - case YGErrataClassic: - return "classic"; - } - return "unknown"; -} - -const char* YGExperimentalFeatureToString(const YGExperimentalFeature value) { - switch (value) { +const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){ + switch(value){ case YGExperimentalFeatureWebFlexBasis: return "web-flex-basis"; - case YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge: - return "absolute-percentage-against-padding-edge"; - case YGExperimentalFeatureFixJNILocalRefOverflows: - return "fix-jnilocal-ref-overflows"; } return "unknown"; } -const char* YGFlexDirectionToString(const YGFlexDirection value) { - switch (value) { +const char *YGFlexDirectionToString(const YGFlexDirection value){ + switch(value){ case YGFlexDirectionColumn: return "column"; case YGFlexDirectionColumnReverse: @@ -127,20 +107,8 @@ const char* YGFlexDirectionToString(const YGFlexDirection value) { return "unknown"; } -const char* YGGutterToString(const YGGutter value) { - switch (value) { - case YGGutterColumn: - return "column"; - case YGGutterRow: - return "row"; - case YGGutterAll: - return "all"; - } - return "unknown"; -} - -const char* YGJustifyToString(const YGJustify value) { - switch (value) { +const char *YGJustifyToString(const YGJustify value){ + switch(value){ case YGJustifyFlexStart: return "flex-start"; case YGJustifyCenter: @@ -157,8 +125,8 @@ const char* YGJustifyToString(const YGJustify value) { return "unknown"; } -const char* YGLogLevelToString(const YGLogLevel value) { - switch (value) { +const char *YGLogLevelToString(const YGLogLevel value){ + switch(value){ case YGLogLevelError: return "error"; case YGLogLevelWarn: @@ -175,8 +143,8 @@ const char* YGLogLevelToString(const YGLogLevel value) { return "unknown"; } -const char* YGMeasureModeToString(const YGMeasureMode value) { - switch (value) { +const char *YGMeasureModeToString(const YGMeasureMode value){ + switch(value){ case YGMeasureModeUndefined: return "undefined"; case YGMeasureModeExactly: @@ -187,8 +155,8 @@ const char* YGMeasureModeToString(const YGMeasureMode value) { return "unknown"; } -const char* YGNodeTypeToString(const YGNodeType value) { - switch (value) { +const char *YGNodeTypeToString(const YGNodeType value){ + switch(value){ case YGNodeTypeDefault: return "default"; case YGNodeTypeText: @@ -197,8 +165,8 @@ const char* YGNodeTypeToString(const YGNodeType value) { return "unknown"; } -const char* YGOverflowToString(const YGOverflow value) { - switch (value) { +const char *YGOverflowToString(const YGOverflow value){ + switch(value){ case YGOverflowVisible: return "visible"; case YGOverflowHidden: @@ -209,10 +177,8 @@ const char* YGOverflowToString(const YGOverflow value) { return "unknown"; } -const char* YGPositionTypeToString(const YGPositionType value) { - switch (value) { - case YGPositionTypeStatic: - return "static"; +const char *YGPositionTypeToString(const YGPositionType value){ + switch(value){ case YGPositionTypeRelative: return "relative"; case YGPositionTypeAbsolute: @@ -221,8 +187,8 @@ const char* YGPositionTypeToString(const YGPositionType value) { return "unknown"; } -const char* YGPrintOptionsToString(const YGPrintOptions value) { - switch (value) { +const char *YGPrintOptionsToString(const YGPrintOptions value){ + switch(value){ case YGPrintOptionsLayout: return "layout"; case YGPrintOptionsStyle: @@ -233,8 +199,8 @@ const char* YGPrintOptionsToString(const YGPrintOptions value) { return "unknown"; } -const char* YGUnitToString(const YGUnit value) { - switch (value) { +const char *YGUnitToString(const YGUnit value){ + switch(value){ case YGUnitUndefined: return "undefined"; case YGUnitPoint: @@ -247,8 +213,8 @@ const char* YGUnitToString(const YGUnit value) { return "unknown"; } -const char* YGWrapToString(const YGWrap value) { - switch (value) { +const char *YGWrapToString(const YGWrap value){ + switch(value){ case YGWrapNoWrap: return "no-wrap"; case YGWrapWrap: diff --git a/Sources/yoga/YGFloatOptional.h b/Sources/yoga/YGFloatOptional.h deleted file mode 100644 index 4aa9e76e..00000000 --- a/Sources/yoga/YGFloatOptional.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include "Yoga-internal.h" - -struct YGFloatOptional { -private: - float value_ = std::numeric_limits::quiet_NaN(); - -public: - explicit constexpr YGFloatOptional(float value) : value_(value) {} - constexpr YGFloatOptional() = default; - - // returns the wrapped value, or a value x with YGIsUndefined(x) == true - constexpr float unwrap() const { return value_; } - - bool isUndefined() const { return std::isnan(value_); } -}; - -// operators take YGFloatOptional by value, as it is a 32bit value - -inline bool operator==(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs.unwrap() == rhs.unwrap() || - (lhs.isUndefined() && rhs.isUndefined()); -} -inline bool operator!=(YGFloatOptional lhs, YGFloatOptional rhs) { - return !(lhs == rhs); -} - -inline bool operator==(YGFloatOptional lhs, float rhs) { - return lhs == YGFloatOptional{rhs}; -} -inline bool operator!=(YGFloatOptional lhs, float rhs) { - return !(lhs == rhs); -} - -inline bool operator==(float lhs, YGFloatOptional rhs) { - return rhs == lhs; -} -inline bool operator!=(float lhs, YGFloatOptional rhs) { - return !(lhs == rhs); -} - -inline YGFloatOptional operator+(YGFloatOptional lhs, YGFloatOptional rhs) { - return YGFloatOptional{lhs.unwrap() + rhs.unwrap()}; -} - -inline bool operator>(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs.unwrap() > rhs.unwrap(); -} - -inline bool operator<(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs.unwrap() < rhs.unwrap(); -} - -inline bool operator>=(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs > rhs || lhs == rhs; -} - -inline bool operator<=(YGFloatOptional lhs, YGFloatOptional rhs) { - return lhs < rhs || lhs == rhs; -} diff --git a/Sources/yoga/YGLayout.cpp b/Sources/yoga/YGLayout.cpp index 9aadcd4a..66348fc2 100644 --- a/Sources/yoga/YGLayout.cpp +++ b/Sources/yoga/YGLayout.cpp @@ -1,42 +1,66 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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 "YGLayout.h" -#include "Utils.h" -using namespace facebook; +const std::array kYGDefaultDimensionValues = { + {YGUndefined, YGUndefined}}; + +YGLayout::YGLayout() + : position(), + dimensions(kYGDefaultDimensionValues), + margin(), + border(), + padding(), + direction(YGDirectionInherit), + computedFlexBasisGeneration(0), + computedFlexBasis(YGUndefined), + hadOverflow(false), + generationCount(0), + lastParentDirection((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 && + bool isEqual = position == layout.position && + dimensions == layout.dimensions && margin == layout.margin && + border == layout.border && padding == layout.padding && + direction == layout.direction && hadOverflow == layout.hadOverflow && + lastParentDirection == layout.lastParentDirection && nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex && - cachedLayout == layout.cachedLayout && - computedFlexBasis == layout.computedFlexBasis; + cachedLayout == layout.cachedLayout; 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])) { + if (!YGFloatIsUndefined(computedFlexBasis) || + !YGFloatIsUndefined(layout.computedFlexBasis)) { + isEqual = isEqual && (computedFlexBasis == layout.computedFlexBasis); + } + if (!YGFloatIsUndefined(measuredDimensions[0]) || + !YGFloatIsUndefined(layout.measuredDimensions[0])) { isEqual = isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]); } - if (!yoga::isUndefined(measuredDimensions[1]) || - !yoga::isUndefined(layout.measuredDimensions[1])) { + if (!YGFloatIsUndefined(measuredDimensions[1]) || + !YGFloatIsUndefined(layout.measuredDimensions[1])) { isEqual = isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]); } return isEqual; } + +bool YGLayout::operator!=(YGLayout layout) const { + return !(*this == layout); +} diff --git a/Sources/yoga/YGLayout.h b/Sources/yoga/YGLayout.h index 166eabb6..125a6d0b 100644 --- a/Sources/yoga/YGLayout.h +++ b/Sources/yoga/YGLayout.h @@ -1,63 +1,42 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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 "BitUtils.h" -#include "YGFloatOptional.h" #include "Yoga-internal.h" struct YGLayout { - std::array position = {}; - std::array dimensions = {{YGUndefined, YGUndefined}}; - std::array margin = {}; - std::array border = {}; - std::array padding = {}; - -private: - static constexpr size_t directionOffset = 0; - static constexpr size_t hadOverflowOffset = - directionOffset + facebook::yoga::detail::bitWidthFn(); - uint8_t flags = 0; - -public: - uint32_t computedFlexBasisGeneration = 0; - YGFloatOptional computedFlexBasis = {}; - - // Instead of recomputing the entire layout every single time, we cache some - // information to break early when nothing changed - uint32_t generationCount = 0; - YGDirection lastOwnerDirection = YGDirectionInherit; - - uint32_t nextCachedMeasurementsIndex = 0; + std::array position; + std::array dimensions; + std::array margin; + std::array border; + std::array padding; + 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; std::array - cachedMeasurements = {}; - std::array measuredDimensions = {{YGUndefined, YGUndefined}}; - - YGCachedMeasurement cachedLayout = YGCachedMeasurement(); - - YGDirection direction() const { - return facebook::yoga::detail::getEnumData( - flags, directionOffset); - } + cachedMeasurements; + std::array measuredDimensions; - void setDirection(YGDirection direction) { - facebook::yoga::detail::setEnumData( - flags, directionOffset, direction); - } + YGCachedMeasurement cachedLayout; + bool didUseLegacyFlag; + bool doesLegacyStretchFlagAffectsLayout; - bool hadOverflow() const { - return facebook::yoga::detail::getBooleanData(flags, hadOverflowOffset); - } - void setHadOverflow(bool hadOverflow) { - facebook::yoga::detail::setBooleanData( - flags, hadOverflowOffset, hadOverflow); - } + YGLayout(); bool operator==(YGLayout layout) const; - bool operator!=(YGLayout layout) const { return !(*this == layout); } + bool operator!=(YGLayout layout) const; }; diff --git a/Sources/yoga/YGNode.cpp b/Sources/yoga/YGNode.cpp index cd323b54..89be5bfe 100644 --- a/Sources/yoga/YGNode.cpp +++ b/Sources/yoga/YGNode.cpp @@ -1,234 +1,214 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * 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 #include #include "Utils.h" -using namespace facebook; -using facebook::yoga::detail::CompactValue; +void* YGNode::getContext() const { + return context_; +} -YGNode::YGNode(const YGConfigRef config) : config_{config} { - YGAssert( - config != nullptr, "Attempting to construct YGNode with null config"); +YGPrintFunc YGNode::getPrintFunc() const { + return print_; +} - flags_.hasNewLayout = true; - if (config->useWebDefaults()) { - useWebDefaults(); - } +bool YGNode::getHasNewLayout() const { + return hasNewLayout_; } -YGNode::YGNode(YGNode&& node) { - context_ = node.context_; - flags_ = node.flags_; - measure_ = node.measure_; - baseline_ = node.baseline_; - print_ = node.print_; - dirtied_ = node.dirtied_; - style_ = node.style_; - layout_ = node.layout_; - lineIndex_ = node.lineIndex_; - owner_ = node.owner_; - children_ = std::move(node.children_); - config_ = node.config_; - resolvedDimensions_ = node.resolvedDimensions_; - for (auto c : children_) { - c->setOwner(this); - } +YGNodeType YGNode::getNodeType() const { + return nodeType_; } -void YGNode::print(void* printContext) { - if (print_.noContext != nullptr) { - if (flags_.printUsesContext) { - print_.withContext(this, printContext); - } else { - print_.noContext(this); - } - } +YGMeasureFunc YGNode::getMeasure() const { + return measure_; } -CompactValue YGNode::computeEdgeValueForRow( - const YGStyle::Edges& edges, - YGEdge rowEdge, - YGEdge edge, - CompactValue defaultValue) { - if (!edges[rowEdge].isUndefined()) { - return edges[rowEdge]; - } else if (!edges[edge].isUndefined()) { - return edges[edge]; - } else if (!edges[YGEdgeHorizontal].isUndefined()) { - return edges[YGEdgeHorizontal]; - } else if (!edges[YGEdgeAll].isUndefined()) { - return edges[YGEdgeAll]; - } else { - return defaultValue; - } +YGBaselineFunc YGNode::getBaseline() const { + return baseline_; } -CompactValue YGNode::computeEdgeValueForColumn( - const YGStyle::Edges& edges, - YGEdge edge, - CompactValue defaultValue) { - if (!edges[edge].isUndefined()) { - return edges[edge]; - } else if (!edges[YGEdgeVertical].isUndefined()) { - return edges[YGEdgeVertical]; - } else if (!edges[YGEdgeAll].isUndefined()) { - return edges[YGEdgeAll]; - } else { - return defaultValue; - } +YGDirtiedFunc YGNode::getDirtied() const { + return dirtied_; } -CompactValue YGNode::computeRowGap( - const YGStyle::Gutters& gutters, - CompactValue defaultValue) { - if (!gutters[YGGutterRow].isUndefined()) { - return gutters[YGGutterRow]; - } else if (!gutters[YGGutterAll].isUndefined()) { - return gutters[YGGutterAll]; - } else { - return defaultValue; - } +YGStyle& YGNode::getStyle() { + return style_; } -CompactValue YGNode::computeColumnGap( - const YGStyle::Gutters& gutters, - CompactValue defaultValue) { - if (!gutters[YGGutterColumn].isUndefined()) { - return gutters[YGGutterColumn]; - } else if (!gutters[YGGutterAll].isUndefined()) { - return gutters[YGGutterAll]; - } else { - return defaultValue; - } +YGLayout& YGNode::getLayout() { + return layout_; +} + +uint32_t YGNode::getLineIndex() const { + return lineIndex_; +} + +YGNodeRef YGNode::getParent() const { + return parent_; +} + +YGVector YGNode::getChildren() const { + return children_; +} + +uint32_t YGNode::getChildrenCount() const { + return static_cast(children_.size()); +} + +YGNodeRef YGNode::getChild(uint32_t index) const { + return children_.at(index); +} + +YGNodeRef YGNode::getNextChild() const { + return nextChild_; +} + +YGConfigRef YGNode::getConfig() const { + return config_; +} + +bool YGNode::isDirty() const { + return isDirty_; +} + +YGValue YGNode::getResolvedDimension(int index) { + return resolvedDimensions_[index]; } -YGFloatOptional YGNode::getLeadingPosition( +std::array YGNode::getResolvedDimensions() const { + return resolvedDimensions_; +} + +float YGNode::getLeadingPosition( const YGFlexDirection axis, - const float axisSize) const { - auto leadingPosition = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.position(), - YGEdgeStart, - leading[axis], - CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.position(), leading[axis], CompactValue::ofZero()); - return YGResolveValue(leadingPosition, axisSize); -} - -YGFloatOptional YGNode::getTrailingPosition( + const float axisSize) { + 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 + ? 0.0f + : YGResolveValue(*leadingPosition, axisSize); +} + +float YGNode::getTrailingPosition( const YGFlexDirection axis, - const float axisSize) const { - auto trailingPosition = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.position(), - YGEdgeEnd, - trailing[axis], - CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.position(), trailing[axis], CompactValue::ofZero()); - return YGResolveValue(trailingPosition, axisSize); -} - -bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { - auto leadingPosition = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.position(), - YGEdgeStart, - leading[axis], - CompactValue::ofUndefined()) - : computeEdgeValueForColumn( - style_.position(), leading[axis], CompactValue::ofUndefined()); - return !leadingPosition.isUndefined(); -} - -bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const { - auto trailingPosition = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.position(), - YGEdgeEnd, - trailing[axis], - CompactValue::ofUndefined()) - : computeEdgeValueForColumn( - style_.position(), trailing[axis], CompactValue::ofUndefined()); - return !trailingPosition.isUndefined(); -} - -YGFloatOptional YGNode::getLeadingMargin( + const float axisSize) { + 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 + ? 0.0f + : YGResolveValue(*trailingPosition, axisSize); +} + +bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) { + return (YGFlexDirectionIsRow(axis) && + YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined) + ->unit != YGUnitUndefined) || + YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined) + ->unit != YGUnitUndefined; +} + +bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) { + return (YGFlexDirectionIsRow(axis) && + YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined) + ->unit != YGUnitUndefined) || + YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined) + ->unit != YGUnitUndefined; +} + +float YGNode::getLeadingMargin( const YGFlexDirection axis, - const float widthSize) const { - auto leadingMargin = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.margin(), YGEdgeStart, leading[axis], CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.margin(), leading[axis], CompactValue::ofZero()); - return YGResolveValueMargin(leadingMargin, widthSize); + const float widthSize) { + 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( +float YGNode::getTrailingMargin( const YGFlexDirection axis, - const float widthSize) const { - auto trailingMargin = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.margin(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.margin(), trailing[axis], CompactValue::ofZero()); - return YGResolveValueMargin(trailingMargin, widthSize); + const float widthSize) { + 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( +float YGNode::getMarginForAxis( const YGFlexDirection axis, - const float widthSize) const { + const float widthSize) { return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize); } -YGFloatOptional YGNode::getGapForAxis( - const YGFlexDirection axis, - const float widthSize) const { - auto gap = YGFlexDirectionIsRow(axis) - ? computeColumnGap(style_.gap(), CompactValue::ofZero()) - : computeRowGap(style_.gap(), CompactValue::ofZero()); - return YGResolveValue(gap, widthSize); +// Setters + +void YGNode::setContext(void* context) { + context_ = context; } -YGSize YGNode::measure( - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode, - void* layoutContext) { - return flags_.measureUsesContext - ? measure_.withContext( - this, width, widthMode, height, heightMode, layoutContext) - : measure_.noContext(this, width, widthMode, height, heightMode); +void YGNode::setPrintFunc(YGPrintFunc printFunc) { + print_ = printFunc; } -float YGNode::baseline(float width, float height, void* layoutContext) { - return flags_.baselineUsesContext - ? baseline_.withContext(this, width, height, layoutContext) - : baseline_.noContext(this, width, height); +void YGNode::setHasNewLayout(bool hasNewLayout) { + hasNewLayout_ = hasNewLayout; } -// Setters +void YGNode::setNodeType(YGNodeType nodeType) { + nodeType_ = nodeType; +} + +void YGNode::setStyleFlexDirection(YGFlexDirection direction) { + style_.flexDirection = direction; +} -void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) { - if (measureFunc.noContext == nullptr) { +void YGNode::setStyleAlignContent(YGAlign alignContent) { + style_.alignContent = alignContent; +} + +void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) { + if (measureFunc == nullptr) { + measure_ = nullptr; // TODO: t18095186 Move nodeType to opt-in function and mark appropriate // places in Litho - setNodeType(YGNodeTypeDefault); + nodeType_ = YGNodeTypeDefault; } else { YGAssertWithNode( this, children_.size() == 0, - "Cannot set measure function: Nodes with measure functions cannot have " - "children."); + "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); @@ -237,18 +217,36 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) { measure_ = measureFunc; } -void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) { - flags_.measureUsesContext = false; - decltype(YGNode::measure_) m; - m.noContext = measureFunc; - setMeasureFunc(m); +void YGNode::setBaseLineFunc(YGBaselineFunc baseLineFunc) { + baseline_ = baseLineFunc; } -YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) { - flags_.measureUsesContext = true; - decltype(YGNode::measure_) m; - m.withContext = measureFunc; - setMeasureFunc(m); +void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) { + dirtied_ = dirtiedFunc; +} + +void YGNode::setStyle(YGStyle style) { + style_ = style; +} + +void YGNode::setLayout(YGLayout layout) { + layout_ = layout; +} + +void YGNode::setLineIndex(uint32_t lineIndex) { + lineIndex_ = lineIndex; +} + +void YGNode::setParent(YGNodeRef parent) { + parent_ = parent; +} + +void YGNode::setChildren(YGVector children) { + children_ = children; +} + +void YGNode::setNextChild(YGNodeRef nextChild) { + nextChild_ = nextChild; } void YGNode::replaceChild(YGNodeRef child, uint32_t index) { @@ -264,24 +262,14 @@ void YGNode::insertChild(YGNodeRef child, uint32_t index) { } void YGNode::setConfig(YGConfigRef config) { - YGAssert(config != nullptr, "Attempting to set a null config on a YGNode"); - YGAssertWithConfig( - config, - config->useWebDefaults() == config_->useWebDefaults(), - "UseWebDefaults may not be changed after constructing a YGNode"); - - if (yoga::configUpdateInvalidatesLayout(config_, config)) { - markDirtyAndPropagate(); - } - config_ = config; } void YGNode::setDirty(bool isDirty) { - if (isDirty == flags_.isDirty) { + if (isDirty == isDirty_) { return; } - flags_.isDirty = isDirty; + isDirty_ = isDirty; if (isDirty && dirtied_) { dirtied_(this); } @@ -302,7 +290,7 @@ void YGNode::removeChild(uint32_t index) { } void YGNode::setLayoutDirection(YGDirection direction) { - layout_.setDirection(direction); + layout_.direction = direction; } void YGNode::setLayoutMargin(float margin, int index) { @@ -317,12 +305,11 @@ void YGNode::setLayoutPadding(float padding, int index) { layout_.padding[index] = padding; } -void YGNode::setLayoutLastOwnerDirection(YGDirection direction) { - layout_.lastOwnerDirection = direction; +void YGNode::setLayoutLastParentDirection(YGDirection direction) { + layout_.lastParentDirection = direction; } -void YGNode::setLayoutComputedFlexBasis( - const YGFloatOptional computedFlexBasis) { +void YGNode::setLayoutComputedFlexBasis(float computedFlexBasis) { layout_.computedFlexBasis = computedFlexBasis; } @@ -340,245 +327,417 @@ void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) { } void YGNode::setLayoutHadOverflow(bool hadOverflow) { - layout_.setHadOverflow(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( +// If both left and right are defined, then use left. Otherwise return +// +left or -right depending on which is defined. +float 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 = YGFloatOptional{-1 * trailingPosition.unwrap()}; - } - return trailingPosition; + const float axisSize) { + return isLeadingPositionDefined(axis) ? getLeadingPosition(axis, axisSize) + : -getTrailingPosition(axis, axisSize); } void YGNode::setPosition( const YGDirection direction, const float mainSize, const float crossSize, - const float ownerWidth) { + const float parentWidth) { /* Root nodes should be always layouted as LTR, so we don't return negative * values. */ const YGDirection directionRespectingRoot = - owner_ != nullptr ? direction : YGDirectionLTR; + parent_ != nullptr ? direction : YGDirectionLTR; const YGFlexDirection mainAxis = - YGResolveFlexDirection(style_.flexDirection(), directionRespectingRoot); + YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot); const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, directionRespectingRoot); - // Here we should check for `YGPositionTypeStatic` and in this case zero inset - // properties (left, right, top, bottom, begin, end). - // https://www.w3.org/TR/css-position-3/#valdef-position-static - const YGFloatOptional relativePositionMain = - relativePosition(mainAxis, mainSize); - const YGFloatOptional relativePositionCross = - relativePosition(crossAxis, crossSize); + const float relativePositionMain = relativePosition(mainAxis, mainSize); + const float relativePositionCross = relativePosition(crossAxis, crossSize); setLayoutPosition( - (getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), + getLeadingMargin(mainAxis, parentWidth) + relativePositionMain, leading[mainAxis]); setLayoutPosition( - (getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), + getTrailingMargin(mainAxis, parentWidth) + relativePositionMain, trailing[mainAxis]); setLayoutPosition( - (getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross) - .unwrap(), + getLeadingMargin(crossAxis, parentWidth) + relativePositionCross, leading[crossAxis]); setLayoutPosition( - (getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross) - .unwrap(), + getTrailingMargin(crossAxis, parentWidth) + relativePositionCross, trailing[crossAxis]); } +YGNode::YGNode() + : context_(nullptr), + print_(nullptr), + hasNewLayout_(true), + nodeType_(YGNodeTypeDefault), + measure_(nullptr), + baseline_(nullptr), + dirtied_(nullptr), + style_(YGStyle()), + layout_(YGLayout()), + lineIndex_(0), + parent_(nullptr), + children_(YGVector()), + nextChild_(nullptr), + config_(nullptr), + isDirty_(false), + resolvedDimensions_({{YGValueUndefined, YGValueUndefined}}) {} + +YGNode::YGNode(const YGNode& node) + : context_(node.context_), + print_(node.print_), + hasNewLayout_(node.hasNewLayout_), + nodeType_(node.nodeType_), + measure_(node.measure_), + baseline_(node.baseline_), + dirtied_(node.dirtied_), + style_(node.style_), + layout_(node.layout_), + lineIndex_(node.lineIndex_), + parent_(node.parent_), + children_(node.children_), + nextChild_(node.nextChild_), + config_(node.config_), + isDirty_(node.isDirty_), + resolvedDimensions_(node.resolvedDimensions_) {} + +YGNode::YGNode(const YGConfigRef newConfig) : YGNode() { + config_ = newConfig; +} + +YGNode::YGNode( + void* context, + YGPrintFunc print, + bool hasNewLayout, + YGNodeType nodeType, + YGMeasureFunc measure, + YGBaselineFunc baseline, + YGDirtiedFunc dirtied, + YGStyle style, + YGLayout layout, + uint32_t lineIndex, + YGNodeRef parent, + YGVector children, + YGNodeRef nextChild, + YGConfigRef config, + bool isDirty, + std::array resolvedDimensions) + : context_(context), + print_(print), + hasNewLayout_(hasNewLayout), + nodeType_(nodeType), + measure_(measure), + baseline_(baseline), + dirtied_(dirtied), + style_(style), + layout_(layout), + lineIndex_(lineIndex), + parent_(parent), + children_(children), + nextChild_(nextChild), + config_(config), + isDirty_(isDirty), + resolvedDimensions_(resolvedDimensions) {} + +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(); + parent_ = node.getParent(); + children_ = node.getChildren(); + nextChild_ = node.getNextChild(); + config_ = node.getConfig(); + isDirty_ = node.isDirty(); + resolvedDimensions_ = node.getResolvedDimensions(); + + return *this; +} + YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const { if (YGFlexDirectionIsRow(axis) && - !style_.margin()[YGEdgeStart].isUndefined()) { - return style_.margin()[YGEdgeStart]; + style_.margin[YGEdgeStart].unit != YGUnitUndefined) { + return style_.margin[YGEdgeStart]; } else { - return style_.margin()[leading[axis]]; + return style_.margin[leading[axis]]; } } YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const { - if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) { - return style_.margin()[YGEdgeEnd]; + if (YGFlexDirectionIsRow(axis) && + style_.margin[YGEdgeEnd].unit != YGUnitUndefined) { + return style_.margin[YGEdgeEnd]; } else { - return style_.margin()[trailing[axis]]; + return style_.margin[trailing[axis]]; } } YGValue YGNode::resolveFlexBasisPtr() const { - YGValue flexBasis = style_.flexBasis(); + YGValue flexBasis = style_.flexBasis; if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) { return flexBasis; } - if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { - return config_->useWebDefaults() ? YGValueAuto : YGValueZero; + if (!YGFloatIsUndefined(style_.flex) && style_.flex > 0.0f) { + return config_->useWebDefaults ? YGValueAuto : YGValueZero; } return YGValueAuto; } void YGNode::resolveDimension() { - using namespace yoga; - const YGStyle& style = getStyle(); - for (auto dim : {YGDimensionWidth, YGDimensionHeight}) { - if (!style.maxDimensions()[dim].isUndefined() && - YGValueEqual(style.maxDimensions()[dim], style.minDimensions()[dim])) { - resolvedDimensions_[dim] = style.maxDimensions()[dim]; + 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]; + resolvedDimensions_[dim] = style_.dimensions[dim]; } } } -YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) { - if (style_.direction() == YGDirectionInherit) { - return ownerDirection > YGDirectionInherit ? ownerDirection - : YGDirectionLTR; +YGDirection YGNode::resolveDirection(const YGDirection parentDirection) { + if (style_.direction == YGDirectionInherit) { + return parentDirection > YGDirectionInherit ? parentDirection + : YGDirectionLTR; } else { - return style_.direction(); + return style_.direction; } } -YOGA_EXPORT void YGNode::clearChildren() { +void YGNode::clearChildren() { children_.clear(); children_.shrink_to_fit(); } +YGNode::~YGNode() { + // All the member variables are deallocated externally, so no need to + // deallocate here +} + // Other Methods -void YGNode::cloneChildrenIfNeeded(void* cloneContext) { - iterChildrenAfterCloningIfNeeded([](YGNodeRef, void*) {}, cloneContext); +void YGNode::cloneChildrenIfNeeded() { + // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm + // optimized for deletions. + + const uint32_t childCount = static_cast(children_.size()); + if (childCount == 0) { + // This is an empty set. Nothing to clone. + return; + } + + const YGNodeRef firstChild = children_.front(); + if (firstChild->getParent() == this) { + // 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 = config_->cloneNodeCallback; + for (uint32_t i = 0; i < childCount; ++i) { + const YGNodeRef oldChild = children_[i]; + const YGNodeRef newChild = YGNodeClone(oldChild); + replaceChild(newChild, i); + newChild->setParent(this); + if (cloneNodeCallback) { + cloneNodeCallback(oldChild, newChild, this, i); + } + } } -void YGNode::markDirtyAndPropagate() { - if (!flags_.isDirty) { +void YGNode::markDirtyAndPropogate() { + if (!isDirty_) { setDirty(true); - setLayoutComputedFlexBasis(YGFloatOptional()); - if (owner_) { - owner_->markDirtyAndPropagate(); + setLayoutComputedFlexBasis(YGUndefined); + if (parent_) { + parent_->markDirtyAndPropogate(); } } } -void YGNode::markDirtyAndPropagateDownwards() { - flags_.isDirty = true; +void YGNode::markDirtyAndPropogateDownwards() { + isDirty_ = true; for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) { - childNode->markDirtyAndPropagateDownwards(); + childNode->markDirtyAndPropogateDownwards(); }); } -float YGNode::resolveFlexGrow() const { +float YGNode::resolveFlexGrow() { // Root nodes flexGrow should always be 0 - if (owner_ == nullptr) { + if (parent_ == nullptr) { return 0.0; } - if (!style_.flexGrow().isUndefined()) { - return style_.flexGrow().unwrap(); + if (!YGFloatIsUndefined(style_.flexGrow)) { + return style_.flexGrow; } - if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { - return style_.flex().unwrap(); + if (!YGFloatIsUndefined(style_.flex) && style_.flex > 0.0f) { + return style_.flex; } return kDefaultFlexGrow; } -float YGNode::resolveFlexShrink() const { - if (owner_ == nullptr) { +float YGNode::resolveFlexShrink() { + if (parent_ == nullptr) { return 0.0; } - if (!style_.flexShrink().isUndefined()) { - return style_.flexShrink().unwrap(); + if (!YGFloatIsUndefined(style_.flexShrink)) { + return style_.flexShrink; } - if (!config_->useWebDefaults() && !style_.flex().isUndefined() && - style_.flex().unwrap() < 0.0f) { - return -style_.flex().unwrap(); + if (!config_->useWebDefaults && !YGFloatIsUndefined(style_.flex) && + style_.flex < 0.0f) { + return -style_.flex; } - return config_->useWebDefaults() ? kWebDefaultFlexShrink : kDefaultFlexShrink; + return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; } bool YGNode::isNodeFlexible() { return ( - (style_.positionType() != YGPositionTypeAbsolute) && + (style_.positionType == YGPositionTypeRelative) && (resolveFlexGrow() != 0 || resolveFlexShrink() != 0)); } -float YGNode::getLeadingBorder(const YGFlexDirection axis) const { - YGValue leadingBorder = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.border(), YGEdgeStart, leading[axis], CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.border(), leading[axis], CompactValue::ofZero()); - return fmaxf(leadingBorder.value, 0.0f); +float YGNode::getLeadingBorder(const YGFlexDirection axis) { + if (YGFlexDirectionIsRow(axis) && + style_.border[YGEdgeStart].unit != YGUnitUndefined && + style_.border[YGEdgeStart].value >= 0.0f) { + return style_.border[YGEdgeStart].value; + } + + return fmaxf( + YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value, + 0.0f); } -float YGNode::getTrailingBorder(const YGFlexDirection axis) const { - YGValue trailingBorder = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.border(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.border(), trailing[axis], CompactValue::ofZero()); - return fmaxf(trailingBorder.value, 0.0f); +float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) { + if (YGFlexDirectionIsRow(flexDirection) && + style_.border[YGEdgeEnd].unit != YGUnitUndefined && + style_.border[YGEdgeEnd].value >= 0.0f) { + return style_.border[YGEdgeEnd].value; + } + + return fmaxf( + YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero) + ->value, + 0.0f); } -YGFloatOptional YGNode::getLeadingPadding( +float YGNode::getLeadingPadding( const YGFlexDirection axis, - const float widthSize) const { - auto leadingPadding = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.padding(), - YGEdgeStart, - leading[axis], - CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.padding(), leading[axis], CompactValue::ofZero()); - return YGFloatOptionalMax( - YGResolveValue(leadingPadding, widthSize), YGFloatOptional(0.0f)); -} - -YGFloatOptional YGNode::getTrailingPadding( + const float widthSize) { + if (YGFlexDirectionIsRow(axis) && + style_.padding[YGEdgeStart].unit != YGUnitUndefined && + YGResolveValue(style_.padding[YGEdgeStart], widthSize) >= 0.0f) { + return YGResolveValue(style_.padding[YGEdgeStart], widthSize); + } + return fmaxf( + YGResolveValue( + *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero), + widthSize), + 0.0f); +} + +float YGNode::getTrailingPadding( const YGFlexDirection axis, - const float widthSize) const { - auto trailingPadding = YGFlexDirectionIsRow(axis) - ? computeEdgeValueForRow( - style_.padding(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) - : computeEdgeValueForColumn( - style_.padding(), trailing[axis], CompactValue::ofZero()); - return YGFloatOptionalMax( - YGResolveValue(trailingPadding, widthSize), YGFloatOptional(0.0f)); + const float widthSize) { + if (YGFlexDirectionIsRow(axis) && + style_.padding[YGEdgeEnd].unit != YGUnitUndefined && + YGResolveValue(style_.padding[YGEdgeEnd], widthSize) >= 0.0f) { + return YGResolveValue(style_.padding[YGEdgeEnd], widthSize); + } + return fmaxf( + YGResolveValue( + *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero), + widthSize), + 0.0f); } -YGFloatOptional YGNode::getLeadingPaddingAndBorder( +float YGNode::getLeadingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize) const { - return getLeadingPadding(axis, widthSize) + - YGFloatOptional(getLeadingBorder(axis)); + const float widthSize) { + return getLeadingPadding(axis, widthSize) + getLeadingBorder(axis); } -YGFloatOptional YGNode::getTrailingPaddingAndBorder( +float YGNode::getTrailingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize) const { - return getTrailingPadding(axis, widthSize) + - YGFloatOptional(getTrailingBorder(axis)); + const float widthSize) { + return getTrailingPadding(axis, widthSize) + 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::reset() { - YGAssertWithNode( - this, - children_.size() == 0, - "Cannot reset a node which still has children attached"); - YGAssertWithNode( - this, owner_ == nullptr, "Cannot reset a node still attached to a owner"); +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; +} - *this = YGNode{getConfig()}; +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::size_type i = 0; i < children_.size(); ++i) { + otherNodeChildren = node.children_[i]; + isLayoutTreeEqual = + children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren); + if (!isLayoutTreeEqual) { + return false; + } + } + return isLayoutTreeEqual; } diff --git a/Sources/yoga/YGNode.h b/Sources/yoga/YGNode.h index e3c202f2..27a1ed68 100644 --- a/Sources/yoga/YGNode.h +++ b/Sources/yoga/YGNode.h @@ -1,299 +1,123 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * 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 #include -#include "CompactValue.h" -#include "YGConfig.h" #include "YGLayout.h" #include "YGStyle.h" #include "Yoga-internal.h" -YGConfigRef YGConfigGetDefault(); - -#pragma pack(push) -#pragma pack(1) -struct YGNodeFlags { - bool hasNewLayout : 1; - bool isReferenceBaseline : 1; - bool isDirty : 1; - uint8_t nodeType : 1; - bool measureUsesContext : 1; - bool baselineUsesContext : 1; - bool printUsesContext : 1; -}; -#pragma pack(pop) - -struct YOGA_EXPORT YGNode { - using MeasureWithContextFn = - YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*); - using BaselineWithContextFn = float (*)(YGNode*, float, float, void*); - using PrintWithContextFn = void (*)(YGNode*, void*); - -private: - void* context_ = nullptr; - YGNodeFlags flags_ = {}; - union { - YGMeasureFunc noContext; - MeasureWithContextFn withContext; - } measure_ = {nullptr}; - union { - YGBaselineFunc noContext; - BaselineWithContextFn withContext; - } baseline_ = {nullptr}; - union { - YGPrintFunc noContext; - PrintWithContextFn withContext; - } print_ = {nullptr}; - YGDirtiedFunc dirtied_ = nullptr; - YGStyle style_ = {}; - YGLayout layout_ = {}; - uint32_t lineIndex_ = 0; - YGNodeRef owner_ = nullptr; - YGVector children_ = {}; +struct YGNode { + private: + void* context_; + YGPrintFunc print_; + bool hasNewLayout_; + YGNodeType nodeType_; + YGMeasureFunc measure_; + YGBaselineFunc baseline_; + YGDirtiedFunc dirtied_; + YGStyle style_; + YGLayout layout_; + uint32_t lineIndex_; + YGNodeRef parent_; + YGVector children_; + YGNodeRef nextChild_; YGConfigRef config_; - std::array resolvedDimensions_ = { - {YGValueUndefined, YGValueUndefined}}; - - YGFloatOptional relativePosition( - const YGFlexDirection axis, - const float axisSize) const; - - void setMeasureFunc(decltype(measure_)); - void setBaselineFunc(decltype(baseline_)); - - void useWebDefaults() { - style_.flexDirection() = YGFlexDirectionRow; - style_.alignContent() = YGAlignStretch; - } - - // DANGER DANGER DANGER! - // If the node assigned to has children, we'd either have to deallocate - // them (potentially incorrect) or ignore them (danger of leaks). Only ever - // use this after checking that there are no children. - // DO NOT CHANGE THE VISIBILITY OF THIS METHOD! - YGNode& operator=(YGNode&&) = default; - - using CompactValue = facebook::yoga::detail::CompactValue; - -public: - YGNode() : YGNode{YGConfigGetDefault()} { flags_.hasNewLayout = true; } - explicit YGNode(const YGConfigRef config); - ~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree - - YGNode(YGNode&&); - - // Does not expose true value semantics, as children are not cloned eagerly. - // Should we remove this? - YGNode(const YGNode& node) = default; - - // assignment means potential leaks of existing children, or alternatively - // freeing unowned memory, double free, or freeing stack memory. - YGNode& operator=(const YGNode&) = delete; + bool isDirty_; + std::array resolvedDimensions_; + + float relativePosition(const YGFlexDirection axis, const float axisSize); + + public: + YGNode(); + ~YGNode(); + explicit YGNode(const YGConfigRef newConfig); + YGNode(const YGNode& node); + YGNode& operator=(const YGNode& node); + YGNode( + void* context, + YGPrintFunc print, + bool hasNewLayout, + YGNodeType nodeType, + YGMeasureFunc measure, + YGBaselineFunc baseline, + YGDirtiedFunc dirtied, + YGStyle style, + YGLayout layout, + uint32_t lineIndex, + YGNodeRef parent, + YGVector children, + YGNodeRef nextChild, + YGConfigRef config, + bool isDirty, + std::array resolvedDimensions); // Getters - void* getContext() const { return context_; } - - void print(void*); - - bool getHasNewLayout() const { return flags_.hasNewLayout; } - - YGNodeType getNodeType() const { - return static_cast(flags_.nodeType); - } - - bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; } - - YGSize measure(float, YGMeasureMode, float, YGMeasureMode, void*); - - bool hasBaselineFunc() const noexcept { - return baseline_.noContext != nullptr; - } - - float baseline(float width, float height, void* layoutContext); - - bool hasErrata(YGErrata errata) const { return config_->hasErrata(errata); } - - YGDirtiedFunc getDirtied() const { return dirtied_; } - + void* getContext() const; + YGPrintFunc getPrintFunc() const; + bool getHasNewLayout() const; + YGNodeType getNodeType() const; + YGMeasureFunc getMeasure() const; + YGBaselineFunc getBaseline() const; + YGDirtiedFunc getDirtied() const; // For Performance reasons passing as reference. - YGStyle& getStyle() { return style_; } - - const YGStyle& getStyle() const { return style_; } - + YGStyle& getStyle(); // For Performance reasons passing as reference. - YGLayout& getLayout() { return layout_; } - - const YGLayout& getLayout() const { return layout_; } - - uint32_t getLineIndex() const { return lineIndex_; } - - bool isReferenceBaseline() { return flags_.isReferenceBaseline; } - - // 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_; } - - // Applies a callback to all children, after cloning them if they are not - // owned. - template - void iterChildrenAfterCloningIfNeeded(T callback, void* cloneContext) { - int i = 0; - for (YGNodeRef& child : children_) { - if (child->getOwner() != this) { - child = config_->cloneNode(child, this, i, cloneContext); - child->setOwner(this); - } - i += 1; - - callback(child, cloneContext); - } - } - - YGNodeRef getChild(uint32_t index) const { return children_.at(index); } - - YGConfigRef getConfig() const { return config_; } - - bool isDirty() const { return flags_.isDirty; } - - std::array getResolvedDimensions() const { - return resolvedDimensions_; - } - - YGValue getResolvedDimension(int index) const { - return resolvedDimensions_[index]; - } - - static CompactValue computeEdgeValueForColumn( - const YGStyle::Edges& edges, - YGEdge edge, - CompactValue defaultValue); - - static CompactValue computeEdgeValueForRow( - const YGStyle::Edges& edges, - YGEdge rowEdge, - YGEdge edge, - CompactValue defaultValue); - - static CompactValue computeRowGap( - const YGStyle::Gutters& gutters, - CompactValue defaultValue); - - static CompactValue computeColumnGap( - const YGStyle::Gutters& gutters, - CompactValue defaultValue); + YGLayout& getLayout(); + uint32_t getLineIndex() const; + YGNodeRef getParent() const; + YGVector getChildren() const; + uint32_t getChildrenCount() const; + YGNodeRef getChild(uint32_t index) const; + YGNodeRef getNextChild() const; + YGConfigRef getConfig() const; + bool isDirty() const; + std::array getResolvedDimensions() const; + YGValue getResolvedDimension(int 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( + float getLeadingPosition(const YGFlexDirection axis, const float axisSize); + bool isLeadingPositionDefined(const YGFlexDirection axis); + bool isTrailingPosDefined(const YGFlexDirection axis); + float getTrailingPosition(const YGFlexDirection axis, const float axisSize); + float getLeadingMargin(const YGFlexDirection axis, const float widthSize); + float getTrailingMargin(const YGFlexDirection axis, const float widthSize); + float getLeadingBorder(const YGFlexDirection flexDirection); + float getTrailingBorder(const YGFlexDirection flexDirection); + float getLeadingPadding(const YGFlexDirection axis, const float widthSize); + float getTrailingPadding(const YGFlexDirection axis, const float widthSize); + float getLeadingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize) const; - YGFloatOptional getMarginForAxis( + const float widthSize); + float getTrailingPaddingAndBorder( const YGFlexDirection axis, - const float widthSize) const; - YGFloatOptional getGapForAxis( - const YGFlexDirection axis, - const float widthSize) const; + const float widthSize); + float getMarginForAxis(const YGFlexDirection axis, const float widthSize); // Setters - void setContext(void* context) { context_ = context; } - - void setPrintFunc(YGPrintFunc printFunc) { - print_.noContext = printFunc; - flags_.printUsesContext = false; - } - void setPrintFunc(PrintWithContextFn printFunc) { - print_.withContext = printFunc; - flags_.printUsesContext = true; - } - void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); } - - void setHasNewLayout(bool hasNewLayout) { - flags_.hasNewLayout = hasNewLayout; - } - - void setNodeType(YGNodeType nodeType) { - flags_.nodeType = static_cast(nodeType); - } - + void setContext(void* context); + void setPrintFunc(YGPrintFunc printFunc); + void setHasNewLayout(bool hasNewLayout); + void setNodeType(YGNodeType nodeTye); void setMeasureFunc(YGMeasureFunc measureFunc); - void setMeasureFunc(MeasureWithContextFn); - void setMeasureFunc(std::nullptr_t) { - return setMeasureFunc(YGMeasureFunc{nullptr}); - } - - void setBaselineFunc(YGBaselineFunc baseLineFunc) { - flags_.baselineUsesContext = false; - baseline_.noContext = baseLineFunc; - } - void setBaselineFunc(BaselineWithContextFn baseLineFunc) { - flags_.baselineUsesContext = true; - baseline_.withContext = baseLineFunc; - } - void setBaselineFunc(std::nullptr_t) { - return setBaselineFunc(YGBaselineFunc{nullptr}); - } - - 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 setIsReferenceBaseline(bool isReferenceBaseline) { - flags_.isReferenceBaseline = isReferenceBaseline; - } - - void setOwner(YGNodeRef owner) { owner_ = owner; } - - void setChildren(const YGVector& children) { children_ = children; } - - // TODO: rvalue override for setChildren - + void setBaseLineFunc(YGBaselineFunc baseLineFunc); + void setDirtiedFunc(YGDirtiedFunc dirtiedFunc); + void setStyle(YGStyle style); + void setStyleFlexDirection(YGFlexDirection direction); + void setStyleAlignContent(YGAlign alignContent); + void setLayout(YGLayout layout); + void setLineIndex(uint32_t lineIndex); + void setParent(YGNodeRef parent); + void setChildren(YGVector children); + void setNextChild(YGNodeRef nextChild); void setConfig(YGConfigRef config); - void setDirty(bool isDirty); - void setLayoutLastOwnerDirection(YGDirection direction); - void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis); + void setLayoutLastParentDirection(YGDirection direction); + void setLayoutComputedFlexBasis(float computedFlexBasis); void setLayoutComputedFlexBasisGeneration( uint32_t computedFlexBasisGeneration); void setLayoutMeasuredDimension(float measuredDimension, int index); @@ -308,15 +132,18 @@ struct YOGA_EXPORT YGNode { const YGDirection direction, const float mainSize, const float crossSize, - const float ownerWidth); - void markDirtyAndPropagateDownwards(); + const float parentWidth); + 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); + YGDirection resolveDirection(const YGDirection parentDirection); void clearChildren(); /// Replaces the occurrences of oldChild with newChild void replaceChild(YGNodeRef oldChild, YGNodeRef newChild); @@ -326,10 +153,11 @@ struct YOGA_EXPORT YGNode { bool removeChild(YGNodeRef child); void removeChild(uint32_t index); - void cloneChildrenIfNeeded(void*); - void markDirtyAndPropagate(); - float resolveFlexGrow() const; - float resolveFlexShrink() const; + void cloneChildrenIfNeeded(); + void markDirtyAndPropogate(); + float resolveFlexGrow(); + float resolveFlexShrink(); bool isNodeFlexible(); - void reset(); + bool didUseLegacyFlag(); + bool isLayoutTreeEqualToNode(const YGNode& node) const; }; diff --git a/Sources/yoga/YGNodePrint.cpp b/Sources/yoga/YGNodePrint.cpp index 08c4a9f7..395fe181 100644 --- a/Sources/yoga/YGNodePrint.cpp +++ b/Sources/yoga/YGNodePrint.cpp @@ -1,36 +1,32 @@ /* - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2017-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -#ifdef DEBUG - +#include "YGNodePrint.h" #include - #include "YGEnums.h" -#include "YGNodePrint.h" #include "YGNode.h" #include "Yoga-internal.h" -#include "Utils.h" namespace facebook { namespace yoga { typedef std::string string; -static void indent(string& base, uint32_t level) { +static void indent(string* base, uint32_t level) { for (uint32_t i = 0; i < level; ++i) { - base.append(" "); + base->append(" "); } } -static bool areFourValuesEqual(const YGStyle::Edges& four) { +static bool areFourValuesEqual(const std::array& four) { return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) && YGValueEqual(four[0], four[3]); } -static void appendFormattedString(string& str, const char* fmt, ...) { +static void appendFormatedString(string* str, const char* fmt, ...) { va_list args; va_start(args, fmt); va_list argsCopy; @@ -40,61 +36,51 @@ static void appendFormattedString(string& str, const char* fmt, ...) { vsnprintf(buf.data(), buf.size(), fmt, argsCopy); va_end(argsCopy); string result = string(buf.begin(), buf.end() - 1); - str.append(result); + str->append(result); } -static void appendFloatOptionalIfDefined( - string& base, - const string key, - const YGFloatOptional num) { - if (!num.isUndefined()) { - appendFormattedString(base, "%s: %g; ", key.c_str(), num.unwrap()); +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, + string* base, const string key, const YGValue number) { if (number.unit != YGUnitUndefined) { if (number.unit == YGUnitAuto) { - base.append(key + ": auto; "); + base->append(key + ": auto; "); } else { string unit = number.unit == YGUnitPoint ? "px" : "%%"; - appendFormattedString( + appendFormatedString( base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str()); } } } -static void appendNumberIfNotAuto( - string& base, - const string& key, - const YGValue number) { +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)) { +static void +appendNumberIfNotZero(string* base, const string& str, const YGValue number) { + if (!YGFloatsEqual(number.value, 0)) { appendNumberIfNotUndefined(base, str, number); } } static void appendEdges( - string& base, + string* base, const string& key, - const YGStyle::Edges& edges) { + const std::array& edges) { if (areFourValuesEqual(edges)) { - auto edgeValue = YGNode::computeEdgeValueForColumn( - edges, YGEdgeLeft, detail::CompactValue::ofZero()); - appendNumberIfNotZero(base, key, edgeValue); + appendNumberIfNotZero(base, key, edges[YGEdgeLeft]); } else { for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) { string str = key + "-" + YGEdgeToString(static_cast(edge)); @@ -104,143 +90,136 @@ static void appendEdges( } static void appendEdgeIfNotUndefined( - string& base, + string* base, const string& str, - const YGStyle::Edges& edges, + const std::array& edges, const YGEdge edge) { - // TODO: this doesn't take RTL / YGEdgeStart / YGEdgeEnd into account - auto value = (edge == YGEdgeLeft || edge == YGEdgeRight) - ? YGNode::computeEdgeValueForRow( - edges, edge, edge, detail::CompactValue::ofUndefined()) - : YGNode::computeEdgeValueForColumn( - edges, edge, detail::CompactValue::ofUndefined()); - appendNumberIfNotUndefined(base, str, value); + appendNumberIfNotUndefined( + base, str, *YGComputedEdgeValue(edges, edge, &YGValueUndefined)); } void YGNodeToString( - std::string& str, + std::string* str, YGNodeRef node, YGPrintOptions options, uint32_t level) { indent(str, level); - appendFormattedString(str, "
getPrintFunc() != nullptr) { + node->getPrintFunc()(node); + } if (options & YGPrintOptionsLayout) { - appendFormattedString(str, "layout=\""); - appendFormattedString( + appendFormatedString(str, "layout=\""); + appendFormatedString( str, "width: %g; ", node->getLayout().dimensions[YGDimensionWidth]); - appendFormattedString( + appendFormatedString( str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]); - appendFormattedString( + appendFormatedString( str, "top: %g; ", node->getLayout().position[YGEdgeTop]); - appendFormattedString( + appendFormatedString( str, "left: %g;", node->getLayout().position[YGEdgeLeft]); - appendFormattedString(str, "\" "); + appendFormatedString(str, "\" "); } if (options & YGPrintOptionsStyle) { - appendFormattedString(str, "style=\""); - const auto& style = node->getStyle(); - if (style.flexDirection() != YGNode().getStyle().flexDirection()) { - appendFormattedString( + appendFormatedString(str, "style=\""); + if (node->getStyle().flexDirection != YGNode().getStyle().flexDirection) { + appendFormatedString( str, "flex-direction: %s; ", - YGFlexDirectionToString(style.flexDirection())); + YGFlexDirectionToString(node->getStyle().flexDirection)); } - if (style.justifyContent() != YGNode().getStyle().justifyContent()) { - appendFormattedString( + if (node->getStyle().justifyContent != YGNode().getStyle().justifyContent) { + appendFormatedString( str, "justify-content: %s; ", - YGJustifyToString(style.justifyContent())); + YGJustifyToString(node->getStyle().justifyContent)); } - if (style.alignItems() != YGNode().getStyle().alignItems()) { - appendFormattedString( - str, "align-items: %s; ", YGAlignToString(style.alignItems())); + if (node->getStyle().alignItems != YGNode().getStyle().alignItems) { + appendFormatedString( + str, + "align-items: %s; ", + YGAlignToString(node->getStyle().alignItems)); } - if (style.alignContent() != YGNode().getStyle().alignContent()) { - appendFormattedString( - str, "align-content: %s; ", YGAlignToString(style.alignContent())); + if (node->getStyle().alignContent != YGNode().getStyle().alignContent) { + appendFormatedString( + str, + "align-content: %s; ", + YGAlignToString(node->getStyle().alignContent)); } - if (style.alignSelf() != YGNode().getStyle().alignSelf()) { - appendFormattedString( - str, "align-self: %s; ", YGAlignToString(style.alignSelf())); + if (node->getStyle().alignSelf != YGNode().getStyle().alignSelf) { + appendFormatedString( + str, "align-self: %s; ", YGAlignToString(node->getStyle().alignSelf)); } - appendFloatOptionalIfDefined(str, "flex-grow", style.flexGrow()); - appendFloatOptionalIfDefined(str, "flex-shrink", style.flexShrink()); - appendNumberIfNotAuto(str, "flex-basis", style.flexBasis()); - appendFloatOptionalIfDefined(str, "flex", style.flex()); - - if (style.flexWrap() != YGNode().getStyle().flexWrap()) { - appendFormattedString( - str, "flex-wrap: %s; ", YGWrapToString(style.flexWrap())); + appendFloatIfNotUndefined(str, "flex-grow", node->getStyle().flexGrow); + appendFloatIfNotUndefined(str, "flex-shrink", node->getStyle().flexShrink); + appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis); + appendFloatIfNotUndefined(str, "flex", node->getStyle().flex); + + if (node->getStyle().flexWrap != YGNode().getStyle().flexWrap) { + appendFormatedString( + str, "flexWrap: %s; ", YGWrapToString(node->getStyle().flexWrap)); } - if (style.overflow() != YGNode().getStyle().overflow()) { - appendFormattedString( - str, "overflow: %s; ", YGOverflowToString(style.overflow())); + if (node->getStyle().overflow != YGNode().getStyle().overflow) { + appendFormatedString( + str, "overflow: %s; ", YGOverflowToString(node->getStyle().overflow)); } - if (style.display() != YGNode().getStyle().display()) { - appendFormattedString( - str, "display: %s; ", YGDisplayToString(style.display())); - } - appendEdges(str, "margin", style.margin()); - appendEdges(str, "padding", style.padding()); - appendEdges(str, "border", style.border()); - - if (YGNode::computeColumnGap( - style.gap(), detail::CompactValue::ofUndefined()) != - YGNode::computeColumnGap( - YGNode().getStyle().gap(), detail::CompactValue::ofUndefined())) { - appendNumberIfNotUndefined( - str, "column-gap", style.gap()[YGGutterColumn]); - } - if (YGNode::computeRowGap( - style.gap(), detail::CompactValue::ofUndefined()) != - YGNode::computeRowGap( - YGNode().getStyle().gap(), detail::CompactValue::ofUndefined())) { - appendNumberIfNotUndefined(str, "row-gap", style.gap()[YGGutterRow]); + 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", style.dimensions()[YGDimensionWidth]); - appendNumberIfNotAuto(str, "height", style.dimensions()[YGDimensionHeight]); appendNumberIfNotAuto( - str, "max-width", style.maxDimensions()[YGDimensionWidth]); + str, "width", node->getStyle().dimensions[YGDimensionWidth]); appendNumberIfNotAuto( - str, "max-height", style.maxDimensions()[YGDimensionHeight]); + str, "height", node->getStyle().dimensions[YGDimensionHeight]); appendNumberIfNotAuto( - str, "min-width", style.minDimensions()[YGDimensionWidth]); + str, "max-width", node->getStyle().maxDimensions[YGDimensionWidth]); appendNumberIfNotAuto( - str, "min-height", style.minDimensions()[YGDimensionHeight]); + str, "max-height", node->getStyle().maxDimensions[YGDimensionHeight]); + appendNumberIfNotAuto( + str, "min-width", node->getStyle().minDimensions[YGDimensionWidth]); + appendNumberIfNotAuto( + str, "min-height", node->getStyle().minDimensions[YGDimensionHeight]); - if (style.positionType() != YGNode().getStyle().positionType()) { - appendFormattedString( - str, "position: %s; ", YGPositionTypeToString(style.positionType())); + if (node->getStyle().positionType != YGNode().getStyle().positionType) { + appendFormatedString( + str, + "position: %s; ", + YGPositionTypeToString(node->getStyle().positionType)); } - appendEdgeIfNotUndefined(str, "left", style.position(), YGEdgeLeft); - appendEdgeIfNotUndefined(str, "right", style.position(), YGEdgeRight); - appendEdgeIfNotUndefined(str, "top", style.position(), YGEdgeTop); - appendEdgeIfNotUndefined(str, "bottom", style.position(), YGEdgeBottom); - appendFormattedString(str, "\" "); - - if (node->hasMeasureFunc()) { - appendFormattedString(str, "has-custom-measure=\"true\""); + 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\""); } } - appendFormattedString(str, ">"); + appendFormatedString(str, ">"); const uint32_t childCount = static_cast(node->getChildren().size()); if (options & YGPrintOptionsChildren && childCount > 0) { for (uint32_t i = 0; i < childCount; i++) { - appendFormattedString(str, "\n"); + appendFormatedString(str, "\n"); YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1); } - appendFormattedString(str, "\n"); + appendFormatedString(str, "\n"); indent(str, level); } - appendFormattedString(str, "
"); + appendFormatedString(str, ""); } } // namespace yoga } // namespace facebook -#endif diff --git a/Sources/yoga/YGNodePrint.h b/Sources/yoga/YGNodePrint.h index f06d457c..16259fcf 100644 --- a/Sources/yoga/YGNodePrint.h +++ b/Sources/yoga/YGNodePrint.h @@ -1,14 +1,10 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ - -#ifdef DEBUG - #pragma once - #include #include "Yoga.h" @@ -17,12 +13,10 @@ namespace facebook { namespace yoga { void YGNodeToString( - std::string& str, + std::string* str, YGNodeRef node, YGPrintOptions options, uint32_t level); } // namespace yoga } // namespace facebook - -#endif diff --git a/Sources/yoga/YGStyle.cpp b/Sources/yoga/YGStyle.cpp index 37153f2e..a73cb3ce 100644 --- a/Sources/yoga/YGStyle.cpp +++ b/Sources/yoga/YGStyle.cpp @@ -1,56 +1,99 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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 "YGStyle.h" -#include "Utils.h" + +const YGValue kYGValueUndefined = {YGUndefined, YGUnitUndefined}; + +const YGValue kYGValueAuto = {YGUndefined, YGUnitAuto}; + +const std::array kYGDefaultEdgeValuesUnit = { + {kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined, + kYGValueUndefined}}; + +const std::array kYGDefaultDimensionValuesAutoUnit = { + {kYGValueAuto, kYGValueAuto}}; + +const std::array 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(YGUndefined), + flexGrow(YGUndefined), + flexShrink(YGUndefined), + flexBasis(kYGValueAuto), + margin(kYGDefaultEdgeValuesUnit), + position(kYGDefaultEdgeValuesUnit), + padding(kYGDefaultEdgeValuesUnit), + border(kYGDefaultEdgeValuesUnit), + dimensions(kYGDefaultDimensionValuesAutoUnit), + minDimensions(kYGDefaultDimensionValuesUnit), + maxDimensions(kYGDefaultDimensionValuesUnit), + aspectRatio(YGUndefined) {} // Yoga specific properties, not compatible with flexbox specification -bool operator==(const YGStyle& lhs, const YGStyle& rhs) { - bool areNonFloatValuesEqual = lhs.direction() == rhs.direction() && - lhs.flexDirection() == rhs.flexDirection() && - lhs.justifyContent() == rhs.justifyContent() && - lhs.alignContent() == rhs.alignContent() && - lhs.alignItems() == rhs.alignItems() && - lhs.alignSelf() == rhs.alignSelf() && - lhs.positionType() == rhs.positionType() && - lhs.flexWrap() == rhs.flexWrap() && lhs.overflow() == rhs.overflow() && - lhs.display() == rhs.display() && - YGValueEqual(lhs.flexBasis(), rhs.flexBasis()) && - lhs.margin() == rhs.margin() && lhs.position() == rhs.position() && - lhs.padding() == rhs.padding() && lhs.border() == rhs.border() && - lhs.gap() == rhs.gap() && lhs.dimensions() == rhs.dimensions() && - lhs.minDimensions() == rhs.minDimensions() && - lhs.maxDimensions() == rhs.maxDimensions(); - - areNonFloatValuesEqual = areNonFloatValuesEqual && - lhs.flex().isUndefined() == rhs.flex().isUndefined(); - if (areNonFloatValuesEqual && !lhs.flex().isUndefined() && - !rhs.flex().isUndefined()) { - areNonFloatValuesEqual = areNonFloatValuesEqual && lhs.flex() == rhs.flex(); +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); + + if (!(std::isnan(flex) && std::isnan(style.flex))) { + areNonFloatValuesEqual = areNonFloatValuesEqual && flex == style.flex; } - areNonFloatValuesEqual = areNonFloatValuesEqual && - lhs.flexGrow().isUndefined() == rhs.flexGrow().isUndefined(); - if (areNonFloatValuesEqual && !lhs.flexGrow().isUndefined()) { + if (!(std::isnan(flexGrow) && std::isnan(style.flexGrow))) { areNonFloatValuesEqual = - areNonFloatValuesEqual && lhs.flexGrow() == rhs.flexGrow(); + areNonFloatValuesEqual && flexGrow == style.flexGrow; } - areNonFloatValuesEqual = areNonFloatValuesEqual && - lhs.flexShrink().isUndefined() == rhs.flexShrink().isUndefined(); - if (areNonFloatValuesEqual && !rhs.flexShrink().isUndefined()) { + if (!(std::isnan(flexShrink) && std::isnan(style.flexShrink))) { areNonFloatValuesEqual = - areNonFloatValuesEqual && lhs.flexShrink() == rhs.flexShrink(); + areNonFloatValuesEqual && flexShrink == style.flexShrink; } - if (!(lhs.aspectRatio().isUndefined() && rhs.aspectRatio().isUndefined())) { + if (!(std::isnan(aspectRatio) && std::isnan(style.aspectRatio))) { areNonFloatValuesEqual = - areNonFloatValuesEqual && lhs.aspectRatio() == rhs.aspectRatio(); + areNonFloatValuesEqual && aspectRatio == style.aspectRatio; } return areNonFloatValuesEqual; } + +bool YGStyle::operator!=(YGStyle style) { + return !(*this == style); +} + +YGStyle::~YGStyle() {} diff --git a/Sources/yoga/YGStyle.h b/Sources/yoga/YGStyle.h index 3a65573c..a95b4a29 100644 --- a/Sources/yoga/YGStyle.h +++ b/Sources/yoga/YGStyle.h @@ -1,237 +1,43 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. + * 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 -#include -#include - -#include "CompactValue.h" -#include "YGFloatOptional.h" -#include "Yoga.h" #include "Yoga-internal.h" -#include "BitUtils.h" - -class YOGA_EXPORT YGStyle { - template - using Values = - facebook::yoga::detail::Values()>; - using CompactValue = facebook::yoga::detail::CompactValue; - -public: - using Dimensions = Values; - using Edges = Values; - using Gutters = Values; - - template - struct BitfieldRef { - YGStyle& style; - size_t offset; - operator T() const { - return facebook::yoga::detail::getEnumData(style.flags, offset); - } - BitfieldRef& operator=(T x) { - facebook::yoga::detail::setEnumData(style.flags, offset, x); - return *this; - } - }; - - template - struct Ref { - YGStyle& style; - operator T() const { return style.*Prop; } - Ref& operator=(T value) { - style.*Prop = value; - return *this; - } - }; - - template YGStyle::*Prop> - struct IdxRef { - struct Ref { - YGStyle& style; - Idx idx; - operator CompactValue() const { return (style.*Prop)[idx]; } - operator YGValue() const { return (style.*Prop)[idx]; } - Ref& operator=(CompactValue value) { - (style.*Prop)[idx] = value; - return *this; - } - }; - - YGStyle& style; - IdxRef& operator=(const Values& values) { - style.*Prop = values; - return *this; - } - operator const Values&() const { return style.*Prop; } - Ref operator[](Idx idx) { return {style, idx}; } - CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; } - }; - - YGStyle() { - alignContent() = YGAlignFlexStart; - alignItems() = YGAlignStretch; - } - ~YGStyle() = default; - -private: - static constexpr size_t directionOffset = 0; - static constexpr size_t flexdirectionOffset = - directionOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t justifyContentOffset = flexdirectionOffset + - facebook::yoga::detail::bitWidthFn(); - static constexpr size_t alignContentOffset = - justifyContentOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t alignItemsOffset = - alignContentOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t alignSelfOffset = - alignItemsOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t positionTypeOffset = - alignSelfOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t flexWrapOffset = - positionTypeOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t overflowOffset = - flexWrapOffset + facebook::yoga::detail::bitWidthFn(); - static constexpr size_t displayOffset = - overflowOffset + facebook::yoga::detail::bitWidthFn(); - - uint32_t flags = 0; +#include "Yoga.h" - YGFloatOptional flex_ = {}; - YGFloatOptional flexGrow_ = {}; - YGFloatOptional flexShrink_ = {}; - CompactValue flexBasis_ = CompactValue::ofAuto(); - Edges margin_ = {}; - Edges position_ = {}; - Edges padding_ = {}; - Edges border_ = {}; - Gutters gap_ = {}; - Dimensions dimensions_{CompactValue::ofAuto()}; - Dimensions minDimensions_ = {}; - Dimensions maxDimensions_ = {}; +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; + std::array margin; + std::array position; + std::array padding; + std::array border; + std::array dimensions; + std::array minDimensions; + std::array maxDimensions; + float aspectRatio; + + YGStyle(); // Yoga specific properties, not compatible with flexbox specification - YGFloatOptional aspectRatio_ = {}; - -public: - // for library users needing a type - using ValueRepr = std::remove_reference::type; - - YGDirection direction() const { - return facebook::yoga::detail::getEnumData( - flags, directionOffset); - } - BitfieldRef direction() { return {*this, directionOffset}; } - - YGFlexDirection flexDirection() const { - return facebook::yoga::detail::getEnumData( - flags, flexdirectionOffset); - } - BitfieldRef flexDirection() { - return {*this, flexdirectionOffset}; - } - - YGJustify justifyContent() const { - return facebook::yoga::detail::getEnumData( - flags, justifyContentOffset); - } - BitfieldRef justifyContent() { - return {*this, justifyContentOffset}; - } - - YGAlign alignContent() const { - return facebook::yoga::detail::getEnumData( - flags, alignContentOffset); - } - BitfieldRef alignContent() { return {*this, alignContentOffset}; } - - YGAlign alignItems() const { - return facebook::yoga::detail::getEnumData( - flags, alignItemsOffset); - } - BitfieldRef alignItems() { return {*this, alignItemsOffset}; } + bool operator==(const YGStyle& style); - YGAlign alignSelf() const { - return facebook::yoga::detail::getEnumData(flags, alignSelfOffset); - } - BitfieldRef alignSelf() { return {*this, alignSelfOffset}; } - - YGPositionType positionType() const { - return facebook::yoga::detail::getEnumData( - flags, positionTypeOffset); - } - BitfieldRef positionType() { - return {*this, positionTypeOffset}; - } - - YGWrap flexWrap() const { - return facebook::yoga::detail::getEnumData(flags, flexWrapOffset); - } - BitfieldRef flexWrap() { return {*this, flexWrapOffset}; } - - YGOverflow overflow() const { - return facebook::yoga::detail::getEnumData( - flags, overflowOffset); - } - BitfieldRef overflow() { return {*this, overflowOffset}; } - - YGDisplay display() const { - return facebook::yoga::detail::getEnumData(flags, displayOffset); - } - BitfieldRef display() { return {*this, displayOffset}; } - - YGFloatOptional flex() const { return flex_; } - Ref flex() { return {*this}; } - - YGFloatOptional flexGrow() const { return flexGrow_; } - Ref flexGrow() { return {*this}; } - - YGFloatOptional flexShrink() const { return flexShrink_; } - Ref flexShrink() { return {*this}; } - - CompactValue flexBasis() const { return flexBasis_; } - Ref flexBasis() { return {*this}; } - - const Edges& margin() const { return margin_; } - IdxRef margin() { return {*this}; } - - const Edges& position() const { return position_; } - IdxRef position() { return {*this}; } - - const Edges& padding() const { return padding_; } - IdxRef padding() { return {*this}; } - - const Edges& border() const { return border_; } - IdxRef border() { return {*this}; } - - const Gutters& gap() const { return gap_; } - IdxRef gap() { return {*this}; } - - const Dimensions& dimensions() const { return dimensions_; } - IdxRef dimensions() { return {*this}; } - - const Dimensions& minDimensions() const { return minDimensions_; } - IdxRef minDimensions() { - return {*this}; - } - - const Dimensions& maxDimensions() const { return maxDimensions_; } - IdxRef maxDimensions() { - return {*this}; - } - - // Yoga specific properties, not compatible with flexbox specification - YGFloatOptional aspectRatio() const { return aspectRatio_; } - Ref aspectRatio() { return {*this}; } + bool operator!=(YGStyle style); + ~YGStyle(); }; - -YOGA_EXPORT bool operator==(const YGStyle& lhs, const YGStyle& rhs); -YOGA_EXPORT inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) { - return !(lhs == rhs); -} diff --git a/Sources/yoga/YGValue.cpp b/Sources/yoga/YGValue.cpp deleted file mode 100644 index 89ff41ba..00000000 --- a/Sources/yoga/YGValue.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "YGValue.h" - -const YGValue YGValueZero = {0, YGUnitPoint}; -const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; -const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; diff --git a/Sources/yoga/Yoga-internal.h b/Sources/yoga/Yoga-internal.h index 903975d5..21b14b23 100644 --- a/Sources/yoga/Yoga-internal.h +++ b/Sources/yoga/Yoga-internal.h @@ -1,59 +1,46 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * 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 #include #include #include - -#include "CompactValue.h" #include "Yoga.h" using YGVector = std::vector; YG_EXTERN_C_BEGIN -void YGNodeCalculateLayoutWithContext( - YGNodeRef node, - float availableWidth, - float availableHeight, - YGDirection ownerDirection, - void* layoutContext); - -// Deallocates a Yoga Node. Unlike YGNodeFree, does not remove the node from -// its parent or children. -void YGNodeDeallocate(YGNodeRef node); +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) { - return std::isnan(value); -} - -inline bool isUndefined(double value) { - return std::isnan(value); -} - -void throwLogicalErrorWithMessage(const char* message); - -} // namespace yoga -} // namespace facebook - extern const std::array trailing; extern const std::array leading; +extern bool YGValueEqual(const YGValue a, const YGValue b); extern const YGValue YGValueUndefined; extern const YGValue YGValueAuto; extern const YGValue YGValueZero; +template +bool YGValueArrayEqual( + const std::array val1, + const std::array 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; @@ -64,33 +51,30 @@ struct YGCachedMeasurement { float computedHeight; YGCachedMeasurement() - : availableWidth(-1), - availableHeight(-1), - widthMeasureMode(YGMeasureModeUndefined), - heightMeasureMode(YGMeasureModeUndefined), + : availableWidth(0), + availableHeight(0), + widthMeasureMode((YGMeasureMode)-1), + heightMeasureMode((YGMeasureMode)-1), computedWidth(-1), computedHeight(-1) {} bool operator==(YGCachedMeasurement measurement) const { - using namespace facebook; - bool isEqual = widthMeasureMode == measurement.widthMeasureMode && heightMeasureMode == measurement.heightMeasureMode; - if (!yoga::isUndefined(availableWidth) || - !yoga::isUndefined(measurement.availableWidth)) { + if (!std::isnan(availableWidth) || + !std::isnan(measurement.availableWidth)) { isEqual = isEqual && availableWidth == measurement.availableWidth; } - if (!yoga::isUndefined(availableHeight) || - !yoga::isUndefined(measurement.availableHeight)) { + if (!std::isnan(availableHeight) || + !std::isnan(measurement.availableHeight)) { isEqual = isEqual && availableHeight == measurement.availableHeight; } - if (!yoga::isUndefined(computedWidth) || - !yoga::isUndefined(measurement.computedWidth)) { + if (!std::isnan(computedWidth) || !std::isnan(measurement.computedWidth)) { isEqual = isEqual && computedWidth == measurement.computedWidth; } - if (!yoga::isUndefined(computedHeight) || - !yoga::isUndefined(measurement.computedHeight)) { + if (!std::isnan(computedHeight) || + !std::isnan(measurement.computedHeight)) { isEqual = isEqual && computedHeight == measurement.computedHeight; } @@ -98,62 +82,28 @@ struct YGCachedMeasurement { } }; -// This value was chosen based on empirical data: -// 98% of analyzed layouts require less than 8 entries. -#define YG_MAX_CACHED_RESULT_COUNT 8 - -namespace facebook { -namespace yoga { -namespace detail { - -template -class Values { -private: - std::array values_; - -public: - Values() = default; - Values(const Values& other) = default; - - explicit Values(const YGValue& defaultValue) noexcept { - values_.fill(defaultValue); - } - - const CompactValue& operator[](size_t i) const noexcept { return values_[i]; } - CompactValue& operator[](size_t i) noexcept { return values_[i]; } - - template - YGValue get() const noexcept { - return std::get(values_); - } - - template - void set(YGValue& value) noexcept { - std::get(values_) = value; - } - - template - void set(YGValue&& value) noexcept { - set(value); - } - - bool operator==(const Values& other) const noexcept { - for (size_t i = 0; i < Size; ++i) { - if (values_[i] != other.values_[i]) { - return false; - } - } - return true; - } - - Values& operator=(const Values& other) = default; +// 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 + +struct YGConfig { + bool experimentalFeatures[YGExperimentalFeatureCount + 1]; + bool useWebDefaults; + bool useLegacyStretchBehaviour; + bool shouldDiffLayoutWithoutLegacyStretchBehaviour; + float pointScaleFactor; + YGLogger logger; + YGNodeClonedFunc cloneNodeCallback; + void* context; }; -} // namespace detail -} // namespace yoga -} // namespace facebook 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& edges, + const YGEdge edge, + const YGValue* const defaultValue); diff --git a/Sources/yoga/Yoga.cpp b/Sources/yoga/Yoga.cpp index 3588fd0a..44324374 100644 --- a/Sources/yoga/Yoga.cpp +++ b/Sources/yoga/Yoga.cpp @@ -1,51 +1,72 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -#include +#include "Yoga.h" #include #include -#include -#include - -#include "log.h" #include "Utils.h" #include "YGNode.h" #include "YGNodePrint.h" -#include "Yoga.h" #include "Yoga-internal.h" -#include "event/event.h" -using namespace facebook::yoga; -using detail::Log; +#ifdef _MSC_VER +#include + +/* 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, + .shouldDiffLayoutWithoutLegacyStretchBehaviour = false, + .pointScaleFactor = 1.0f, #ifdef ANDROID -static int YGAndroidLog( - const YGConfigRef config, - const YGNodeRef node, - YGLogLevel level, - const char* format, - va_list args); + .logger = &YGAndroidLog, #else -static int YGDefaultLog( - const YGConfigRef config, - const YGNodeRef node, - YGLogLevel level, - const char* format, - va_list args); + .logger = &YGDefaultLog, #endif + .cloneNodeCallback = nullptr, + .context = nullptr, +}; + +const YGValue YGValueZero = {.value = 0, .unit = YGUnitPoint}; +const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; +const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; #ifdef ANDROID #include -static int YGAndroidLog( - const YGConfigRef /*config*/, - const YGNodeRef /*node*/, - YGLogLevel level, - const char* format, - va_list args) { +static int YGAndroidLog(const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + const char *format, + va_list args) { int androidLevel = YGLogLevelDebug; switch (level) { case YGLogLevelFatal: @@ -71,14 +92,13 @@ static int YGAndroidLog( return result; } #else -#define YG_UNUSED(x) (void) (x); +#define YG_UNUSED(x) (void)(x); -static int YGDefaultLog( - const YGConfigRef config, - const YGNodeRef node, - YGLogLevel level, - const char* format, - va_list args) { +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) { @@ -97,190 +117,259 @@ static int YGDefaultLog( #undef YG_UNUSED #endif -static inline bool YGDoubleIsUndefined(const double value) { - return facebook::yoga::isUndefined(value); +bool YGFloatIsUndefined(const float value) { + return std::isnan(value); } -YOGA_EXPORT bool YGFloatIsUndefined(const float value) { - return facebook::yoga::isUndefined(value); -} +const YGValue* YGComputedEdgeValue( + const std::array& edges, + const YGEdge edge, + const YGValue* const defaultValue) { + if (edges[edge].unit != YGUnitUndefined) { + return &edges[edge]; + } -YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node) { - return node->getContext(); -} + if ((edge == YGEdgeTop || edge == YGEdgeBottom) && + edges[YGEdgeVertical].unit != YGUnitUndefined) { + return &edges[YGEdgeVertical]; + } -YOGA_EXPORT void YGNodeSetContext(YGNodeRef node, void* context) { - return node->setContext(context); + 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; } -YOGA_EXPORT YGConfigRef YGNodeGetConfig(YGNodeRef node) { - return node->getConfig(); +void* YGNodeGetContext(YGNodeRef node) { + return node->getContext(); } -YOGA_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config) { - node->setConfig(config); +void YGNodeSetContext(YGNodeRef node, void* context) { + return node->setContext(context); } -YOGA_EXPORT bool YGNodeHasMeasureFunc(YGNodeRef node) { - return node->hasMeasureFunc(); +YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node) { + return node->getMeasure(); } -YOGA_EXPORT void YGNodeSetMeasureFunc( - YGNodeRef node, - YGMeasureFunc measureFunc) { +void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) { node->setMeasureFunc(measureFunc); } -YOGA_EXPORT bool YGNodeHasBaselineFunc(YGNodeRef node) { - return node->hasBaselineFunc(); +YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node) { + return node->getBaseline(); } -YOGA_EXPORT void YGNodeSetBaselineFunc( - YGNodeRef node, - YGBaselineFunc baselineFunc) { - node->setBaselineFunc(baselineFunc); +void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) { + node->setBaseLineFunc(baselineFunc); } -YOGA_EXPORT YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) { +YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) { return node->getDirtied(); } -YOGA_EXPORT void YGNodeSetDirtiedFunc( - YGNodeRef node, - YGDirtiedFunc dirtiedFunc) { +void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) { node->setDirtiedFunc(dirtiedFunc); } -YOGA_EXPORT void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) { - node->setPrintFunc(printFunc); +YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node) { + return node->getPrintFunc(); } -YOGA_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node) { - return node->getHasNewLayout(); +void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) { + node->setPrintFunc(printFunc); } -YOGA_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) { - config->setShouldPrintTree(enabled); +bool YGNodeGetHasNewLayout(YGNodeRef node) { + return node->getHasNewLayout(); } -YOGA_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { +void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { node->setHasNewLayout(hasNewLayout); } -YOGA_EXPORT YGNodeType YGNodeGetNodeType(YGNodeRef node) { +YGNodeType YGNodeGetNodeType(YGNodeRef node) { return node->getNodeType(); } -YOGA_EXPORT void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) { +void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) { return node->setNodeType(nodeType); } -YOGA_EXPORT bool YGNodeIsDirty(YGNodeRef node) { +bool YGNodeIsDirty(YGNodeRef node) { return node->isDirty(); } -YOGA_EXPORT void YGNodeMarkDirtyAndPropagateToDescendants( - const YGNodeRef node) { - return node->markDirtyAndPropagateDownwards(); +bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) { + return node->didUseLegacyFlag(); } +void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) { + return node->markDirtyAndPropogateDownwards(); +} + +int32_t gNodeInstanceCount = 0; int32_t gConfigInstanceCount = 0; -YOGA_EXPORT WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { - const YGNodeRef node = new YGNode{config}; - YGAssert(config != nullptr, "Tried to construct YGNode with null config"); +WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { + const YGNodeRef node = new YGNode(); YGAssertWithConfig( config, node != nullptr, "Could not allocate memory for node"); - Event::publish(node, {config}); + gNodeInstanceCount++; + if (config->useWebDefaults) { + node->setStyleFlexDirection(YGFlexDirectionRow); + node->setStyleAlignContent(YGAlignStretch); + } + node->setConfig(config); return node; } -YOGA_EXPORT YGConfigRef YGConfigGetDefault() { - static YGConfigRef defaultConfig = YGConfigNew(); - return defaultConfig; -} - -YOGA_EXPORT YGNodeRef YGNodeNew(void) { - return YGNodeNewWithConfig(YGConfigGetDefault()); +YGNodeRef YGNodeNew(void) { + return YGNodeNewWithConfig(&gYGConfigDefaults); } -YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) { +YGNodeRef YGNodeClone(YGNodeRef oldNode) { YGNodeRef node = new YGNode(*oldNode); YGAssertWithConfig( oldNode->getConfig(), node != nullptr, "Could not allocate memory for node"); - Event::publish(node, {node->getConfig()}); - node->setOwner(nullptr); + gNodeInstanceCount++; + node->setParent(nullptr); return node; } -YOGA_EXPORT void YGNodeFree(const YGNodeRef node) { - if (YGNodeRef owner = node->getOwner()) { - owner->removeChild(node); - node->setOwner(nullptr); +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->setParent(node); + vec.push_back(childNode); + } + node->setChildren(vec); + + if (oldNode->getConfig() != nullptr) { + node->setConfig(YGConfigClone(*(oldNode->getConfig()))); + } + + if (oldNode->getNextChild() != nullptr) { + node->setNextChild(YGNodeDeepClone(oldNode->getNextChild())); + } + + return node; +} + +void YGNodeFree(const YGNodeRef node) { + if (node->getParent()) { + node->getParent()->removeChild(node); + node->setParent(nullptr); } const uint32_t childCount = YGNodeGetChildCount(node); for (uint32_t i = 0; i < childCount; i++) { const YGNodeRef child = YGNodeGetChild(node, i); - child->setOwner(nullptr); + child->setParent(nullptr); } node->clearChildren(); - YGNodeDeallocate(node); + delete node; + gNodeInstanceCount--; } -YOGA_EXPORT void YGNodeDeallocate(const YGNodeRef node) { - Event::publish(node, {node->getConfig()}); - delete node; +static void YGConfigFreeRecursive(const YGNodeRef root) { + if (root->getConfig() != nullptr) { + gConfigInstanceCount--; + delete root->getConfig(); + } + // Delete configs recursively for childrens + for (uint32_t i = 0; i < root->getChildrenCount(); ++i) { + YGConfigFreeRecursive(root->getChild(i)); + } } -YOGA_EXPORT void YGNodeFreeRecursiveWithCleanupFunc( - const YGNodeRef root, - YGNodeCleanupFunc cleanup) { - uint32_t skipped = 0; - while (YGNodeGetChildCount(root) > skipped) { - const YGNodeRef child = YGNodeGetChild(root, skipped); - if (child->getOwner() != root) { +void YGNodeFreeRecursive(const YGNodeRef root) { + while (YGNodeGetChildCount(root) > 0) { + const YGNodeRef child = YGNodeGetChild(root, 0); + if (child->getParent() != root) { // Don't free shared nodes that we don't own. - skipped += 1; - } else { - YGNodeRemoveChild(root, child); - YGNodeFreeRecursive(child); + break; } - } - if (cleanup != nullptr) { - cleanup(root); + YGNodeRemoveChild(root, child); + YGNodeFreeRecursive(child); } YGNodeFree(root); } -YOGA_EXPORT void YGNodeFreeRecursive(const YGNodeRef root) { - return YGNodeFreeRecursiveWithCleanupFunc(root, nullptr); +void YGNodeReset(const YGNodeRef node) { + YGAssertWithNode(node, + YGNodeGetChildCount(node) == 0, + "Cannot reset a node which still has children attached"); + YGAssertWithNode( + node, + node->getParent() == nullptr, + "Cannot reset a node still attached to a parent"); + + node->clearChildren(); + + const YGConfigRef config = node->getConfig(); + *node = YGNode(); + if (config->useWebDefaults) { + node->setStyleFlexDirection(YGFlexDirectionRow); + node->setStyleAlignContent(YGAlignStretch); + } + node->setConfig(config); } -YOGA_EXPORT void YGNodeReset(YGNodeRef node) { - node->reset(); +int32_t YGNodeGetInstanceCount(void) { + return gNodeInstanceCount; } -YOGA_EXPORT int32_t YGConfigGetInstanceCount(void) { +int32_t YGConfigGetInstanceCount(void) { return gConfigInstanceCount; } -YOGA_EXPORT YGConfigRef YGConfigNew(void) { -#ifdef ANDROID - const YGConfigRef config = new YGConfig(YGAndroidLog); -#else - const YGConfigRef config = new YGConfig(YGDefaultLog); -#endif +// 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"); + if (config == nullptr) { + abort(); + } gConfigInstanceCount++; + memcpy(config, &gYGConfigDefaults, sizeof(YGConfig)); return config; } -YOGA_EXPORT void YGConfigFree(const YGConfigRef config) { - delete config; +void YGConfigFree(const YGConfigRef config) { + free(config); gConfigInstanceCount--; } @@ -288,697 +377,440 @@ void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) { memcpy(dest, src, sizeof(YGConfig)); } -YOGA_EXPORT void YGNodeSetIsReferenceBaseline( - YGNodeRef node, - bool isReferenceBaseline) { - if (node->isReferenceBaseline() != isReferenceBaseline) { - node->setIsReferenceBaseline(isReferenceBaseline); - node->markDirtyAndPropagate(); - } -} - -YOGA_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node) { - return node->isReferenceBaseline(); -} - -YOGA_EXPORT void YGNodeInsertChild( - const YGNodeRef owner, - const YGNodeRef child, - const uint32_t index) { +void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) { YGAssertWithNode( - owner, - child->getOwner() == nullptr, - "Child already has a owner, it must be removed first."); - + node, + child->getParent() == nullptr, + "Child already has a parent, it must be removed first."); YGAssertWithNode( - owner, - !owner->hasMeasureFunc(), + node, + node->getMeasure() == nullptr, "Cannot add child: Nodes with measure functions cannot have children."); - owner->insertChild(child, index); - child->setOwner(owner); - owner->markDirtyAndPropagate(); + node->cloneChildrenIfNeeded(); + node->insertChild(child, index); + child->setParent(node); + node->markDirtyAndPropogate(); } -YOGA_EXPORT void YGNodeSwapChild( - const YGNodeRef owner, - const YGNodeRef child, - const uint32_t index) { - owner->replaceChild(child, index); - child->setOwner(owner); -} +void YGNodeRemoveChild(const YGNodeRef parent, const YGNodeRef excludedChild) { + // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode + // that excludes a child. + const uint32_t childCount = YGNodeGetChildCount(parent); -YOGA_EXPORT void YGNodeRemoveChild( - const YGNodeRef owner, - const YGNodeRef excludedChild) { - if (YGNodeGetChildCount(owner) == 0) { + if (childCount == 0) { // This is an empty set. Nothing to remove. return; } - - // Children may be shared between parents, which is indicated by not having an - // owner. We only want to reset the child completely if it is owned - // exclusively by one node. - auto childOwner = excludedChild->getOwner(); - if (owner->removeChild(excludedChild)) { - if (owner == childOwner) { - excludedChild->setLayout({}); // layout is no longer valid - excludedChild->setOwner(nullptr); + const YGNodeRef firstChild = YGNodeGetChild(parent, 0); + if (firstChild->getParent() == 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 (parent->removeChild(excludedChild)) { + excludedChild->setLayout( + YGNode().getLayout()); // layout is no longer valid + excludedChild->setParent(nullptr); + parent->markDirtyAndPropogate(); } - owner->markDirtyAndPropagate(); + 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->getConfig()->cloneNodeCallback; + uint32_t nextInsertIndex = 0; + for (uint32_t i = 0; i < childCount; i++) { + const YGNodeRef oldChild = parent->getChild(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. + parent->markDirtyAndPropogate(); + continue; + } + const YGNodeRef newChild = YGNodeClone(oldChild); + parent->replaceChild(newChild, nextInsertIndex); + newChild->setParent(parent); + if (cloneNodeCallback) { + cloneNodeCallback(oldChild, newChild, parent, nextInsertIndex); + } + nextInsertIndex++; + } + while (nextInsertIndex < childCount) { + parent->removeChild(nextInsertIndex); + nextInsertIndex++; } } -YOGA_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef owner) { - const uint32_t childCount = YGNodeGetChildCount(owner); +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(owner, 0); - if (firstChild->getOwner() == owner) { - // If the first child has this node as its owner, we assume that this child - // set is unique. + const YGNodeRef firstChild = YGNodeGetChild(parent, 0); + if (firstChild->getParent() == 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(owner, i); + const YGNodeRef oldChild = YGNodeGetChild(parent, i); oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid - oldChild->setOwner(nullptr); + oldChild->setParent(nullptr); } - owner->clearChildren(); - owner->markDirtyAndPropagate(); + parent->clearChildren(); + parent->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->markDirtyAndPropagate(); -} - -YOGA_EXPORT void YGNodeSetChildren( - const YGNodeRef owner, - const YGNodeRef* children, - const uint32_t count) { - if (!owner) { - return; - } - - const YGVector childrenVector = {children, children + count}; - if (childrenVector.size() == 0) { - if (YGNodeGetChildCount(owner) > 0) { - for (YGNodeRef const child : owner->getChildren()) { - child->setLayout(YGLayout()); - child->setOwner(nullptr); - } - owner->setChildren(YGVector()); - owner->markDirtyAndPropagate(); - } - } 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(childrenVector.begin(), childrenVector.end(), oldChild) == - childrenVector.end()) { - oldChild->setLayout(YGLayout()); - oldChild->setOwner(nullptr); - } - } - } - owner->setChildren(childrenVector); - for (YGNodeRef child : childrenVector) { - child->setOwner(owner); - } - owner->markDirtyAndPropagate(); - } + // Otherwise, we are not the owner of the child set. We don't have to do anything to clear it. + parent->setChildren(YGVector()); + parent->markDirtyAndPropogate(); } -YOGA_EXPORT YGNodeRef -YGNodeGetChild(const YGNodeRef node, const uint32_t index) { +YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) { if (index < node->getChildren().size()) { return node->getChild(index); } return nullptr; } -YOGA_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node) { +uint32_t YGNodeGetChildCount(const YGNodeRef node) { return static_cast(node->getChildren().size()); } -YOGA_EXPORT YGNodeRef YGNodeGetOwner(const YGNodeRef node) { - return node->getOwner(); +YGNodeRef YGNodeGetParent(const YGNodeRef node) { + return node->getParent(); } -YOGA_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node) { - return node->getOwner(); -} - -YOGA_EXPORT void YGNodeMarkDirty(const YGNodeRef node) { +void YGNodeMarkDirty(const YGNodeRef node) { YGAssertWithNode( node, - node->hasMeasureFunc(), - "Only leaf nodes with custom measure functions " + node->getMeasure() != nullptr, + "Only leaf nodes with custom measure functions" "should manually mark themselves as dirty"); - node->markDirtyAndPropagate(); + node->markDirtyAndPropogate(); } -YOGA_EXPORT void YGNodeCopyStyle( - const YGNodeRef dstNode, - const YGNodeRef srcNode) { +void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) { if (!(dstNode->getStyle() == srcNode->getStyle())) { dstNode->setStyle(srcNode->getStyle()); - dstNode->markDirtyAndPropagate(); + dstNode->markDirtyAndPropogate(); } } -YOGA_EXPORT float YGNodeStyleGetFlexGrow(const YGNodeConstRef node) { - return node->getStyle().flexGrow().isUndefined() +float YGNodeStyleGetFlexGrow(const YGNodeRef node) { + return YGFloatIsUndefined(node->getStyle().flexGrow) ? kDefaultFlexGrow - : node->getStyle().flexGrow().unwrap(); -} - -YOGA_EXPORT float YGNodeStyleGetFlexShrink(const YGNodeConstRef node) { - return node->getStyle().flexShrink().isUndefined() - ? (node->getConfig()->useWebDefaults() ? kWebDefaultFlexShrink - : kDefaultFlexShrink) - : node->getStyle().flexShrink().unwrap(); -} - -namespace { - -template -void updateStyle( - YGNode* node, - T value, - NeedsUpdate&& needsUpdate, - Update&& update) { - if (needsUpdate(node->getStyle(), value)) { - update(node->getStyle(), value); - node->markDirtyAndPropagate(); - } -} - -template -void updateStyle(YGNode* node, Ref (YGStyle::*prop)(), T value) { - updateStyle( - node, - value, - [prop](YGStyle& s, T x) { return (s.*prop)() != x; }, - [prop](YGStyle& s, T x) { (s.*prop)() = x; }); -} - -template -void updateIndexedStyleProp( - YGNode* node, - Ref (YGStyle::*prop)(), - Idx idx, - detail::CompactValue value) { - using detail::CompactValue; - updateStyle( - node, - value, - [idx, prop](YGStyle& s, CompactValue x) { return (s.*prop)()[idx] != x; }, - [idx, prop](YGStyle& s, CompactValue x) { (s.*prop)()[idx] = x; }); -} - -} // namespace - -// MSVC has trouble inferring the return type of pointer to member functions -// with const and non-const overloads, instead of preferring the non-const -// overload like clang and GCC. For the purposes of updateStyle(), we can help -// MSVC by specifying that return type explicitly. In combination with -// decltype, MSVC will prefer the non-const version. -#define MSVC_HINT(PROP) decltype(YGStyle{}.PROP()) - -YOGA_EXPORT void YGNodeStyleSetDirection( - const YGNodeRef node, - const YGDirection value) { - updateStyle(node, &YGStyle::direction, value); -} -YOGA_EXPORT YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) { - return node->getStyle().direction(); -} - -YOGA_EXPORT void YGNodeStyleSetFlexDirection( - const YGNodeRef node, - const YGFlexDirection flexDirection) { - updateStyle( - node, &YGStyle::flexDirection, flexDirection); -} -YOGA_EXPORT YGFlexDirection -YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { - return node->getStyle().flexDirection(); -} - -YOGA_EXPORT void YGNodeStyleSetJustifyContent( - const YGNodeRef node, - const YGJustify justifyContent) { - updateStyle( - node, &YGStyle::justifyContent, justifyContent); -} -YOGA_EXPORT YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { - return node->getStyle().justifyContent(); -} - -YOGA_EXPORT void YGNodeStyleSetAlignContent( - const YGNodeRef node, - const YGAlign alignContent) { - updateStyle( - node, &YGStyle::alignContent, alignContent); -} -YOGA_EXPORT YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { - return node->getStyle().alignContent(); -} - -YOGA_EXPORT void YGNodeStyleSetAlignItems( - const YGNodeRef node, - const YGAlign alignItems) { - updateStyle(node, &YGStyle::alignItems, alignItems); -} -YOGA_EXPORT YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { - return node->getStyle().alignItems(); -} - -YOGA_EXPORT void YGNodeStyleSetAlignSelf( - const YGNodeRef node, - const YGAlign alignSelf) { - updateStyle(node, &YGStyle::alignSelf, alignSelf); -} -YOGA_EXPORT YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { - return node->getStyle().alignSelf(); -} - -YOGA_EXPORT void YGNodeStyleSetPositionType( - const YGNodeRef node, - const YGPositionType positionType) { - updateStyle( - node, &YGStyle::positionType, positionType); -} -YOGA_EXPORT YGPositionType -YGNodeStyleGetPositionType(const YGNodeConstRef node) { - return node->getStyle().positionType(); -} - -YOGA_EXPORT void YGNodeStyleSetFlexWrap( - const YGNodeRef node, - const YGWrap flexWrap) { - updateStyle(node, &YGStyle::flexWrap, flexWrap); -} -YOGA_EXPORT YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { - return node->getStyle().flexWrap(); -} - -YOGA_EXPORT void YGNodeStyleSetOverflow( - const YGNodeRef node, - const YGOverflow overflow) { - updateStyle(node, &YGStyle::overflow, overflow); -} -YOGA_EXPORT YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { - return node->getStyle().overflow(); -} - -YOGA_EXPORT void YGNodeStyleSetDisplay( - const YGNodeRef node, - const YGDisplay display) { - updateStyle(node, &YGStyle::display, display); -} -YOGA_EXPORT YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { - return node->getStyle().display(); -} - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { - updateStyle(node, &YGStyle::flex, YGFloatOptional{flex}); -} - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT float YGNodeStyleGetFlex(const YGNodeConstRef node) { - return node->getStyle().flex().isUndefined() - ? YGUndefined - : node->getStyle().flex().unwrap(); -} - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT void YGNodeStyleSetFlexGrow( - const YGNodeRef node, - const float flexGrow) { - updateStyle( - node, &YGStyle::flexGrow, YGFloatOptional{flexGrow}); -} - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT void YGNodeStyleSetFlexShrink( - const YGNodeRef node, - const float flexShrink) { - updateStyle( - node, &YGStyle::flexShrink, YGFloatOptional{flexShrink}); -} - -YOGA_EXPORT YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef 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; -} - -YOGA_EXPORT void YGNodeStyleSetFlexBasis( - const YGNodeRef node, - const float flexBasis) { - auto value = detail::CompactValue::ofMaybe(flexBasis); - updateStyle(node, &YGStyle::flexBasis, value); -} - -YOGA_EXPORT void YGNodeStyleSetFlexBasisPercent( - const YGNodeRef node, - const float flexBasisPercent) { - auto value = detail::CompactValue::ofMaybe(flexBasisPercent); - updateStyle(node, &YGStyle::flexBasis, value); -} - -YOGA_EXPORT void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { - updateStyle( - node, &YGStyle::flexBasis, detail::CompactValue::ofAuto()); -} - -YOGA_EXPORT void YGNodeStyleSetPosition( - YGNodeRef node, - YGEdge edge, - float points) { - auto value = detail::CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &YGStyle::position, edge, value); -} -YOGA_EXPORT void YGNodeStyleSetPositionPercent( - YGNodeRef node, - YGEdge edge, - float percent) { - auto value = detail::CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &YGStyle::position, edge, value); -} -YOGA_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) { - return node->getStyle().position()[edge]; -} - -YOGA_EXPORT void YGNodeStyleSetMargin( - YGNodeRef node, - YGEdge edge, - float points) { - auto value = detail::CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &YGStyle::margin, edge, value); -} -YOGA_EXPORT void YGNodeStyleSetMarginPercent( - YGNodeRef node, - YGEdge edge, - float percent) { - auto value = detail::CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &YGStyle::margin, edge, value); -} -YOGA_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { - updateIndexedStyleProp( - node, &YGStyle::margin, edge, detail::CompactValue::ofAuto()); -} -YOGA_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) { - return node->getStyle().margin()[edge]; -} - -YOGA_EXPORT void YGNodeStyleSetPadding( - YGNodeRef node, - YGEdge edge, - float points) { - auto value = detail::CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &YGStyle::padding, edge, value); -} -YOGA_EXPORT void YGNodeStyleSetPaddingPercent( - YGNodeRef node, - YGEdge edge, - float percent) { - auto value = detail::CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &YGStyle::padding, edge, value); -} -YOGA_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { - return node->getStyle().padding()[edge]; -} - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT void YGNodeStyleSetBorder( - const YGNodeRef node, - const YGEdge edge, - const float border) { - auto value = detail::CompactValue::ofMaybe(border); - updateIndexedStyleProp( - node, &YGStyle::border, edge, value); -} - -YOGA_EXPORT float YGNodeStyleGetBorder( - const YGNodeConstRef node, - const YGEdge edge) { - auto border = node->getStyle().border()[edge]; - if (border.isUndefined() || border.isAuto()) { - // TODO(T26792433): Rather than returning YGUndefined, change the api to - // return YGFloatOptional. - return YGUndefined; - } - - return static_cast(border).value; -} - -YOGA_EXPORT void YGNodeStyleSetGap( - const YGNodeRef node, - const YGGutter gutter, - const float gapLength) { - auto length = detail::CompactValue::ofMaybe(gapLength); - updateIndexedStyleProp(node, &YGStyle::gap, gutter, length); -} - -YOGA_EXPORT float YGNodeStyleGetGap( - const YGNodeConstRef node, - const YGGutter gutter) { - auto gapLength = node->getStyle().gap()[gutter]; - if (gapLength.isUndefined() || gapLength.isAuto()) { - // TODO(T26792433): Rather than returning YGUndefined, change the api to - // return YGFloatOptional. - return YGUndefined; - } - - return static_cast(gapLength).value; -} - -// Yoga specific properties, not compatible with flexbox specification - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { - const YGFloatOptional op = node->getStyle().aspectRatio(); - return op.isUndefined() ? YGUndefined : op.unwrap(); -} - -// TODO(T26792433): Change the API to accept YGFloatOptional. -YOGA_EXPORT void YGNodeStyleSetAspectRatio( - const YGNodeRef node, - const float aspectRatio) { - updateStyle( - node, &YGStyle::aspectRatio, YGFloatOptional{aspectRatio}); -} - -YOGA_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float points) { - auto value = detail::CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &YGStyle::dimensions, YGDimensionWidth, value); -} -YOGA_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { - auto value = detail::CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &YGStyle::dimensions, YGDimensionWidth, value); -} -YOGA_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node) { - updateIndexedStyleProp( - node, - &YGStyle::dimensions, - YGDimensionWidth, - detail::CompactValue::ofAuto()); -} -YOGA_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { - return node->getStyle().dimensions()[YGDimensionWidth]; -} - -YOGA_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float points) { - auto value = detail::CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &YGStyle::dimensions, YGDimensionHeight, value); -} -YOGA_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { - auto value = detail::CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &YGStyle::dimensions, YGDimensionHeight, value); -} -YOGA_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node) { - updateIndexedStyleProp( - node, - &YGStyle::dimensions, - YGDimensionHeight, - detail::CompactValue::ofAuto()); -} -YOGA_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { - return node->getStyle().dimensions()[YGDimensionHeight]; -} - -YOGA_EXPORT void YGNodeStyleSetMinWidth( - const YGNodeRef node, - const float minWidth) { - auto value = detail::CompactValue::ofMaybe(minWidth); - updateIndexedStyleProp( - node, &YGStyle::minDimensions, YGDimensionWidth, value); -} -YOGA_EXPORT void YGNodeStyleSetMinWidthPercent( - const YGNodeRef node, - const float minWidth) { - auto value = detail::CompactValue::ofMaybe(minWidth); - updateIndexedStyleProp( - node, &YGStyle::minDimensions, YGDimensionWidth, value); -} -YOGA_EXPORT YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { - return node->getStyle().minDimensions()[YGDimensionWidth]; -} - -YOGA_EXPORT void YGNodeStyleSetMinHeight( - const YGNodeRef node, - const float minHeight) { - auto value = detail::CompactValue::ofMaybe(minHeight); - updateIndexedStyleProp( - node, &YGStyle::minDimensions, YGDimensionHeight, value); -} -YOGA_EXPORT void YGNodeStyleSetMinHeightPercent( - const YGNodeRef node, - const float minHeight) { - auto value = detail::CompactValue::ofMaybe(minHeight); - updateIndexedStyleProp( - node, &YGStyle::minDimensions, YGDimensionHeight, value); -} -YOGA_EXPORT YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { - return node->getStyle().minDimensions()[YGDimensionHeight]; -} - -YOGA_EXPORT void YGNodeStyleSetMaxWidth( - const YGNodeRef node, - const float maxWidth) { - auto value = detail::CompactValue::ofMaybe(maxWidth); - updateIndexedStyleProp( - node, &YGStyle::maxDimensions, YGDimensionWidth, value); -} -YOGA_EXPORT void YGNodeStyleSetMaxWidthPercent( - const YGNodeRef node, - const float maxWidth) { - auto value = detail::CompactValue::ofMaybe(maxWidth); - updateIndexedStyleProp( - node, &YGStyle::maxDimensions, YGDimensionWidth, value); -} -YOGA_EXPORT YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { - return node->getStyle().maxDimensions()[YGDimensionWidth]; -} - -YOGA_EXPORT void YGNodeStyleSetMaxHeight( - const YGNodeRef node, - const float maxHeight) { - auto value = detail::CompactValue::ofMaybe(maxHeight); - updateIndexedStyleProp( - node, &YGStyle::maxDimensions, YGDimensionHeight, value); -} -YOGA_EXPORT void YGNodeStyleSetMaxHeightPercent( - const YGNodeRef node, - const float maxHeight) { - auto value = detail::CompactValue::ofMaybe(maxHeight); - updateIndexedStyleProp( - node, &YGStyle::maxDimensions, YGDimensionHeight, value); -} -YOGA_EXPORT YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { - return node->getStyle().maxDimensions()[YGDimensionHeight]; -} - -#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \ - YOGA_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node) { \ - return node->getLayout().instanceName; \ + : node->getStyle().flexGrow; +} + +float YGNodeStyleGetFlexShrink(const YGNodeRef node) { + return YGFloatIsUndefined(node->getStyle().flexShrink) + ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink + : kDefaultFlexShrink) + : node->getStyle().flexShrink; +} + +#define YG_NODE_STYLE_PROPERTY_SETTER_IMPL( \ + type, name, paramName, instanceName) \ + void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ + if (node->getStyle().instanceName != paramName) { \ + YGStyle style = node->getStyle(); \ + style.instanceName = paramName; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } + +#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->getStyle().instanceName.value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName.unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent( \ + const YGNodeRef node, const type paramName) { \ + YGValue value = { \ + .value = paramName, \ + .unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ + }; \ + if ((node->getStyle().instanceName.value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName.unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + \ + style.instanceName = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } + +#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->getStyle().instanceName.value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName.unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent( \ + const YGNodeRef node, const type paramName) { \ + if (node->getStyle().instanceName.value != paramName || \ + node->getStyle().instanceName.unit != YGUnitPercent) { \ + YGStyle style = node->getStyle(); \ + style.instanceName.value = paramName; \ + style.instanceName.unit = \ + YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \ + if (node->getStyle().instanceName.unit != YGUnitAuto) { \ + YGStyle style = node->getStyle(); \ + style.instanceName.value = YGUndefined; \ + style.instanceName.unit = YGUnitAuto; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } + +#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->getStyle().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->getStyle().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->getStyle().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->getStyle().instanceName[edge].unit != YGUnitAuto) { \ + YGStyle style = node->getStyle(); \ + style.instanceName[edge].value = YGUndefined; \ + style.instanceName[edge].unit = YGUnitAuto; \ + node->setStyle(style); \ + 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 = { \ + .value = paramName, \ + .unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \ + }; \ + if ((node->getStyle().instanceName[edge].value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName[edge].unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName[edge] = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent( \ + const YGNodeRef node, const YGEdge edge, const float paramName) { \ + YGValue value = { \ + .value = paramName, \ + .unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \ + }; \ + if ((node->getStyle().instanceName[edge].value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName[edge].unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName[edge] = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + WIN_STRUCT(type) \ + YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ + return WIN_STRUCT_REF(node->getStyle().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->getStyle().instanceName[edge].value != value.value && \ + value.unit != YGUnitUndefined) || \ + node->getStyle().instanceName[edge].unit != value.unit) { \ + YGStyle style = node->getStyle(); \ + style.instanceName[edge] = value; \ + node->setStyle(style); \ + node->markDirtyAndPropogate(); \ + } \ + } \ + \ + float YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ + return node->getStyle().instanceName[edge].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) \ - YOGA_EXPORT type YGNodeLayoutGet##name( \ - const YGNodeRef node, const YGEdge edge) { \ + type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \ YGAssertWithNode( \ node, \ edge <= YGEdgeEnd, \ "Cannot get layout properties of multi-edge shorthands"); \ \ - if (edge == YGEdgeStart) { \ - if (node->getLayout().direction() == YGDirectionRTL) { \ - return node->getLayout().instanceName[YGEdgeRight]; \ + if (edge == YGEdgeLeft) { \ + if (node->getLayout().direction == YGDirectionRTL) { \ + return node->getLayout().instanceName[YGEdgeEnd]; \ } else { \ - return node->getLayout().instanceName[YGEdgeLeft]; \ + return node->getLayout().instanceName[YGEdgeStart]; \ } \ } \ \ - if (edge == YGEdgeEnd) { \ - if (node->getLayout().direction() == YGDirectionRTL) { \ - return node->getLayout().instanceName[YGEdgeLeft]; \ + if (edge == YGEdgeRight) { \ + if (node->getLayout().direction == YGDirectionRTL) { \ + return node->getLayout().instanceName[YGEdgeStart]; \ } else { \ - return node->getLayout().instanceName[YGEdgeRight]; \ + return node->getLayout().instanceName[YGEdgeEnd]; \ } \ } \ \ return node->getLayout().instanceName[edge]; \ } -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_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]); -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) +// Yoga specific properties, not compatible with flexbox specification +YG_NODE_STYLE_PROPERTY_IMPL(float, AspectRatio, aspectRatio, aspectRatio); -std::atomic gCurrentGenerationCount(0); +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); -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 LayoutPassReason reason, - const YGConfigRef config, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount); +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); -#ifdef DEBUG -static void YGNodePrintInternal( - const YGNodeRef node, - const YGPrintOptions options) { +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 YGFloatsEqualWithPrecision(const float a, const float b, const float precision) { + assert(precision > 0); + + if (YGFloatIsUndefined(a)) { + return YGFloatIsUndefined(b); + } + return fabs(a - b) < precision; +} + +bool YGFloatsEqual(const float a, const float b) { + return YGFloatsEqualWithPrecision(a, b, 0.0001f); +} + +static void YGNodePrintInternal(const YGNodeRef node, + const YGPrintOptions options) { std::string str; - facebook::yoga::YGNodeToString(str, node, options, 0); - Log::log(node, YGLogLevelDebug, nullptr, str.c_str()); + facebook::yoga::YGNodeToString(&str, node, options, 0); + YGLog(node, YGLogLevelDebug, str.c_str()); } -YOGA_EXPORT void YGNodePrint( - const YGNodeRef node, - const YGPrintOptions options) { +void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) { YGNodePrintInternal(node, options); } -#endif const std::array leading = { {YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}}; @@ -995,42 +827,33 @@ static const std::array pos = {{ static const std::array dim = { {YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}}; -static inline float YGNodePaddingAndBorderForAxis( - const YGNodeConstRef node, - const YGFlexDirection axis, - const float widthSize) { - return (node->getLeadingPaddingAndBorder(axis, widthSize) + - node->getTrailingPaddingAndBorder(axis, widthSize)) - .unwrap(); +static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + return node->getLeadingPaddingAndBorder(axis, widthSize) + + node->getTrailingPaddingAndBorder(axis, widthSize); } -static inline YGAlign YGNodeAlignItem(const YGNode* node, const YGNode* child) { - const YGAlign align = child->getStyle().alignSelf() == YGAlignAuto - ? node->getStyle().alignItems() - : child->getStyle().alignSelf(); +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())) { + YGFlexDirectionIsColumn(node->getStyle().flexDirection)) { return YGAlignFlexStart; } return align; } -static float YGBaseline(const YGNodeRef node, void* layoutContext) { - if (node->hasBaselineFunc()) { - - Event::publish(node); - - const float baseline = node->baseline( - node->getLayout().measuredDimensions[YGDimensionWidth], - node->getLayout().measuredDimensions[YGDimensionHeight], - layoutContext); - - Event::publish(node); - - YGAssertWithNode( +static float YGBaseline(const YGNodeRef node) { + if (node->getBaseline() != nullptr) { + const float baseline = node->getBaseline()( node, - !YGFloatIsUndefined(baseline), - "Expect custom baseline function to not return NaN"); + node->getLayout().measuredDimensions[YGDimensionWidth], + node->getLayout().measuredDimensions[YGDimensionHeight]); + YGAssertWithNode(node, + !YGFloatIsUndefined(baseline), + "Expect custom baseline function to not return NaN"); return baseline; } @@ -1041,11 +864,10 @@ static float YGBaseline(const YGNodeRef node, void* layoutContext) { if (child->getLineIndex() > 0) { break; } - if (child->getStyle().positionType() == YGPositionTypeAbsolute) { + if (child->getStyle().positionType == YGPositionTypeAbsolute) { continue; } - if (YGNodeAlignItem(node, child) == YGAlignBaseline || - child->isReferenceBaseline()) { + if (YGNodeAlignItem(node, child) == YGAlignBaseline) { baselineChild = child; break; } @@ -1059,22 +881,22 @@ static float YGBaseline(const YGNodeRef node, void* layoutContext) { return node->getLayout().measuredDimensions[YGDimensionHeight]; } - const float baseline = YGBaseline(baselineChild, layoutContext); + const float baseline = YGBaseline(baselineChild); return baseline + baselineChild->getLayout().position[YGEdgeTop]; } static bool YGIsBaselineLayout(const YGNodeRef node) { - if (YGFlexDirectionIsColumn(node->getStyle().flexDirection())) { + if (YGFlexDirectionIsColumn(node->getStyle().flexDirection)) { return false; } - if (node->getStyle().alignItems() == YGAlignBaseline) { + 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() != YGPositionTypeAbsolute && - child->getStyle().alignSelf() == YGAlignBaseline) { + if (child->getStyle().positionType == YGPositionTypeRelative && + child->getStyle().alignSelf == YGAlignBaseline) { return true; } } @@ -1082,90 +904,79 @@ static bool YGIsBaselineLayout(const YGNodeRef node) { return false; } -static inline float YGNodeDimWithMargin( - const YGNodeRef node, - const YGFlexDirection axis, - const float widthSize) { +static inline float YGNodeDimWithMargin(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { return node->getLayout().measuredDimensions[dim[axis]] + - (node->getLeadingMargin(axis, widthSize) + - node->getTrailingMargin(axis, widthSize)) - .unwrap(); + 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); +static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node, + const YGFlexDirection axis, + const float parentSize) { 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]).value < 0.0f) || (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent && - !isUndefined && (node->getResolvedDimension(dim[axis]).value < 0.0f || - YGFloatIsUndefined(ownerSize)))); + YGFloatIsUndefined(parentSize)))); } -static inline bool YGNodeIsLayoutDimDefined( - const YGNodeRef node, - const YGFlexDirection axis) { +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 YGNodeConstRef node, - const YGFlexDirection axis, - const YGFloatOptional value, - const float axisSize) { - YGFloatOptional min; - YGFloatOptional max; +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->getStyle().minDimensions()[YGDimensionHeight], axisSize); + node->getStyle().minDimensions[YGDimensionHeight], axisSize); max = YGResolveValue( - node->getStyle().maxDimensions()[YGDimensionHeight], axisSize); + node->getStyle().maxDimensions[YGDimensionHeight], axisSize); } else if (YGFlexDirectionIsRow(axis)) { min = YGResolveValue( - node->getStyle().minDimensions()[YGDimensionWidth], axisSize); + node->getStyle().minDimensions[YGDimensionWidth], axisSize); max = YGResolveValue( - node->getStyle().maxDimensions()[YGDimensionWidth], axisSize); + node->getStyle().maxDimensions[YGDimensionWidth], axisSize); } - if (max >= YGFloatOptional{0} && value > max) { - return max; + float boundValue = value; + + if (!YGFloatIsUndefined(max) && max >= 0.0f && boundValue > max) { + boundValue = max; } - if (min >= YGFloatOptional{0} && value < min) { - return min; + if (!YGFloatIsUndefined(min) && min >= 0.0f && boundValue < min) { + boundValue = min; } - return value; + return boundValue; } -// 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( - YGNodeBoundAxisWithinMinAndMax( - node, axis, YGFloatOptional{value}, axisSize) - .unwrap(), - YGNodePaddingAndBorderForAxis(node, axis, widthSize)); +// 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) { +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 - @@ -1173,246 +984,206 @@ static void YGNodeSetChildTrailingPosition( trailing[axis]); } -static void YGConstrainMaxSizeForMode( - const YGNodeConstRef node, - const enum YGFlexDirection axis, - const float ownerAxisSize, - const float ownerWidth, - YGMeasureMode* mode, - float* size) { - const YGFloatOptional maxSize = +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->getStyle().maxDimensions()[dim[axis]], ownerAxisSize) + - YGFloatOptional(node->getMarginForAxis(axis, ownerWidth)); + node->getStyle().maxDimensions[dim[axis]], parentAxisSize) + + node->getMarginForAxis(axis, parentWidth); switch (*mode) { case YGMeasureModeExactly: case YGMeasureModeAtMost: - *size = (maxSize.isUndefined() || *size < maxSize.unwrap()) - ? *size - : maxSize.unwrap(); + *size = (YGFloatIsUndefined(maxSize) || *size < maxSize) ? *size : maxSize; break; case YGMeasureModeUndefined: - if (!maxSize.isUndefined()) { + if (!YGFloatIsUndefined(maxSize)) { *mode = YGMeasureModeAtMost; - *size = maxSize.unwrap(); + *size = maxSize; } 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, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount) { +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->getStyle().flexDirection(), direction); + YGResolveFlexDirection(node->getStyle().flexDirection, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); const float mainAxisSize = isMainAxisRow ? width : height; - const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; + const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; float childWidth; float childHeight; YGMeasureMode childWidthMeasureMode; YGMeasureMode childHeightMeasureMode; - const YGFloatOptional resolvedFlexBasis = - YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize); - const bool isRowStyleDimDefined = - YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth); + const float resolvedFlexBasis = + YGResolveValue(child->resolveFlexBasisPtr(), mainAxisParentSize); + const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, parentWidth); const bool isColumnStyleDimDefined = - YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight); - - if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) { - if (child->getLayout().computedFlexBasis.isUndefined() || - (child->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureWebFlexBasis) && - child->getLayout().computedFlexBasisGeneration != generationCount)) { - const YGFloatOptional paddingAndBorder = YGFloatOptional( - YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); - child->setLayoutComputedFlexBasis( - YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder)); + YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, parentHeight); + + if (!YGFloatIsUndefined(resolvedFlexBasis) && !YGFloatIsUndefined(mainAxisSize)) { + if (YGFloatIsUndefined(child->getLayout().computedFlexBasis) || + (YGConfigIsExperimentalFeatureEnabled( + child->getConfig(), YGExperimentalFeatureWebFlexBasis) && + child->getLayout().computedFlexBasisGeneration != + gCurrentGenerationCount)) { + child->setLayoutComputedFlexBasis(fmaxf( + resolvedFlexBasis, + YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth))); } } 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( + child->setLayoutComputedFlexBasis(fmaxf( YGResolveValue( - child->getResolvedDimensions()[YGDimensionWidth], ownerWidth), - paddingAndBorder)); + child->getResolvedDimension(YGDimensionWidth), parentWidth), + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth))); } 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( + child->setLayoutComputedFlexBasis(fmaxf( YGResolveValue( - child->getResolvedDimensions()[YGDimensionHeight], ownerHeight), - paddingAndBorder)); + child->getResolvedDimension(YGDimensionHeight), parentHeight), + YGNodePaddingAndBorderForAxis( + child, YGFlexDirectionColumn, parentWidth))); } else { - // Compute the flex basis and hypothetical main size (i.e. the clamped flex - // basis). + // Compute the flex basis and hypothetical main size (i.e. the clamped + // flex basis). childWidth = YGUndefined; childHeight = YGUndefined; childWidthMeasureMode = YGMeasureModeUndefined; childHeightMeasureMode = YGMeasureModeUndefined; - auto marginRow = - child->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap(); - auto marginColumn = - child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap(); + const float marginRow = + child->getMarginForAxis(YGFlexDirectionRow, parentWidth); + const float marginColumn = + child->getMarginForAxis(YGFlexDirectionColumn, parentWidth); if (isRowStyleDimDefined) { childWidth = YGResolveValue( - child->getResolvedDimensions()[YGDimensionWidth], ownerWidth) - .unwrap() + + child->getResolvedDimension(YGDimensionWidth), parentWidth) + marginRow; childWidthMeasureMode = YGMeasureModeExactly; } if (isColumnStyleDimDefined) { childHeight = YGResolveValue( - child->getResolvedDimensions()[YGDimensionHeight], ownerHeight) - .unwrap() + + child->getResolvedDimension(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->getStyle().overflow() == YGOverflowScroll) || - node->getStyle().overflow() != YGOverflowScroll) { + // 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 ((isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) || + node->getStyle().overflow != YGOverflowScroll) { if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) { childHeight = height; childHeightMeasureMode = YGMeasureModeAtMost; } } - const auto& childStyle = child->getStyle(); - if (!childStyle.aspectRatio().isUndefined()) { + if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) { childHeight = marginColumn + - (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); + (childWidth - marginRow) / child->getStyle().aspectRatio; childHeightMeasureMode = YGMeasureModeExactly; - } else if ( - isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { + } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { childWidth = marginRow + - (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); + (childHeight - marginColumn) * child->getStyle().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 + // 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) { + 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 (!childStyle.aspectRatio().isUndefined()) { - childHeight = - (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); + if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { + childHeight = (childWidth - marginRow) / child->getStyle().aspectRatio; childHeightMeasureMode = YGMeasureModeExactly; } } - const bool hasExactHeight = - !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly; - const bool childHeightStretch = - YGNodeAlignItem(node, child) == YGAlignStretch && - childHeightMeasureMode != YGMeasureModeExactly; - if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && - childHeightStretch) { + 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 (!childStyle.aspectRatio().isUndefined()) { + if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { childWidth = - (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); + (childHeight - marginColumn) * child->getStyle().aspectRatio; childWidthMeasureMode = YGMeasureModeExactly; } } YGConstrainMaxSizeForMode( - child, - YGFlexDirectionRow, - ownerWidth, - ownerWidth, - &childWidthMeasureMode, - &childWidth); - YGConstrainMaxSizeForMode( - child, - YGFlexDirectionColumn, - ownerHeight, - ownerWidth, - &childHeightMeasureMode, - &childHeight); + child, YGFlexDirectionRow, parentWidth, parentWidth, &childWidthMeasureMode, &childWidth); + YGConstrainMaxSizeForMode(child, + YGFlexDirectionColumn, + parentHeight, + parentWidth, + &childHeightMeasureMode, + &childHeight); // Measure the child - YGLayoutNodeInternal( - child, - childWidth, - childHeight, - direction, - childWidthMeasureMode, - childHeightMeasureMode, - ownerWidth, - ownerHeight, - false, - LayoutPassReason::kMeasureChild, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); - - child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax( + YGLayoutNodeInternal(child, + childWidth, + childHeight, + direction, + childWidthMeasureMode, + childHeightMeasureMode, + parentWidth, + parentHeight, + false, + "measure", + config); + + child->setLayoutComputedFlexBasis(fmaxf( child->getLayout().measuredDimensions[dim[mainAxis]], - YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)))); + YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth))); } - child->setLayoutComputedFlexBasisGeneration(generationCount); + 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, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount) { +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); + YGResolveFlexDirection(node->getStyle().flexDirection, direction); const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); @@ -1421,126 +1192,106 @@ static void YGNodeAbsoluteLayoutChild( YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined; YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined; - auto marginRow = child->getMarginForAxis(YGFlexDirectionRow, width).unwrap(); - auto marginColumn = - child->getMarginForAxis(YGFlexDirectionColumn, width).unwrap(); + const float marginRow = child->getMarginForAxis(YGFlexDirectionRow, width); + const float marginColumn = + child->getMarginForAxis(YGFlexDirectionColumn, width); if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) { childWidth = - YGResolveValue(child->getResolvedDimensions()[YGDimensionWidth], width) - .unwrap() + + 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 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)) - (child->getLeadingPosition(YGFlexDirectionRow, width) + - child->getTrailingPosition(YGFlexDirectionRow, width)) - .unwrap(); - childWidth = - YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width); + child->getTrailingPosition(YGFlexDirectionRow, width)); + childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width); } } if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) { - childHeight = YGResolveValue( - child->getResolvedDimensions()[YGDimensionHeight], height) - .unwrap() + + childHeight = + 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 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)) - (child->getLeadingPosition(YGFlexDirectionColumn, height) + - child->getTrailingPosition(YGFlexDirectionColumn, height)) - .unwrap(); - childHeight = YGNodeBoundAxis( - child, YGFlexDirectionColumn, childHeight, height, width); + 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. - const auto& childStyle = child->getStyle(); + // 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 (!childStyle.aspectRatio().isUndefined()) { + if (!YGFloatIsUndefined(child->getStyle().aspectRatio)) { if (YGFloatIsUndefined(childWidth)) { childWidth = marginRow + - (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); + (childHeight - marginColumn) * child->getStyle().aspectRatio; } else if (YGFloatIsUndefined(childHeight)) { childHeight = marginColumn + - (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); + (childWidth - marginRow) / child->getStyle().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 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) && + 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, - LayoutPassReason::kAbsMeasureChild, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + YGLayoutNodeInternal(child, + childWidth, + childHeight, + direction, + childWidthMeasureMode, + childHeightMeasureMode, + childWidth, + childHeight, + false, + "abs-measure", + config); childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] + - child->getMarginForAxis(YGFlexDirectionRow, width).unwrap(); + child->getMarginForAxis(YGFlexDirectionRow, width); childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] + - child->getMarginForAxis(YGFlexDirectionColumn, width).unwrap(); + child->getMarginForAxis(YGFlexDirectionColumn, width); } - YGLayoutNodeInternal( - child, - childWidth, - childHeight, - direction, - YGMeasureModeExactly, - YGMeasureModeExactly, - childWidth, - childHeight, - true, - LayoutPassReason::kAbsLayout, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + YGLayoutNodeInternal(child, + childWidth, + childHeight, + direction, + YGMeasureModeExactly, + YGMeasureModeExactly, + childWidth, + childHeight, + true, + "abs-layout", + config); if (child->isTrailingPosDefined(mainAxis) && !child->isLeadingPositionDefined(mainAxis)) { @@ -1548,14 +1299,13 @@ static void YGNodeAbsoluteLayoutChild( node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]] - node->getTrailingBorder(mainAxis) - - child->getTrailingMargin(mainAxis, isMainAxisRow ? width : height) - .unwrap() - - child->getTrailingPosition(mainAxis, isMainAxisRow ? width : height) - .unwrap(), + child->getTrailingMargin(mainAxis, width) - + child->getTrailingPosition( + mainAxis, isMainAxisRow ? width : height), leading[mainAxis]); } else if ( !child->isLeadingPositionDefined(mainAxis) && - node->getStyle().justifyContent() == YGJustifyCenter) { + node->getStyle().justifyContent == YGJustifyCenter) { child->setLayoutPosition( (node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]]) / @@ -1563,26 +1313,11 @@ static void YGNodeAbsoluteLayoutChild( leading[mainAxis]); } else if ( !child->isLeadingPositionDefined(mainAxis) && - node->getStyle().justifyContent() == YGJustifyFlexEnd) { + node->getStyle().justifyContent == YGJustifyFlexEnd) { child->setLayoutPosition( (node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]]), leading[mainAxis]); - } else if ( - node->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && - child->isLeadingPositionDefined(mainAxis)) { - child->setLayoutPosition( - child->getLeadingPosition( - mainAxis, node->getLayout().measuredDimensions[dim[mainAxis]]) - .unwrap() + - node->getLeadingBorder(mainAxis) + - child - ->getLeadingMargin( - mainAxis, - node->getLayout().measuredDimensions[dim[mainAxis]]) - .unwrap(), - leading[mainAxis]); } if (child->isTrailingPosDefined(crossAxis) && @@ -1591,11 +1326,9 @@ static void YGNodeAbsoluteLayoutChild( node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]] - node->getTrailingBorder(crossAxis) - - child->getTrailingMargin(crossAxis, isMainAxisRow ? height : width) - .unwrap() - - child - ->getTrailingPosition(crossAxis, isMainAxisRow ? height : width) - .unwrap(), + child->getTrailingMargin(crossAxis, width) - + child->getTrailingPosition( + crossAxis, isMainAxisRow ? height : width), leading[crossAxis]); } else if ( @@ -1609,108 +1342,67 @@ static void YGNodeAbsoluteLayoutChild( } else if ( !child->isLeadingPositionDefined(crossAxis) && ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^ - (node->getStyle().flexWrap() == YGWrapWrapReverse))) { + (node->getStyle().flexWrap == YGWrapWrapReverse))) { child->setLayoutPosition( (node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]]), leading[crossAxis]); - } else if ( - node->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && - child->isLeadingPositionDefined(crossAxis)) { - child->setLayoutPosition( - child->getLeadingPosition( - crossAxis, - node->getLayout().measuredDimensions[dim[crossAxis]]) - .unwrap() + - node->getLeadingBorder(crossAxis) + - child - ->getLeadingMargin( - crossAxis, - node->getLayout().measuredDimensions[dim[crossAxis]]) - .unwrap(), - leading[crossAxis]); } } -static void YGNodeWithMeasureFuncSetMeasuredDimensions( - const YGNodeRef node, - float availableWidth, - float availableHeight, - const YGMeasureMode widthMeasureMode, - const YGMeasureMode heightMeasureMode, - const float ownerWidth, - const float ownerHeight, - LayoutData& layoutMarkerData, - void* const layoutContext, - const LayoutPassReason reason) { +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->hasMeasureFunc(), + node->getMeasure() != nullptr, "Expected node to have custom measure function"); - if (widthMeasureMode == YGMeasureModeUndefined) { - availableWidth = YGUndefined; - } - if (heightMeasureMode == YGMeasureModeUndefined) { - availableHeight = YGUndefined; - } - - const auto& padding = node->getLayout().padding; - const auto& border = node->getLayout().border; - const float paddingAndBorderAxisRow = padding[YGEdgeLeft] + - padding[YGEdgeRight] + border[YGEdgeLeft] + border[YGEdgeRight]; - const float paddingAndBorderAxisColumn = padding[YGEdgeTop] + - padding[YGEdgeBottom] + border[YGEdgeTop] + border[YGEdgeBottom]; + const float paddingAndBorderAxisRow = + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); + const float paddingAndBorderAxisColumn = + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth); + const float marginAxisRow = + node->getMarginForAxis(YGFlexDirectionRow, availableWidth); + const float marginAxisColumn = + 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 - paddingAndBorderAxisRow); + : fmaxf(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow); const float innerHeight = YGFloatIsUndefined(availableHeight) ? availableHeight - : YGFloatMax(0, availableHeight - paddingAndBorderAxisColumn); + : fmaxf( + 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, ownerWidth, ownerWidth), + node, + YGFlexDirectionRow, + availableWidth - marginAxisRow, + parentWidth, + parentWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, YGFlexDirectionColumn, - availableHeight, - ownerHeight, - ownerWidth), + availableHeight - marginAxisColumn, + parentHeight, + parentWidth), YGDimensionHeight); } else { - Event::publish(node); - // Measure the text under the current constraints. - const YGSize measuredSize = node->measure( - innerWidth, - widthMeasureMode, - innerHeight, - heightMeasureMode, - layoutContext); - - layoutMarkerData.measureCallbacks += 1; - layoutMarkerData.measureCallbackReasonsCount[static_cast(reason)] += - 1; - - Event::publish( - node, - {layoutContext, - innerWidth, - widthMeasureMode, - innerHeight, - heightMeasureMode, - measuredSize.width, - measuredSize.height, - reason}); + const YGSize measuredSize = node->getMeasure()( + node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1719,9 +1411,9 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( (widthMeasureMode == YGMeasureModeUndefined || widthMeasureMode == YGMeasureModeAtMost) ? measuredSize.width + paddingAndBorderAxisRow - : availableWidth, - ownerWidth, - ownerWidth), + : availableWidth - marginAxisRow, + parentWidth, + parentWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -1731,62 +1423,71 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( (heightMeasureMode == YGMeasureModeUndefined || heightMeasureMode == YGMeasureModeAtMost) ? measuredSize.height + paddingAndBorderAxisColumn - : availableHeight, - ownerHeight, - ownerWidth), + : availableHeight - marginAxisColumn, + parentHeight, + parentWidth), 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 auto& padding = node->getLayout().padding; - const auto& border = node->getLayout().border; - - float width = availableWidth; - if (widthMeasureMode == YGMeasureModeUndefined || - widthMeasureMode == YGMeasureModeAtMost) { - width = padding[YGEdgeLeft] + padding[YGEdgeRight] + border[YGEdgeLeft] + - border[YGEdgeRight]; - } +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 = + node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + const float marginAxisColumn = + node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + node->setLayoutMeasuredDimension( - YGNodeBoundAxis(node, YGFlexDirectionRow, width, ownerWidth, ownerWidth), + YGNodeBoundAxis( + node, + YGFlexDirectionRow, + (widthMeasureMode == YGMeasureModeUndefined || + widthMeasureMode == YGMeasureModeAtMost) + ? paddingAndBorderAxisRow + : availableWidth - marginAxisRow, + parentWidth, + parentWidth), YGDimensionWidth); - float height = availableHeight; - if (heightMeasureMode == YGMeasureModeUndefined || - heightMeasureMode == YGMeasureModeAtMost) { - height = padding[YGEdgeTop] + padding[YGEdgeBottom] + border[YGEdgeTop] + - border[YGEdgeBottom]; - } node->setLayoutMeasuredDimension( YGNodeBoundAxis( - node, YGFlexDirectionColumn, height, ownerHeight, ownerWidth), + node, + YGFlexDirectionColumn, + (heightMeasureMode == YGMeasureModeUndefined || + heightMeasureMode == YGMeasureModeAtMost) + ? paddingAndBorderAxisColumn + : availableHeight - marginAxisColumn, + parentHeight, + parentWidth), 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)) { +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 = + node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + const float marginAxisRow = + node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, @@ -1795,9 +1496,9 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( (widthMeasureMode == YGMeasureModeAtMost && availableWidth < 0.0f) ? 0.0f - : availableWidth, - ownerWidth, - ownerWidth), + : availableWidth - marginAxisRow, + parentWidth, + parentWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -1808,9 +1509,9 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( (heightMeasureMode == YGMeasureModeAtMost && availableHeight < 0.0f) ? 0.0f - : availableHeight, - ownerHeight, - ownerWidth), + : availableHeight - marginAxisColumn, + parentHeight, + parentWidth), YGDimensionHeight); return true; } @@ -1818,50 +1519,51 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( return false; } -static void YGZeroOutLayoutRecursively( - const YGNodeRef node, - void* layoutContext) { - node->getLayout() = {}; - node->setLayoutDimension(0, 0); - node->setLayoutDimension(0, 1); +static void YGZeroOutLayoutRecursivly(const YGNodeRef node) { + memset(&(node->getLayout()), 0, sizeof(YGLayout)); node->setHasNewLayout(true); - - node->iterChildrenAfterCloningIfNeeded( - YGZeroOutLayoutRecursively, layoutContext); + 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 YGNodeConstRef node, - const YGDimension dimension, - const float availableDim, - const float paddingAndBorder, - const float ownerDim) { - float availableInnerDim = availableDim - paddingAndBorder; + const YGNodeRef node, + YGFlexDirection axis, + float availableDim, + float parentDim) { + YGFlexDirection direction = + YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn; + YGDimension dimension = + YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight; + + const float margin = node->getMarginForAxis(direction, parentDim); + const float paddingAndBorder = + YGNodePaddingAndBorderForAxis(node, direction, parentDim); + + 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.unwrap() - paddingAndBorder; - - const YGFloatOptional maxDimensionOptional = - YGResolveValue(node->getStyle().maxDimensions()[dimension], ownerDim); - - const float maxInnerDim = maxDimensionOptional.isUndefined() - ? FLT_MAX - : maxDimensionOptional.unwrap() - paddingAndBorder; + const float minInnerDim = + YGResolveValue(node->getStyle().minDimensions[dimension], parentDim) - + paddingAndBorder; + const float maxInnerDim = + YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) - + paddingAndBorder; availableInnerDim = - YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim); + fmaxf(fminf(availableInnerDim, maxInnerDim), minInnerDim); } return availableInnerDim; } -static float YGNodeComputeFlexBasisForChildren( +static void YGNodeComputeFlexBasisForChildren( const YGNodeRef node, const float availableInnerWidth, const float availableInnerHeight, @@ -1871,13 +1573,9 @@ static float YGNodeComputeFlexBasisForChildren( YGFlexDirection mainAxis, const YGConfigRef config, bool performLayout, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount) { - float totalOuterFlexBasis = 0.0f; + float& totalOuterFlexBasis) { YGNodeRef singleFlexChild = nullptr; - const YGVector& children = node->getChildren(); + YGVector children = node->getChildren(); YGMeasureMode measureModeMainDim = YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode; // If there is only one child with flexGrow + flexShrink it means we can set @@ -1885,31 +1583,30 @@ static float YGNodeComputeFlexBasisForChildren( // 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 + if (singleFlexChild != nullptr) { + if (child->isNodeFlexible()) { + // There is already a flexible child, abort singleFlexChild = nullptr; break; - } else { - singleFlexChild = child; } + } else if ( + child->resolveFlexGrow() > 0.0f && + child->resolveFlexShrink() > 0.0f) { + singleFlexChild = child; } } } for (auto child : children) { child->resolveDimension(); - if (child->getStyle().display() == YGDisplayNone) { - YGZeroOutLayoutRecursively(child, layoutContext); + if (child->getStyle().display == YGDisplayNone) { + YGZeroOutLayoutRecursivly(child); child->setHasNewLayout(true); child->setDirty(false); continue; } if (performLayout) { - // Set the initial position (relative to the owner). + // Set the initial position (relative to the parent). const YGDirection childDirection = child->resolveDirection(direction); const float mainDim = YGFlexDirectionIsRow(mainAxis) ? availableInnerWidth @@ -1921,12 +1618,12 @@ static float YGNodeComputeFlexBasisForChildren( childDirection, mainDim, crossDim, availableInnerWidth); } - if (child->getStyle().positionType() == YGPositionTypeAbsolute) { + if (child->getStyle().positionType == YGPositionTypeAbsolute) { continue; } if (child == singleFlexChild) { - child->setLayoutComputedFlexBasisGeneration(generationCount); - child->setLayoutComputedFlexBasis(YGFloatOptional(0)); + child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount); + child->setLayoutComputedFlexBasis(0); } else { YGNodeComputeFlexBasisForChild( node, @@ -1938,30 +1635,22 @@ static float YGNodeComputeFlexBasisForChildren( availableInnerHeight, heightMeasureMode, direction, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + config); } - totalOuterFlexBasis += - (child->getLayout().computedFlexBasis + - child->getMarginForAxis(mainAxis, availableInnerWidth)) - .unwrap(); + totalOuterFlexBasis += child->getLayout().computedFlexBasis + + child->getMarginForAxis(mainAxis, availableInnerWidth); } - - return totalOuterFlexBasis; } // This function assumes that all the children of node have their // computedFlexBasis properly computed(To do this use -// YGNodeComputeFlexBasisForChildren function). This function calculates -// YGCollectFlexItemsRowMeasurement +// YGNodeComputeFlexBasisForChildren function). +// This function calculates YGCollectFlexItemsRowMeasurement static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( const YGNodeRef& node, - const YGDirection ownerDirection, - const float mainAxisownerSize, + const YGDirection parentDirection, + const float mainAxisParentSize, const float availableInnerWidth, const float availableInnerMainDim, const uint32_t startOfLineIndex, @@ -1971,50 +1660,42 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( float sizeConsumedOnCurrentLineIncludingMinConstraint = 0; const YGFlexDirection mainAxis = YGResolveFlexDirection( - node->getStyle().flexDirection(), node->resolveDirection(ownerDirection)); - const bool isNodeFlexWrap = node->getStyle().flexWrap() != YGWrapNoWrap; - const float gap = node->getGapForAxis(mainAxis, availableInnerWidth).unwrap(); + node->getStyle().flexDirection, node->resolveDirection(parentDirection)); + 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++) { + for (; endOfLineIndex < node->getChildrenCount(); endOfLineIndex++) { const YGNodeRef child = node->getChild(endOfLineIndex); - if (child->getStyle().display() == YGDisplayNone || - child->getStyle().positionType() == YGPositionTypeAbsolute) { + if (child->getStyle().display == YGDisplayNone || + child->getStyle().positionType == YGPositionTypeAbsolute) { continue; } - - const bool isFirstElementInLine = (endOfLineIndex - startOfLineIndex) == 0; - child->setLineIndex(lineCount); const float childMarginMainAxis = - child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap(); - const float childLeadingGapMainAxis = isFirstElementInLine ? 0.0f : gap; + child->getMarginForAxis(mainAxis, availableInnerWidth); const float flexBasisWithMinAndMaxConstraints = YGNodeBoundAxisWithinMinAndMax( child, mainAxis, child->getLayout().computedFlexBasis, - mainAxisownerSize) - .unwrap(); + mainAxisParentSize); - // 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 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 + - childLeadingGapMainAxis > + flexBasisWithMinAndMaxConstraints + childMarginMainAxis > availableInnerMainDim && isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) { break; } sizeConsumedOnCurrentLineIncludingMinConstraint += - flexBasisWithMinAndMaxConstraints + childMarginMainAxis + - childLeadingGapMainAxis; + flexBasisWithMinAndMaxConstraints + childMarginMainAxis; flexAlgoRowMeasurement.sizeConsumedOnCurrentLine += - flexBasisWithMinAndMaxConstraints + childMarginMainAxis + - childLeadingGapMainAxis; + flexBasisWithMinAndMaxConstraints + childMarginMainAxis; flexAlgoRowMeasurement.itemsOnLine++; if (child->isNodeFlexible()) { @@ -2023,8 +1704,7 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( // Unlike the grow factor, the shrink factor is scaled relative to the // child dimension. flexAlgoRowMeasurement.totalFlexShrinkScaledFactors += - -child->resolveFlexShrink() * - child->getLayout().computedFlexBasis.unwrap(); + -child->resolveFlexShrink() * child->getLayout().computedFlexBasis; } flexAlgoRowMeasurement.relativeChildren.push_back(child); @@ -2054,46 +1734,38 @@ static float YGDistributeFreeSpaceSecondPass( const YGNodeRef node, const YGFlexDirection mainAxis, const YGFlexDirection crossAxis, - const float mainAxisownerSize, + const float mainAxisParentSize, const float availableInnerMainDim, const float availableInnerCrossDim, const float availableInnerWidth, const float availableInnerHeight, - const bool mainAxisOverflows, + const bool flexBasisOverflows, const YGMeasureMode measureModeCrossDim, const bool performLayout, - const YGConfigRef config, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount) { + 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; + const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap; for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) { childFlexBasis = YGNodeBoundAxisWithinMinAndMax( - currentRelativeChild, - mainAxis, - currentRelativeChild->getLayout().computedFlexBasis, - mainAxisownerSize) - .unwrap(); + currentRelativeChild, + mainAxis, + currentRelativeChild->getLayout().computedFlexBasis, + mainAxisParentSize); float updatedMainSize = childFlexBasis; - if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && - collectedFlexItemsValues.remainingFreeSpace < 0) { + if (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) { + if (collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) { childSize = childFlexBasis + flexShrinkScaledFactor; } else { childSize = childFlexBasis + @@ -2109,13 +1781,11 @@ static float YGDistributeFreeSpaceSecondPass( availableInnerMainDim, availableInnerWidth); } - } else if ( - !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && - collectedFlexItemsValues.remainingFreeSpace > 0) { + } else if (collectedFlexItemsValues.remainingFreeSpace > 0) { flexGrowFactor = currentRelativeChild->resolveFlexGrow(); // Is this child able to grow? - if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) { + if (flexGrowFactor != 0) { updatedMainSize = YGNodeBoundAxis( currentRelativeChild, mainAxis, @@ -2131,22 +1801,20 @@ static float YGDistributeFreeSpaceSecondPass( deltaFreeSpace += updatedMainSize - childFlexBasis; const float marginMain = - currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth) - .unwrap(); + currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth); const float marginCross = - currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth) - .unwrap(); + currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth); float childCrossSize; float childMainSize = updatedMainSize + marginMain; YGMeasureMode childCrossMeasureMode; YGMeasureMode childMainMeasureMode = YGMeasureModeExactly; - const auto& childStyle = currentRelativeChild->getStyle(); - if (!childStyle.aspectRatio().isUndefined()) { - childCrossSize = isMainAxisRow - ? (childMainSize - marginMain) / childStyle.aspectRatio().unwrap() - : (childMainSize - marginMain) * childStyle.aspectRatio().unwrap(); + if (!YGFloatIsUndefined(currentRelativeChild->getStyle().aspectRatio)) { + childCrossSize = isMainAxisRow ? (childMainSize - marginMain) / + currentRelativeChild->getStyle().aspectRatio + : (childMainSize - marginMain) * + currentRelativeChild->getStyle().aspectRatio; childCrossMeasureMode = YGMeasureModeExactly; childCrossSize += marginCross; @@ -2155,7 +1823,7 @@ static float YGDistributeFreeSpaceSecondPass( !YGNodeIsStyleDimDefined( currentRelativeChild, crossAxis, availableInnerCrossDim) && measureModeCrossDim == YGMeasureModeExactly && - !(isNodeFlexWrap && mainAxisOverflows) && + !(isNodeFlexWrap && flexBasisOverflows) && YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch && currentRelativeChild->marginLeadingValue(crossAxis).unit != YGUnitAuto && @@ -2173,8 +1841,7 @@ static float YGDistributeFreeSpaceSecondPass( childCrossSize = YGResolveValue( currentRelativeChild->getResolvedDimension(dim[crossAxis]), - availableInnerCrossDim) - .unwrap() + + availableInnerCrossDim) + marginCross; const bool isLoosePercentageMeasurement = currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit == @@ -2217,29 +1884,23 @@ static float YGDistributeFreeSpaceSecondPass( const YGMeasureMode childHeightMeasureMode = !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode; - const bool isLayoutPass = performLayout && !requiresStretchLayout; // Recursively call the layout algorithm for this child with the updated // main size. YGLayoutNodeInternal( currentRelativeChild, childWidth, childHeight, - node->getLayout().direction(), + node->getLayout().direction, childWidthMeasureMode, childHeightMeasureMode, availableInnerWidth, availableInnerHeight, - isLayoutPass, - isLayoutPass ? LayoutPassReason::kFlexLayout - : LayoutPassReason::kFlexMeasure, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + performLayout && !requiresStretchLayout, + "flex", + config); node->setLayoutHadOverflow( - node->getLayout().hadOverflow() || - currentRelativeChild->getLayout().hadOverflow()); + node->getLayout().hadOverflow || + currentRelativeChild->getLayout().hadOverflow); } return deltaFreeSpace; } @@ -2250,7 +1911,7 @@ static float YGDistributeFreeSpaceSecondPass( static void YGDistributeFreeSpaceFirstPass( YGCollectFlexItemsRowValues& collectedFlexItemsValues, const YGFlexDirection mainAxis, - const float mainAxisownerSize, + const float mainAxisParentSize, const float availableInnerMainDim, const float availableInnerWidth) { float flexShrinkScaledFactor = 0; @@ -2260,21 +1921,18 @@ static void YGDistributeFreeSpaceFirstPass( float deltaFreeSpace = 0; for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) { - float childFlexBasis = - YGNodeBoundAxisWithinMinAndMax( - currentRelativeChild, - mainAxis, - currentRelativeChild->getLayout().computedFlexBasis, - mainAxisownerSize) - .unwrap(); + float childFlexBasis = YGNodeBoundAxisWithinMinAndMax( + currentRelativeChild, + mainAxis, + currentRelativeChild->getLayout().computedFlexBasis, + mainAxisParentSize); if (collectedFlexItemsValues.remainingFreeSpace < 0) { flexShrinkScaledFactor = -currentRelativeChild->resolveFlexShrink() * childFlexBasis; // Is this child able to shrink? - if (!YGFloatIsUndefined(flexShrinkScaledFactor) && - flexShrinkScaledFactor != 0) { + if (flexShrinkScaledFactor != 0) { baseMainSize = childFlexBasis + collectedFlexItemsValues.remainingFreeSpace / collectedFlexItemsValues.totalFlexShrinkScaledFactors * @@ -2285,26 +1943,23 @@ static void YGDistributeFreeSpaceFirstPass( 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. + 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; collectedFlexItemsValues.totalFlexShrinkScaledFactors -= - (-currentRelativeChild->resolveFlexShrink() * - currentRelativeChild->getLayout().computedFlexBasis.unwrap()); + flexShrinkScaledFactor; } } - } else if ( - !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && - collectedFlexItemsValues.remainingFreeSpace > 0) { + } else if (collectedFlexItemsValues.remainingFreeSpace > 0) { flexGrowFactor = currentRelativeChild->resolveFlexGrow(); // Is this child able to grow? - if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) { + if (flexGrowFactor != 0) { baseMainSize = childFlexBasis + collectedFlexItemsValues.remainingFreeSpace / collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor; @@ -2315,13 +1970,13 @@ static void YGDistributeFreeSpaceFirstPass( 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. + 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; collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor; } @@ -2333,22 +1988,25 @@ static void YGDistributeFreeSpaceFirstPass( // 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. // -// The first pass finds the items whose min/max constraints trigger, freezes -// them at those sizes, and excludes those sizes from the remaining space. -// -// The second pass sets the size of each flexible item. It distributes the -// remaining space amongst the items whose min/max constraints didn't trigger in -// the first pass. For the other items, it sets their sizes by forcing their -// min/max constraints to trigger again. -// -// This two pass approach for resolving min/max constraints deviates from the -// spec. The spec -// (https://www.w3.org/TR/CSS-flexbox-1/#resolve-flexible-lengths) describes a -// process that needs to be repeated a variable number of times. The algorithm -// implemented here won't handle all cases but it was simpler to implement and -// it mitigates performance concerns because we know exactly how many passes -// it'll do. +// 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. @@ -2358,25 +2016,21 @@ static void YGResolveFlexibleLength( YGCollectFlexItemsRowValues& collectedFlexItemsValues, const YGFlexDirection mainAxis, const YGFlexDirection crossAxis, - const float mainAxisownerSize, + const float mainAxisParentSize, const float availableInnerMainDim, const float availableInnerCrossDim, const float availableInnerWidth, const float availableInnerHeight, - const bool mainAxisOverflows, + const bool flexBasisOverflows, const YGMeasureMode measureModeCrossDim, const bool performLayout, - const YGConfigRef config, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount) { + const YGConfigRef config) { const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace; // First pass: detect the flex items whose min/max constraints trigger YGDistributeFreeSpaceFirstPass( collectedFlexItemsValues, mainAxis, - mainAxisownerSize, + mainAxisParentSize, availableInnerMainDim, availableInnerWidth); @@ -2386,19 +2040,15 @@ static void YGResolveFlexibleLength( node, mainAxis, crossAxis, - mainAxisownerSize, + mainAxisParentSize, availableInnerMainDim, availableInnerCrossDim, availableInnerWidth, availableInnerHeight, - mainAxisOverflows, + flexBasisOverflows, measureModeCrossDim, performLayout, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + config); collectedFlexItemsValues.remainingFreeSpace = originalFreeSpace - distributedFreeSpace; @@ -2407,47 +2057,32 @@ static void YGResolveFlexibleLength( 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, - void* const layoutContext) { - const auto& style = node->getStyle(); - const float leadingPaddingAndBorderMain = - node->getLeadingPaddingAndBorder(mainAxis, ownerWidth).unwrap(); - const float trailingPaddingAndBorderMain = - node->getTrailingPaddingAndBorder(mainAxis, ownerWidth).unwrap(); - const float gap = node->getGapForAxis(mainAxis, ownerWidth).unwrap(); - // If we are using "at most" rules in the main axis, make sure that - // remainingFreeSpace is 0 when min main dimension is not given + const uint32_t& startOfLineIndex, + const YGFlexDirection& mainAxis, + const YGFlexDirection& crossAxis, + const YGMeasureMode& measureModeMainDim, + const YGMeasureMode& measureModeCrossDim, + const float& mainAxisParentSize, + const float& parentWidth, + const float& availableInnerMainDim, + const float& availableInnerCrossDim, + const float& availableInnerWidth, + const bool& performLayout) { + const YGStyle style = node->getStyle(); + + // 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 && collectedFlexItemsValues.remainingFreeSpace > 0) { - if (!style.minDimensions()[dim[mainAxis]].isUndefined() && - !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 = + if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined && + YGResolveValue( + style.minDimensions[dim[mainAxis]], mainAxisParentSize) >= 0) { + collectedFlexItemsValues.remainingFreeSpace = fmaxf( + 0, YGResolveValue( - style.minDimensions()[dim[mainAxis]], mainAxisownerSize) - .unwrap() - - leadingPaddingAndBorderMain - trailingPaddingAndBorderMain; - const float occupiedSpaceByChildNodes = - availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace; - collectedFlexItemsValues.remainingFreeSpace = - YGFloatMax(0, minAvailableMainDim - occupiedSpaceByChildNodes); + style.minDimensions[dim[mainAxis]], mainAxisParentSize) - + (availableInnerMainDim - + collectedFlexItemsValues.remainingFreeSpace)); } else { collectedFlexItemsValues.remainingFreeSpace = 0; } @@ -2458,7 +2093,7 @@ static void YGJustifyMainAxis( i < collectedFlexItemsValues.endOfLineIndex; i++) { const YGNodeRef child = node->getChild(i); - if (child->getStyle().positionType() != YGPositionTypeAbsolute) { + if (child->getStyle().positionType == YGPositionTypeRelative) { if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) { numberOfAutoMarginsOnCurrentLine++; } @@ -2468,12 +2103,12 @@ static void YGJustifyMainAxis( } } - // 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. + // In order to position the elements in the main axis, we have two + // controls. The space between the beginning and the first element + // and the space between each two elements. float leadingMainDim = 0; - float betweenMainDim = gap; - const YGJustify justifyContent = node->getStyle().justifyContent(); + float betweenMainDim = 0; + const YGJustify justifyContent = node->getStyle().justifyContent; if (numberOfAutoMarginsOnCurrentLine == 0) { switch (justifyContent) { @@ -2485,67 +2120,62 @@ static void YGJustifyMainAxis( break; case YGJustifySpaceBetween: if (collectedFlexItemsValues.itemsOnLine > 1) { - betweenMainDim += - YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) / + betweenMainDim = + fmaxf(collectedFlexItemsValues.remainingFreeSpace, 0) / (collectedFlexItemsValues.itemsOnLine - 1); + } else { + betweenMainDim = 0; } break; case YGJustifySpaceEvenly: // Space is distributed evenly across all elements - leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / + betweenMainDim = collectedFlexItemsValues.remainingFreeSpace / (collectedFlexItemsValues.itemsOnLine + 1); - betweenMainDim += leadingMainDim; + leadingMainDim = betweenMainDim; break; case YGJustifySpaceAround: // Space on the edges is half of the space between elements - leadingMainDim = 0.5f * collectedFlexItemsValues.remainingFreeSpace / + betweenMainDim = collectedFlexItemsValues.remainingFreeSpace / collectedFlexItemsValues.itemsOnLine; - betweenMainDim += leadingMainDim * 2; + leadingMainDim = betweenMainDim / 2; break; case YGJustifyFlexStart: break; } } + const float leadingPaddingAndBorderMain = + node->getLeadingPaddingAndBorder(mainAxis, parentWidth); 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 YGStyle childStyle = child->getStyle(); const YGLayout childLayout = child->getLayout(); - const bool isLastChild = i == collectedFlexItemsValues.endOfLineIndex - 1; - // remove the gap if it is the last element of the line - if (isLastChild) { - betweenMainDim -= gap; - } - if (childStyle.display() == YGDisplayNone) { + if (childStyle.display == YGDisplayNone) { continue; } - if (childStyle.positionType() == YGPositionTypeAbsolute && + 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). + // defined, we override the position to whatever the user said + // (and margin/border). child->setLayoutPosition( - child->getLeadingPosition(mainAxis, availableInnerMainDim) - .unwrap() + + child->getLeadingPosition(mainAxis, availableInnerMainDim) + node->getLeadingBorder(mainAxis) + - child->getLeadingMargin(mainAxis, availableInnerWidth).unwrap(), + 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() != YGPositionTypeAbsolute) { + // 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 / @@ -2567,12 +2197,13 @@ static void YGJustifyMainAxis( 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 + // 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 + - child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap() + - childLayout.computedFlexBasis.unwrap(); + child->getMarginForAxis(mainAxis, availableInnerWidth) + + childLayout.computedFlexBasis; collectedFlexItemsValues.crossDim = availableInnerCrossDim; } else { // The main dimension is the sum of all the elements dimension plus @@ -2580,34 +2211,11 @@ static void YGJustifyMainAxis( 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, layoutContext) + - child - ->getLeadingMargin( - YGFlexDirectionColumn, availableInnerWidth) - .unwrap(); - const float descent = - child->getLayout().measuredDimensions[YGDimensionHeight] + - child - ->getMarginForAxis( - YGFlexDirectionColumn, availableInnerWidth) - .unwrap() - - 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)); - } + // The cross dimension is the max of the elements dimension since + // there can only be one element in that cross dimension. + collectedFlexItemsValues.crossDim = fmaxf( + collectedFlexItemsValues.crossDim, + YGNodeDimWithMargin(child, crossAxis, availableInnerWidth)); } } else if (performLayout) { child->setLayoutPosition( @@ -2617,261 +2225,255 @@ static void YGJustifyMainAxis( } } } - collectedFlexItemsValues.mainDim += trailingPaddingAndBorderMain; - - if (isNodeBaselineLayout) { - collectedFlexItemsValues.crossDim = - maxAscentForCurrentLine + maxDescentForCurrentLine; - } + collectedFlexItemsValues.mainDim += + node->getTrailingPaddingAndBorder(mainAxis, parentWidth); } // // This is the main routine that implements a subset of the flexbox layout -// algorithm described in the W3C CSS documentation: -// https://www.w3.org/TR/CSS3-flexbox/. +// 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'. +// 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. +// are +// stacked in document order. // * The 'order' property is not supported. The order of flex items is always -// defined by document order. +// defined +// by document order. // * The 'visibility' property is always assumed to be 'visible'. Values of -// 'collapse' and 'hidden' are not supported. +// '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). +// 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. +// 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. +// lengths. // * The spec indicates that the default value for 'flexDirection' is 'row', -// but the algorithm below assumes a default of 'column'. +// but +// the algorithm below assumes a default of 'column'. // // Input parameters: -// - node: current node to be sized and laid out +// - 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) +// 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) +// for explanation) // - heightMeasureMode: indicates the sizing rules for the height (see below -// for explanation) +// for explanation) // - performLayout: specifies whether the caller is interested in just the -// dimensions of the node or it requires the entire node and its subtree to -// be laid out (with final positions) +// 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 +// 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. +// 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/CSS3-sizing/#terms): +// 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. +// 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, - LayoutData& layoutMarkerData, - void* const layoutContext, - const uint32_t depth, - const uint32_t generationCount, - const LayoutPassReason reason) { - 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"); - - (performLayout ? layoutMarkerData.layouts : layoutMarkerData.measures) += 1; +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 = node->resolveDirection(ownerDirection); + const YGDirection direction = node->resolveDirection(parentDirection); node->setLayoutDirection(direction); - const YGFlexDirection flexRowDirection = - YGResolveFlexDirection(YGFlexDirectionRow, direction); + const YGFlexDirection flexRowDirection = YGResolveFlexDirection(YGFlexDirectionRow, direction); const YGFlexDirection flexColumnDirection = YGResolveFlexDirection(YGFlexDirectionColumn, direction); - const YGEdge startEdge = - direction == YGDirectionLTR ? YGEdgeLeft : YGEdgeRight; - const YGEdge endEdge = direction == YGDirectionLTR ? YGEdgeRight : YGEdgeLeft; - - const float marginRowLeading = - node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap(); - node->setLayoutMargin(marginRowLeading, startEdge); - const float marginRowTrailing = - node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap(); - node->setLayoutMargin(marginRowTrailing, endEdge); - const float marginColumnLeading = - node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap(); - node->setLayoutMargin(marginColumnLeading, YGEdgeTop); - const float marginColumnTrailing = - node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap(); - node->setLayoutMargin(marginColumnTrailing, YGEdgeBottom); - - const float marginAxisRow = marginRowLeading + marginRowTrailing; - const float marginAxisColumn = marginColumnLeading + marginColumnTrailing; - - node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), startEdge); - node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), endEdge); + node->setLayoutMargin( + node->getLeadingMargin(flexRowDirection, parentWidth), YGEdgeStart); + node->setLayoutMargin( + node->getTrailingMargin(flexRowDirection, parentWidth), YGEdgeEnd); + node->setLayoutMargin( + node->getLeadingMargin(flexColumnDirection, parentWidth), YGEdgeTop); + node->setLayoutMargin( + node->getTrailingMargin(flexColumnDirection, parentWidth), 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( - node->getLeadingPadding(flexRowDirection, ownerWidth).unwrap(), - startEdge); + node->getLeadingPadding(flexRowDirection, parentWidth), YGEdgeStart); node->setLayoutPadding( - node->getTrailingPadding(flexRowDirection, ownerWidth).unwrap(), endEdge); + node->getTrailingPadding(flexRowDirection, parentWidth), YGEdgeEnd); node->setLayoutPadding( - node->getLeadingPadding(flexColumnDirection, ownerWidth).unwrap(), - YGEdgeTop); + node->getLeadingPadding(flexColumnDirection, parentWidth), YGEdgeTop); node->setLayoutPadding( - node->getTrailingPadding(flexColumnDirection, ownerWidth).unwrap(), - YGEdgeBottom); - - if (node->hasMeasureFunc()) { - YGNodeWithMeasureFuncSetMeasuredDimensions( - node, - availableWidth - marginAxisRow, - availableHeight - marginAxisColumn, - widthMeasureMode, - heightMeasureMode, - ownerWidth, - ownerHeight, - layoutMarkerData, - layoutContext, - reason); + node->getTrailingPadding(flexColumnDirection, parentWidth), YGEdgeBottom); + + if (node->getMeasure() != nullptr) { + YGNodeWithMeasureFuncSetMeasuredDimensions(node, + availableWidth, + availableHeight, + widthMeasureMode, + heightMeasureMode, + parentWidth, + parentHeight); return; } const uint32_t childCount = YGNodeGetChildCount(node); if (childCount == 0) { - YGNodeEmptyContainerSetMeasuredDimensions( - node, - availableWidth - marginAxisRow, - availableHeight - marginAxisColumn, - widthMeasureMode, - heightMeasureMode, - ownerWidth, - ownerHeight); + 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 - marginAxisRow, - availableHeight - marginAxisColumn, - widthMeasureMode, - heightMeasureMode, - ownerWidth, - ownerHeight)) { + // 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. - node->cloneChildrenIfNeeded(layoutContext); + // 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); + YGResolveFlexDirection(node->getStyle().flexDirection, direction); const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); - const bool isNodeFlexWrap = node->getStyle().flexWrap() != YGWrapNoWrap; + const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap; - const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; - const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth; + const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; + const float crossAxisParentSize = isMainAxisRow ? parentHeight : parentWidth; - const float paddingAndBorderAxisMain = - YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth); const float leadingPaddingAndBorderCross = - node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap(); - const float trailingPaddingAndBorderCross = - node->getTrailingPaddingAndBorder(crossAxis, ownerWidth).unwrap(); + node->getLeadingPaddingAndBorder(crossAxis, parentWidth); + const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, parentWidth); const float paddingAndBorderAxisCross = - leadingPaddingAndBorderCross + trailingPaddingAndBorderCross; + YGNodePaddingAndBorderForAxis(node, crossAxis, parentWidth); - YGMeasureMode measureModeMainDim = - isMainAxisRow ? widthMeasureMode : heightMeasureMode; - YGMeasureMode measureModeCrossDim = - isMainAxisRow ? heightMeasureMode : widthMeasureMode; + 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 = + node->getMarginForAxis(YGFlexDirectionRow, parentWidth); + const float marginAxisColumn = + node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); + + const float minInnerWidth = + YGResolveValue( + node->getStyle().minDimensions[YGDimensionWidth], parentWidth) - + paddingAndBorderAxisRow; + const float maxInnerWidth = + YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) - + paddingAndBorderAxisRow; + const float minInnerHeight = + YGResolveValue( + node->getStyle().minDimensions[YGDimensionHeight], parentHeight) - + paddingAndBorderAxisColumn; + const float maxInnerHeight = + YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], parentHeight) - + 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, - YGDimensionWidth, - availableWidth - marginAxisRow, - paddingAndBorderAxisRow, - ownerWidth); + node, YGFlexDirectionRow, availableWidth, parentWidth); float availableInnerHeight = YGNodeCalculateAvailableInnerDim( - node, - YGDimensionHeight, - availableHeight - marginAxisColumn, - paddingAndBorderAxisColumn, - ownerHeight); + node, YGFlexDirectionColumn, availableHeight, parentHeight); float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight; const float availableInnerCrossDim = isMainAxisRow ? availableInnerHeight : availableInnerWidth; + float totalOuterFlexBasis = 0; + // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM - // Computed basis + margins + gap - float totalMainDim = 0; - totalMainDim += YGNodeComputeFlexBasisForChildren( + YGNodeComputeFlexBasisForChildren( node, availableInnerWidth, availableInnerHeight, @@ -2881,22 +2483,12 @@ static void YGNodelayoutImpl( mainAxis, config, performLayout, - layoutMarkerData, - layoutContext, - depth, - generationCount); - - if (childCount > 1) { - totalMainDim += - node->getGapForAxis(mainAxis, availableInnerCrossDim).unwrap() * - (childCount - 1); - } + totalOuterFlexBasis); - const bool mainAxisOverflows = - (measureModeMainDim != YGMeasureModeUndefined) && - totalMainDim > availableInnerMainDim; - - if (isNodeFlexWrap && mainAxisOverflows && + const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined + ? false + : totalOuterFlexBasis > availableInnerMainDim; + if (isNodeFlexWrap && flexBasisOverflows && measureModeMainDim == YGMeasureModeAtMost) { measureModeMainDim = YGMeasureModeExactly; } @@ -2912,9 +2504,6 @@ static void YGNodelayoutImpl( // Accumulated cross dimensions of all lines so far. float totalLineCrossDim = 0; - const float crossAxisGap = - node->getGapForAxis(crossAxis, availableInnerCrossDim).unwrap(); - // Max main dimension of all the lines. float maxLineMainDim = 0; YGCollectFlexItemsRowValues collectedFlexItemsValues; @@ -2922,8 +2511,8 @@ static void YGNodelayoutImpl( lineCount++, startOfLineIndex = endOfLineIndex) { collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues( node, - ownerDirection, - mainAxisownerSize, + parentDirection, + mainAxisParentSize, availableInnerWidth, availableInnerMainDim, startOfLineIndex, @@ -2936,36 +2525,13 @@ static void YGNodelayoutImpl( !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. + // 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 we don't measure with exact main dimension we want to ensure we don't violate min and max if (measureModeMainDim != YGMeasureModeExactly) { - const auto& minDimensions = node->getStyle().minDimensions(); - const auto& maxDimensions = node->getStyle().maxDimensions(); - const float minInnerWidth = - YGResolveValue(minDimensions[YGDimensionWidth], ownerWidth).unwrap() - - paddingAndBorderAxisRow; - const float maxInnerWidth = - YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth).unwrap() - - paddingAndBorderAxisRow; - const float minInnerHeight = - YGResolveValue(minDimensions[YGDimensionHeight], ownerHeight) - .unwrap() - - paddingAndBorderAxisColumn; - const float maxInnerHeight = - YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight) - .unwrap() - - paddingAndBorderAxisColumn; - - const float minInnerMainDim = - isMainAxisRow ? minInnerWidth : minInnerHeight; - const float maxInnerMainDim = - isMainAxisRow ? maxInnerWidth : maxInnerHeight; - if (!YGFloatIsUndefined(minInnerMainDim) && collectedFlexItemsValues.sizeConsumedOnCurrentLine < minInnerMainDim) { @@ -2976,15 +2542,9 @@ static void YGNodelayoutImpl( maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; } else { - bool useLegacyStretchBehaviour = - node->hasErrata(YGErrataStretchFlexBasis); - - if (!useLegacyStretchBehaviour && - ((!YGFloatIsUndefined( - collectedFlexItemsValues.totalFlexGrowFactors) && - collectedFlexItemsValues.totalFlexGrowFactors == 0) || - (!YGFloatIsUndefined(node->resolveFlexGrow()) && - node->resolveFlexGrow() == 0))) { + if (!node->getConfig()->useLegacyStretchBehaviour && + (collectedFlexItemsValues.totalFlexGrowFactors == 0 || + 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 @@ -2992,7 +2552,10 @@ static void YGNodelayoutImpl( collectedFlexItemsValues.sizeConsumedOnCurrentLine; } - sizeBasedOnContent = !useLegacyStretchBehaviour; + if (node->getConfig()->useLegacyStretchBehaviour) { + node->setLayoutDidUseLegacyFlag(true); + } + sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour; } } @@ -3000,10 +2563,10 @@ static void YGNodelayoutImpl( 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. + // 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; } @@ -3014,31 +2577,29 @@ static void YGNodelayoutImpl( collectedFlexItemsValues, mainAxis, crossAxis, - mainAxisownerSize, + mainAxisParentSize, availableInnerMainDim, availableInnerCrossDim, availableInnerWidth, availableInnerHeight, - mainAxisOverflows, + flexBasisOverflows, measureModeCrossDim, performLayout, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + config); } node->setLayoutHadOverflow( - node->getLayout().hadOverflow() | + 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. + // 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, @@ -3048,13 +2609,12 @@ static void YGNodelayoutImpl( crossAxis, measureModeMainDim, measureModeCrossDim, - mainAxisownerSize, - ownerWidth, + mainAxisParentSize, + parentWidth, availableInnerMainDim, availableInnerCrossDim, availableInnerWidth, - performLayout, - layoutContext); + performLayout); float containerCrossAxis = availableInnerCrossDim; if (measureModeCrossDim == YGMeasureModeUndefined || @@ -3065,8 +2625,8 @@ static void YGNodelayoutImpl( node, crossAxis, collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross, - crossAxisownerSize, - ownerWidth) - + crossAxisParentSize, + parentWidth) - paddingAndBorderAxisCross; } @@ -3081,8 +2641,8 @@ static void YGNodelayoutImpl( node, crossAxis, collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross, - crossAxisownerSize, - ownerWidth) - + crossAxisParentSize, + parentWidth) - paddingAndBorderAxisCross; // STEP 7: CROSS-AXIS ALIGNMENT @@ -3090,102 +2650,85 @@ static void YGNodelayoutImpl( if (performLayout) { for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) { const YGNodeRef child = node->getChild(i); - if (child->getStyle().display() == YGDisplayNone) { + if (child->getStyle().display == YGDisplayNone) { continue; } - if (child->getStyle().positionType() == YGPositionTypeAbsolute) { + 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. + // 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( - child->getLeadingPosition(crossAxis, availableInnerCrossDim) - .unwrap() + + child->getLeadingPosition(crossAxis, availableInnerCrossDim) + node->getLeadingBorder(crossAxis) + - child->getLeadingMargin(crossAxis, availableInnerWidth) - .unwrap(), + child->getLeadingMargin(crossAxis, availableInnerWidth), pos[crossAxis]); } - // If leading position is not defined or calculations result in Nan, - // default to border + margin + // 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) + - child->getLeadingMargin(crossAxis, availableInnerWidth) - .unwrap(), + child->getLeadingMargin(crossAxis, availableInnerWidth), pos[crossAxis]); } } else { float leadingCrossDim = leadingPaddingAndBorderCross; - // For a relative children, we're either using alignItems (owner) or + // 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. + // 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)) { + if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) { float childMainSize = child->getLayout().measuredDimensions[dim[mainAxis]]; - const auto& childStyle = child->getStyle(); - float childCrossSize = !childStyle.aspectRatio().isUndefined() - ? child->getMarginForAxis(crossAxis, availableInnerWidth) - .unwrap() + + float childCrossSize = + !YGFloatIsUndefined(child->getStyle().aspectRatio) + ? ((child->getMarginForAxis(crossAxis, availableInnerWidth) + (isMainAxisRow - ? childMainSize / childStyle.aspectRatio().unwrap() - : childMainSize * childStyle.aspectRatio().unwrap()) + ? childMainSize / child->getStyle().aspectRatio + : childMainSize * child->getStyle().aspectRatio))) : collectedFlexItemsValues.crossDim; childMainSize += - child->getMarginForAxis(mainAxis, availableInnerWidth) - .unwrap(); + child->getMarginForAxis(mainAxis, availableInnerWidth); YGMeasureMode childMainMeasureMode = YGMeasureModeExactly; YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly; - YGConstrainMaxSizeForMode( - child, - mainAxis, - availableInnerMainDim, - availableInnerWidth, - &childMainMeasureMode, - &childMainSize); - YGConstrainMaxSizeForMode( - child, - crossAxis, - availableInnerCrossDim, - availableInnerWidth, - &childCrossMeasureMode, - &childCrossSize); + 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 float childWidth = - isMainAxisRow ? childMainSize : childCrossSize; - const float childHeight = - !isMainAxisRow ? childMainSize : childCrossSize; - - auto alignContent = node->getStyle().alignContent(); - auto crossAxisDoesNotGrow = - alignContent != YGAlignStretch && isNodeFlexWrap; const YGMeasureMode childWidthMeasureMode = - YGFloatIsUndefined(childWidth) || - (!isMainAxisRow && crossAxisDoesNotGrow) - ? YGMeasureModeUndefined - : YGMeasureModeExactly; + YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined + : YGMeasureModeExactly; const YGMeasureMode childHeightMeasureMode = - YGFloatIsUndefined(childHeight) || - (isMainAxisRow && crossAxisDoesNotGrow) - ? YGMeasureModeUndefined - : YGMeasureModeExactly; + YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined + : YGMeasureModeExactly; YGLayoutNodeInternal( child, @@ -3197,12 +2740,8 @@ static void YGNodelayoutImpl( availableInnerWidth, availableInnerHeight, true, - LayoutPassReason::kStretch, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + "stretch", + config); } } else { const float remainingCrossDim = containerCrossAxis - @@ -3210,13 +2749,13 @@ static void YGNodelayoutImpl( if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto && child->marginTrailingValue(crossAxis).unit == YGUnitAuto) { - leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2); + leadingCrossDim += fmaxf(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); + leadingCrossDim += fmaxf(0.0f, remainingCrossDim); } else if (alignItem == YGAlignFlexStart) { // No-Op } else if (alignItem == YGAlignCenter) { @@ -3234,53 +2773,51 @@ static void YGNodelayoutImpl( } } - const float appliedCrossGap = lineCount != 0 ? crossAxisGap : 0.0f; - totalLineCrossDim += collectedFlexItemsValues.crossDim + appliedCrossGap; - maxLineMainDim = - YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim); + totalLineCrossDim += collectedFlexItemsValues.crossDim; + maxLineMainDim = fmaxf(maxLineMainDim, collectedFlexItemsValues.mainDim); } // STEP 8: MULTI-LINE CONTENT ALIGNMENT - // currentLead stores the size of the cross dim - if (performLayout && (isNodeFlexWrap || YGIsBaselineLayout(node))) { + if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) && + !YGFloatIsUndefined(availableInnerCrossDim)) { + const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim; + 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) { + + 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; } - 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; - } + } 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; @@ -3292,67 +2829,57 @@ static void YGNodelayoutImpl( float maxDescentForCurrentLine = 0; for (ii = startIndex; ii < childCount; ii++) { const YGNodeRef child = node->getChild(ii); - if (child->getStyle().display() == YGDisplayNone) { + if (child->getStyle().display == YGDisplayNone) { continue; } - if (child->getStyle().positionType() != YGPositionTypeAbsolute) { + if (child->getStyle().positionType == YGPositionTypeRelative) { if (child->getLineIndex() != i) { break; } if (YGNodeIsLayoutDimDefined(child, crossAxis)) { - lineHeight = YGFloatMax( + lineHeight = fmaxf( lineHeight, child->getLayout().measuredDimensions[dim[crossAxis]] + - child->getMarginForAxis(crossAxis, availableInnerWidth) - .unwrap()); + child->getMarginForAxis(crossAxis, availableInnerWidth)); } if (YGNodeAlignItem(node, child) == YGAlignBaseline) { - const float ascent = YGBaseline(child, layoutContext) + - child - ->getLeadingMargin( - YGFlexDirectionColumn, availableInnerWidth) - .unwrap(); + const float ascent = YGBaseline(child) + + child->getLeadingMargin( + YGFlexDirectionColumn, availableInnerWidth); const float descent = child->getLayout().measuredDimensions[YGDimensionHeight] + - child - ->getMarginForAxis( - YGFlexDirectionColumn, availableInnerWidth) - .unwrap() - + child->getMarginForAxis( + YGFlexDirectionColumn, availableInnerWidth) - ascent; - maxAscentForCurrentLine = - YGFloatMax(maxAscentForCurrentLine, ascent); - maxDescentForCurrentLine = - YGFloatMax(maxDescentForCurrentLine, descent); - lineHeight = YGFloatMax( - lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine); + maxAscentForCurrentLine = fmaxf(maxAscentForCurrentLine, ascent); + maxDescentForCurrentLine = fmaxf(maxDescentForCurrentLine, descent); + lineHeight = fmaxf(lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine); } } } endIndex = ii; lineHeight += crossDimLead; - currentLead += i != 0 ? crossAxisGap : 0; if (performLayout) { for (ii = startIndex; ii < endIndex; ii++) { const YGNodeRef child = node->getChild(ii); - if (child->getStyle().display() == YGDisplayNone) { + if (child->getStyle().display == YGDisplayNone) { continue; } - if (child->getStyle().positionType() != YGPositionTypeAbsolute) { + if (child->getStyle().positionType == YGPositionTypeRelative) { switch (YGNodeAlignItem(node, child)) { case YGAlignFlexStart: { child->setLayoutPosition( currentLead + - child->getLeadingMargin(crossAxis, availableInnerWidth) - .unwrap(), + child->getLeadingMargin(crossAxis, availableInnerWidth), pos[crossAxis]); break; } case YGAlignFlexEnd: { child->setLayoutPosition( currentLead + lineHeight - - child->getTrailingMargin(crossAxis, availableInnerWidth) - .unwrap() - + child->getTrailingMargin( + crossAxis, availableInnerWidth) - child->getLayout().measuredDimensions[dim[crossAxis]], pos[crossAxis]); break; @@ -3369,26 +2896,23 @@ static void YGNodelayoutImpl( case YGAlignStretch: { child->setLayoutPosition( currentLead + - child->getLeadingMargin(crossAxis, availableInnerWidth) - .unwrap(), + 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)) { + // 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->getLayout() .measuredDimensions[YGDimensionWidth] + - child->getMarginForAxis(mainAxis, availableInnerWidth) - .unwrap()) + child->getMarginForAxis(mainAxis, availableInnerWidth)) : lineHeight; const float childHeight = !isMainAxisRow ? (child->getLayout() .measuredDimensions[YGDimensionHeight] + - child->getMarginForAxis(crossAxis, availableInnerWidth) - .unwrap()) + child->getMarginForAxis( + crossAxis, availableInnerWidth)) : lineHeight; if (!(YGFloatsEqual( @@ -3399,34 +2923,26 @@ static void YGNodelayoutImpl( childHeight, child->getLayout() .measuredDimensions[YGDimensionHeight]))) { - YGLayoutNodeInternal( - child, - childWidth, - childHeight, - direction, - YGMeasureModeExactly, - YGMeasureModeExactly, - availableInnerWidth, - availableInnerHeight, - true, - LayoutPassReason::kMultilineStretch, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + YGLayoutNodeInternal(child, + childWidth, + childHeight, + direction, + YGMeasureModeExactly, + YGMeasureModeExactly, + availableInnerWidth, + availableInnerHeight, + true, + "multiline-stretch", + config); } } break; } case YGAlignBaseline: { child->setLayoutPosition( - currentLead + maxAscentForCurrentLine - - YGBaseline(child, layoutContext) + - child - ->getLeadingPosition( - YGFlexDirectionColumn, availableInnerCrossDim) - .unwrap(), + currentLead + maxAscentForCurrentLine - YGBaseline(child) + + child->getLeadingPosition( + YGFlexDirectionColumn, availableInnerCrossDim), YGEdgeTop); break; @@ -3439,6 +2955,7 @@ static void YGNodelayoutImpl( } } } + currentLead += lineHeight; } } @@ -3450,8 +2967,8 @@ static void YGNodelayoutImpl( node, YGFlexDirectionRow, availableWidth - marginAxisRow, - ownerWidth, - ownerWidth), + parentWidth, + parentWidth), YGDimensionWidth); node->setLayoutMeasuredDimension( @@ -3459,77 +2976,71 @@ static void YGNodelayoutImpl( node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, - ownerHeight, - ownerWidth), + parentHeight, + parentWidth), 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 && + (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), + node, mainAxis, maxLineMainDim, mainAxisParentSize, parentWidth), dim[mainAxis]); } else if ( measureModeMainDim == YGMeasureModeAtMost && - node->getStyle().overflow() == YGOverflowScroll) { + node->getStyle().overflow == YGOverflowScroll) { node->setLayoutMeasuredDimension( - YGFloatMax( - YGFloatMin( + fmaxf( + fminf( availableInnerMainDim + paddingAndBorderAxisMain, YGNodeBoundAxisWithinMinAndMax( - node, - mainAxis, - YGFloatOptional{maxLineMainDim}, - mainAxisownerSize) - .unwrap()), + node, mainAxis, maxLineMainDim, mainAxisParentSize)), paddingAndBorderAxisMain), dim[mainAxis]); } if (measureModeCrossDim == YGMeasureModeUndefined || - (node->getStyle().overflow() != YGOverflowScroll && + (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), + crossAxisParentSize, + parentWidth), dim[crossAxis]); } else if ( measureModeCrossDim == YGMeasureModeAtMost && - node->getStyle().overflow() == YGOverflowScroll) { + node->getStyle().overflow == YGOverflowScroll) { node->setLayoutMeasuredDimension( - YGFloatMax( - YGFloatMin( + fmaxf( + fminf( availableInnerCrossDim + paddingAndBorderAxisCross, YGNodeBoundAxisWithinMinAndMax( node, crossAxis, - YGFloatOptional{ - totalLineCrossDim + paddingAndBorderAxisCross}, - crossAxisownerSize) - .unwrap()), + totalLineCrossDim + paddingAndBorderAxisCross, + crossAxisParentSize)), 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) { + // 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() != YGPositionTypeAbsolute) { + if (child->getStyle().positionType == YGPositionTypeRelative) { child->setLayoutPosition( node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().position[pos[crossAxis]] - @@ -3542,43 +3053,30 @@ static void YGNodelayoutImpl( if (performLayout) { // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN for (auto child : node->getChildren()) { - if (child->getStyle().display() == YGDisplayNone || - child->getStyle().positionType() != YGPositionTypeAbsolute) { + if (child->getStyle().positionType != YGPositionTypeAbsolute) { continue; } - const bool absolutePercentageAgainstPaddingEdge = - node->getConfig()->isExperimentalFeatureEnabled( - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge); - YGNodeAbsoluteLayoutChild( node, child, - absolutePercentageAgainstPaddingEdge - ? node->getLayout().measuredDimensions[YGDimensionWidth] - : availableInnerWidth, + availableInnerWidth, isMainAxisRow ? measureModeMainDim : measureModeCrossDim, - absolutePercentageAgainstPaddingEdge - ? node->getLayout().measuredDimensions[YGDimensionHeight] - : availableInnerHeight, + availableInnerHeight, direction, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount); + config); } // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN - const bool needsMainTrailingPos = mainAxis == YGFlexDirectionRowReverse || - mainAxis == YGFlexDirectionColumnReverse; - const bool needsCrossTrailingPos = crossAxis == YGFlexDirectionRowReverse || - crossAxis == YGFlexDirectionColumnReverse; + 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) { + if (child->getStyle().display == YGDisplayNone) { continue; } if (needsMainTrailingPos) { @@ -3593,13 +3091,14 @@ static void YGNodelayoutImpl( } } +uint32_t gDepth = 0; +bool gPrintTree = false; bool gPrintChanges = false; bool gPrintSkips = false; -static const char* spacer = - " "; +static const char *spacer = " "; -static const char* YGSpacer(const unsigned long level) { +static const char *YGSpacer(const unsigned long level) { const size_t spacerLen = strlen(spacer); if (level > spacerLen) { return &spacer[0]; @@ -3608,216 +3107,163 @@ static const char* YGSpacer(const unsigned long level) { } } -static const char* YGMeasureModeName( - const YGMeasureMode mode, - const bool performLayout) { - constexpr auto N = enums::count(); - const char* kMeasureModeNames[N] = {"UNDEFINED", "EXACTLY", "AT_MOST"}; - const char* kLayoutModeNames[N] = { - "LAY_UNDEFINED", "LAY_EXACTLY", "LAY_AT_MOST"}; +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 >= N) { + 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 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 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)); +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)); } -YOGA_EXPORT float YGRoundValueToPixelGrid( - const double value, - const double pointScaleFactor, - const bool forceCeil, - const bool forceFloor) { - double scaledValue = value * pointScaleFactor; - // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue - // - fractial`. - double fractial = fmod(scaledValue, 1.0); - if (fractial < 0) { - // This branch is for handling negative numbers for `value`. - // - // Regarding `floor` and `ceil`. Note that for a number x, `floor(x) <= x <= - // ceil(x)` even for negative numbers. Here are a couple of examples: - // - x = 2.2: floor( 2.2) = 2, ceil( 2.2) = 3 - // - x = -2.2: floor(-2.2) = -3, ceil(-2.2) = -2 - // - // Regarding `fmodf`. For fractional negative numbers, `fmodf` returns a - // negative number. For example, `fmodf(-2.2) = -0.2`. However, we want - // `fractial` to be the number such that subtracting it from `value` will - // give us `floor(value)`. In the case of negative numbers, adding 1 to - // `fmodf(value)` gives us this. Let's continue the example from above: - // - fractial = fmodf(-2.2) = -0.2 - // - Add 1 to the fraction: fractial2 = fractial + 1 = -0.2 + 1 = 0.8 - // - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3 - ++fractial; - } - if (YGDoubleEqual(fractial, 0)) { +float YGRoundValueToPixelGrid(const float value, + const float pointScaleFactor, + const bool forceCeil, + const bool forceFloor) { + const float roundingError = fmax(0.0001, 0.01 * pointScaleFactor); + float scaledValue = value * pointScaleFactor; + float fractial = fmodf(scaledValue, 1.0); + if (YGFloatsEqualWithPrecision(fractial, 0.0, roundingError)) { // First we check if the value is already rounded scaledValue = scaledValue - fractial; - } else if (YGDoubleEqual(fractial, 1.0)) { + } else if (YGFloatsEqualWithPrecision(fractial, 1.0, roundingError)) { scaledValue = scaledValue - fractial + 1.0; } else if (forceCeil) { // Next we check if we need to use forced rounding - scaledValue = scaledValue - fractial + 1.0; + scaledValue = scaledValue - fractial + 1.0f; } else if (forceFloor) { scaledValue = scaledValue - fractial; } else { // Finally we just round the value scaledValue = scaledValue - fractial + - (!YGDoubleIsUndefined(fractial) && - (fractial > 0.5 || YGDoubleEqual(fractial, 0.5)) - ? 1.0 - : 0.0); - } - return (YGDoubleIsUndefined(scaledValue) || - YGDoubleIsUndefined(pointScaleFactor)) - ? YGUndefined - : (float) (scaledValue / pointScaleFactor); -} - -YOGA_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) { - if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) || - (!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) { + (fractial > 0.5f || YGFloatsEqualWithPrecision(fractial, 0.5f, roundingError) ? 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->getPointScaleFactor() != 0; - const float effectiveWidth = useRoundedComparison - ? YGRoundValueToPixelGrid( - width, config->getPointScaleFactor(), false, false) - : width; - const float effectiveHeight = useRoundedComparison - ? YGRoundValueToPixelGrid( - height, config->getPointScaleFactor(), false, false) - : height; - const float effectiveLastWidth = useRoundedComparison - ? YGRoundValueToPixelGrid( - lastWidth, config->getPointScaleFactor(), false, false) - : lastWidth; - const float effectiveLastHeight = useRoundedComparison - ? YGRoundValueToPixelGrid( - lastHeight, config->getPointScaleFactor(), false, false) - : lastHeight; - - const bool hasSameWidthSpec = lastWidthMode == widthMode && - YGFloatsEqual(effectiveLastWidth, effectiveWidth); - const bool hasSameHeightSpec = lastHeightMode == heightMode && - YGFloatsEqual(effectiveLastHeight, effectiveHeight); + 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) || + hasSameWidthSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(widthMode, + width - marginRow, + lastComputedWidth) || + YGMeasureModeOldSizeIsUnspecifiedAndStillFits(widthMode, + width - marginRow, + lastWidthMode, + lastComputedWidth) || YGMeasureModeNewMeasureSizeIsStricterAndStillValid( - widthMode, - width - marginRow, - lastWidthMode, - lastWidth, - lastComputedWidth); + widthMode, width - marginRow, lastWidthMode, lastWidth, lastComputedWidth); const bool heightIsCompatible = - hasSameHeightSpec || - YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize( - heightMode, height - marginColumn, lastComputedHeight) || - YGMeasureModeOldSizeIsUnspecifiedAndStillFits( - heightMode, - height - marginColumn, - lastHeightMode, - lastComputedHeight) || + hasSameHeightSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(heightMode, + height - marginColumn, + lastComputedHeight) || + YGMeasureModeOldSizeIsUnspecifiedAndStillFits(heightMode, + height - marginColumn, + lastHeightMode, + lastComputedHeight) || YGMeasureModeNewMeasureSizeIsStricterAndStillValid( - heightMode, - height - marginColumn, - lastHeightMode, - lastHeight, - lastComputedHeight); + 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. +// 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 LayoutPassReason reason, - const YGConfigRef config, - LayoutData& layoutMarkerData, - void* const layoutContext, - uint32_t depth, - const uint32_t generationCount) { +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->getLayout(); - depth++; + gDepth++; const bool needToVisitNode = - (node->isDirty() && layout->generationCount != generationCount) || - layout->lastOwnerDirection != ownerDirection; + (node->isDirty() && layout->generationCount != gCurrentGenerationCount) || + layout->lastParentDirection != parentDirection; if (needToVisitNode) { // Invalidate the cached results. layout->nextCachedMeasurementsIndex = 0; - layout->cachedLayout.availableWidth = -1; - layout->cachedLayout.availableHeight = -1; - layout->cachedLayout.widthMeasureMode = YGMeasureModeUndefined; - layout->cachedLayout.heightMeasureMode = YGMeasureModeUndefined; + layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1; + layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1; layout->cachedLayout.computedWidth = -1; layout->cachedLayout.computedHeight = -1; } @@ -3826,51 +3272,53 @@ bool YGLayoutNodeInternal( // Determine whether the results are already cached. We maintain a separate // cache for layouts and measurements. A layout operation modifies the - // positions and dimensions for nodes in the subtree. The algorithm assumes - // that each node gets laid out a maximum of one time per tree layout, but - // multiple measurements may be required to resolve all of the flex - // dimensions. We handle nodes with measure functions specially here because - // they are the most expensive to measure, so it's worth avoiding redundant - // measurements if at all possible. - if (node->hasMeasureFunc()) { + // 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 = - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap(); + node->getMarginForAxis(YGFlexDirectionRow, parentWidth); const float marginAxisColumn = - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap(); + node->getMarginForAxis(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)) { + 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)) { + 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; } @@ -3885,13 +3333,10 @@ bool YGLayoutNodeInternal( } } else { for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) { - if (YGFloatsEqual( - layout->cachedMeasurements[i].availableWidth, availableWidth) && - YGFloatsEqual( - layout->cachedMeasurements[i].availableHeight, availableHeight) && + if (YGFloatsEqual(layout->cachedMeasurements[i].availableWidth, availableWidth) && + YGFloatsEqual(layout->cachedMeasurements[i].availableHeight, availableHeight) && layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode && - layout->cachedMeasurements[i].heightMeasureMode == - heightMeasureMode) { + layout->cachedMeasurements[i].heightMeasureMode == heightMeasureMode) { cachedResults = &layout->cachedMeasurements[i]; break; } @@ -3900,25 +3345,16 @@ bool YGLayoutNodeInternal( if (!needToVisitNode && cachedResults != nullptr) { layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth; - layout->measuredDimensions[YGDimensionHeight] = - cachedResults->computedHeight; - - (performLayout ? layoutMarkerData.cachedLayouts - : layoutMarkerData.cachedMeasures) += 1; + layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight; if (gPrintChanges && gPrintSkips) { - Log::log( - node, - YGLogLevelVerbose, - nullptr, - "%s%d.{[skipped] ", - YGSpacer(depth), - depth); - node->print(layoutContext); - Log::log( + YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(gDepth), gDepth); + if (node->getPrintFunc() != nullptr) { + node->getPrintFunc()(node); + } + YGLog( node, YGLogLevelVerbose, - nullptr, "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n", YGMeasureModeName(widthMeasureMode, performLayout), YGMeasureModeName(heightMeasureMode, performLayout), @@ -3926,93 +3362,81 @@ bool YGLayoutNodeInternal( availableHeight, cachedResults->computedWidth, cachedResults->computedHeight, - LayoutPassReasonToString(reason)); + reason); } } else { if (gPrintChanges) { - Log::log( + YGLog( node, YGLogLevelVerbose, - nullptr, "%s%d.{%s", - YGSpacer(depth), - depth, + YGSpacer(gDepth), + gDepth, needToVisitNode ? "*" : ""); - node->print(layoutContext); - Log::log( + if (node->getPrintFunc() != nullptr) { + node->getPrintFunc()(node); + } + YGLog( node, YGLogLevelVerbose, - nullptr, "wm: %s, hm: %s, aw: %f ah: %f %s\n", YGMeasureModeName(widthMeasureMode, performLayout), YGMeasureModeName(heightMeasureMode, performLayout), availableWidth, availableHeight, - LayoutPassReasonToString(reason)); + reason); } - YGNodelayoutImpl( - node, - availableWidth, - availableHeight, - ownerDirection, - widthMeasureMode, - heightMeasureMode, - ownerWidth, - ownerHeight, - performLayout, - config, - layoutMarkerData, - layoutContext, - depth, - generationCount, - reason); + YGNodelayoutImpl(node, + availableWidth, + availableHeight, + parentDirection, + widthMeasureMode, + heightMeasureMode, + parentWidth, + parentHeight, + performLayout, + config); if (gPrintChanges) { - Log::log( + YGLog( node, YGLogLevelVerbose, - nullptr, "%s%d.}%s", - YGSpacer(depth), - depth, + YGSpacer(gDepth), + gDepth, needToVisitNode ? "*" : ""); - node->print(layoutContext); - Log::log( + if (node->getPrintFunc() != nullptr) { + node->getPrintFunc()(node); + } + YGLog( node, YGLogLevelVerbose, - nullptr, "wm: %s, hm: %s, d: (%f, %f) %s\n", YGMeasureModeName(widthMeasureMode, performLayout), YGMeasureModeName(heightMeasureMode, performLayout), layout->measuredDimensions[YGDimensionWidth], layout->measuredDimensions[YGDimensionHeight], - LayoutPassReasonToString(reason)); + reason); } - layout->lastOwnerDirection = ownerDirection; + layout->lastParentDirection = parentDirection; if (cachedResults == nullptr) { - if (layout->nextCachedMeasurementsIndex + 1 > - (uint32_t) layoutMarkerData.maxMeasureCache) { - layoutMarkerData.maxMeasureCache = - layout->nextCachedMeasurementsIndex + 1; - } if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) { if (gPrintChanges) { - Log::log(node, YGLogLevelVerbose, nullptr, "Out of cache entries!\n"); + YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n"); } layout->nextCachedMeasurementsIndex = 0; } - YGCachedMeasurement* newCacheEntry; + 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]; + newCacheEntry = &layout->cachedMeasurements[layout->nextCachedMeasurementsIndex]; layout->nextCachedMeasurementsIndex++; } @@ -4020,10 +3444,8 @@ bool YGLayoutNodeInternal( newCacheEntry->availableHeight = availableHeight; newCacheEntry->widthMeasureMode = widthMeasureMode; newCacheEntry->heightMeasureMode = heightMeasureMode; - newCacheEntry->computedWidth = - layout->measuredDimensions[YGDimensionWidth]; - newCacheEntry->computedHeight = - layout->measuredDimensions[YGDimensionHeight]; + newCacheEntry->computedWidth = layout->measuredDimensions[YGDimensionWidth]; + newCacheEntry->computedHeight = layout->measuredDimensions[YGDimensionHeight]; } } @@ -4039,66 +3461,45 @@ bool YGLayoutNodeInternal( node->setDirty(false); } - layout->generationCount = generationCount; - - LayoutType layoutType; - if (performLayout) { - layoutType = !needToVisitNode && cachedResults == &layout->cachedLayout - ? LayoutType::kCachedLayout - : LayoutType::kLayout; - } else { - layoutType = cachedResults != nullptr ? LayoutType::kCachedMeasure - : LayoutType::kMeasure; - } - Event::publish(node, {layoutType, layoutContext}); - + gDepth--; + layout->generationCount = gCurrentGenerationCount; return (needToVisitNode || cachedResults == nullptr); } -YOGA_EXPORT void YGConfigSetPointScaleFactor( - const YGConfigRef config, - const float pixelsInPoint) { - YGAssertWithConfig( - config, - pixelsInPoint >= 0.0f, - "Scale factor should not be less than zero"); +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->setPointScaleFactor(0.0f); + config->pointScaleFactor = 0.0f; } else { - config->setPointScaleFactor(pixelsInPoint); + config->pointScaleFactor = pixelsInPoint; } } -YOGA_EXPORT float YGConfigGetPointScaleFactor(const YGConfigRef config) { - return config->getPointScaleFactor(); -} - -static void YGRoundToPixelGrid( - const YGNodeRef node, - const double pointScaleFactor, - const double absoluteLeft, - const double absoluteTop) { +static void YGRoundToPixelGrid(const YGNodeRef node, + const float pointScaleFactor, + const float absoluteLeft, + const float absoluteTop) { if (pointScaleFactor == 0.0f) { return; } - const double nodeLeft = node->getLayout().position[YGEdgeLeft]; - const double nodeTop = node->getLayout().position[YGEdgeTop]; + const float nodeLeft = node->getLayout().position[YGEdgeLeft]; + const float nodeTop = node->getLayout().position[YGEdgeTop]; - const double nodeWidth = node->getLayout().dimensions[YGDimensionWidth]; - const double nodeHeight = node->getLayout().dimensions[YGDimensionHeight]; + const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth]; + const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight]; - const double absoluteNodeLeft = absoluteLeft + nodeLeft; - const double absoluteNodeTop = absoluteTop + nodeTop; + const float absoluteNodeLeft = absoluteLeft + nodeLeft; + const float absoluteNodeTop = absoluteTop + nodeTop; - const double absoluteNodeRight = absoluteNodeLeft + nodeWidth; - const double absoluteNodeBottom = absoluteNodeTop + nodeHeight; + 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. + // 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( @@ -4109,15 +3510,13 @@ static void YGRoundToPixelGrid( 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 = - !YGDoubleEqual(fmod(nodeWidth * pointScaleFactor, 1.0), 0) && - !YGDoubleEqual(fmod(nodeWidth * pointScaleFactor, 1.0), 1.0); - const bool hasFractionalHeight = - !YGDoubleEqual(fmod(nodeHeight * pointScaleFactor, 1.0), 0) && - !YGDoubleEqual(fmod(nodeHeight * pointScaleFactor, 1.0), 1.0); + // 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( @@ -4141,206 +3540,232 @@ static void YGRoundToPixelGrid( const uint32_t childCount = YGNodeGetChildCount(node); for (uint32_t i = 0; i < childCount; i++) { - YGRoundToPixelGrid( - YGNodeGetChild(node, i), - pointScaleFactor, - absoluteNodeLeft, - absoluteNodeTop); + YGRoundToPixelGrid(YGNodeGetChild(node, i), pointScaleFactor, absoluteNodeLeft, absoluteNodeTop); } } -YOGA_EXPORT void YGNodeCalculateLayoutWithContext( - const YGNodeRef node, - const float ownerWidth, - const float ownerHeight, - const YGDirection ownerDirection, - void* layoutContext) { - - Event::publish(node, {layoutContext}); - LayoutData markerData = {}; - +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.fetch_add(1, std::memory_order_relaxed); + // 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; - const auto& maxDimensions = node->getStyle().maxDimensions(); - if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) { + if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, parentWidth)) { width = - (YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) + - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)) - .unwrap(); + YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth) + + node->getMarginForAxis(YGFlexDirectionRow, parentWidth); widthMeasureMode = YGMeasureModeExactly; - } else if (!YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth) - .isUndefined()) { - width = - YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth).unwrap(); + } else if ( + YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) >= + 0.0f) { + width = YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], parentWidth); widthMeasureMode = YGMeasureModeAtMost; } else { - width = ownerWidth; - widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined - : YGMeasureModeExactly; + width = parentWidth; + widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined : YGMeasureModeExactly; } float height = YGUndefined; YGMeasureMode heightMeasureMode = YGMeasureModeUndefined; - if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) { - height = (YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionColumn]), - ownerHeight) + - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)) - .unwrap(); + if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, parentHeight)) { + height = YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionColumn]), + parentHeight) + + node->getMarginForAxis(YGFlexDirectionColumn, parentWidth); heightMeasureMode = YGMeasureModeExactly; - } else if (!YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight) - .isUndefined()) { - height = - YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight).unwrap(); + } else if ( + YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], parentHeight) >= + 0.0f) { + height = YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], parentHeight); heightMeasureMode = YGMeasureModeAtMost; } else { - height = ownerHeight; - heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined - : YGMeasureModeExactly; + height = parentHeight; + heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined : YGMeasureModeExactly; } + if (YGLayoutNodeInternal( node, width, height, - ownerDirection, + parentDirection, widthMeasureMode, heightMeasureMode, - ownerWidth, - ownerHeight, + parentWidth, + parentHeight, true, - LayoutPassReason::kInitial, - node->getConfig(), - markerData, - layoutContext, - 0, // tree root - gCurrentGenerationCount.load(std::memory_order_relaxed))) { + "initial", + node->getConfig())) { node->setPosition( - node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth); - YGRoundToPixelGrid( - node, node->getConfig()->getPointScaleFactor(), 0.0f, 0.0f); + node->getLayout().direction, parentWidth, parentHeight, parentWidth); + YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f); -#ifdef DEBUG - if (node->getConfig()->shouldPrintTree()) { + if (gPrintTree) { YGNodePrint( node, - (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); + (YGPrintOptions)( + YGPrintOptionsLayout | YGPrintOptionsChildren | + YGPrintOptionsStyle)); } -#endif } - Event::publish(node, {layoutContext, &markerData}); -} - -YOGA_EXPORT void YGNodeCalculateLayout( - const YGNodeRef node, - const float ownerWidth, - const float ownerHeight, - const YGDirection ownerDirection) { - YGNodeCalculateLayoutWithContext( - node, ownerWidth, ownerHeight, ownerDirection, nullptr); + // 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, + parentDirection, + widthMeasureMode, + heightMeasureMode, + parentWidth, + parentHeight, + true, + "initial", + originalNode->getConfig())) { + originalNode->setPosition( + originalNode->getLayout().direction, + parentWidth, + parentHeight, + parentWidth); + YGRoundToPixelGrid( + originalNode, + originalNode->getConfig()->pointScaleFactor, + 0.0f, + 0.0f); + + // Set whether the two layouts are different or not. + node->setLayoutDoesLegacyFlagAffectsLayout( + !originalNode->isLayoutTreeEqualToNode(*node)); + + if (gPrintTree) { + YGNodePrint( + originalNode, + (YGPrintOptions)( + YGPrintOptionsLayout | YGPrintOptionsChildren | + YGPrintOptionsStyle)); + } + } + YGConfigFreeRecursive(originalNode); + YGNodeFreeRecursive(originalNode); + } } -YOGA_EXPORT void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { +void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { if (logger != nullptr) { - config->setLogger(logger); + config->logger = logger; } else { #ifdef ANDROID - config->setLogger(&YGAndroidLog); + config->logger = &YGAndroidLog; #else - config->setLogger(&YGDefaultLog); + config->logger = &YGDefaultLog; #endif } } -void YGAssert(const bool condition, const char* message) { - if (!condition) { - Log::log(YGNodeRef{nullptr}, YGLogLevelFatal, nullptr, "%s\n", message); - throwLogicalErrorWithMessage(message); +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 YGAssertWithNode( - const YGNodeRef node, - const bool condition, - const char* message) { +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) { - Log::log(node, YGLogLevelFatal, nullptr, "%s\n", message); - throwLogicalErrorWithMessage(message); + YGLog(nullptr, YGLogLevelFatal, "%s\n", message); } } -void YGAssertWithConfig( - const YGConfigRef config, - const bool condition, - const char* message) { +void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message) { if (!condition) { - Log::log(config, YGLogLevelFatal, nullptr, "%s\n", message); - throwLogicalErrorWithMessage(message); + YGLog(node, YGLogLevelFatal, "%s\n", message); } } -YOGA_EXPORT void YGConfigSetExperimentalFeatureEnabled( - const YGConfigRef config, - const YGExperimentalFeature feature, - const bool enabled) { - config->setExperimentalFeatureEnabled(feature, enabled); +void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message) { + if (!condition) { + YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message); + } } -YOGA_EXPORT bool YGConfigIsExperimentalFeatureEnabled( - const YGConfigRef config, - const YGExperimentalFeature feature) { - return config->isExperimentalFeatureEnabled(feature); +void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config, + const YGExperimentalFeature feature, + const bool enabled) { + config->experimentalFeatures[feature] = enabled; } -YOGA_EXPORT void YGConfigSetUseWebDefaults( - const YGConfigRef config, - const bool enabled) { - config->setUseWebDefaults(enabled); +inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config, + const YGExperimentalFeature feature) { + return config->experimentalFeatures[feature]; } -YOGA_EXPORT bool YGConfigGetUseLegacyStretchBehaviour( - const YGConfigRef config) { - return config->hasErrata(YGErrataStretchFlexBasis); +void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) { + config->useWebDefaults = enabled; } -YOGA_EXPORT void YGConfigSetUseLegacyStretchBehaviour( - const YGConfigRef config, - const bool useLegacyStretchBehaviour) { - if (useLegacyStretchBehaviour) { - config->addErrata(YGErrataStretchFlexBasis); - } else { - config->removeErrata(YGErrataStretchFlexBasis); - } +void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config, + const bool useLegacyStretchBehaviour) { + config->useLegacyStretchBehaviour = useLegacyStretchBehaviour; } bool YGConfigGetUseWebDefaults(const YGConfigRef config) { - return config->useWebDefaults(); -} - -YOGA_EXPORT void YGConfigSetContext(const YGConfigRef config, void* context) { - config->setContext(context); -} - -YOGA_EXPORT void* YGConfigGetContext(const YGConfigRef config) { - return config->getContext(); + return config->useWebDefaults; } -YOGA_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata) { - config->setErrata(errata); +void YGConfigSetContext(const YGConfigRef config, void *context) { + config->context = context; } -YOGA_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config) { - return config->getErrata(); +void *YGConfigGetContext(const YGConfigRef config) { + return config->context; } -YOGA_EXPORT void YGConfigSetCloneNodeFunc( - const YGConfigRef config, - const YGCloneNodeFunc callback) { - config->setCloneNodeCallback(callback); +void YGConfigSetNodeClonedFunc(const YGConfigRef config, const YGNodeClonedFunc callback) { + config->cloneNodeCallback = callback; } diff --git a/Sources/yoga/event/event.cpp b/Sources/yoga/event/event.cpp deleted file mode 100644 index 152c4e16..00000000 --- a/Sources/yoga/event/event.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "event.h" -#include -#include - -namespace facebook { -namespace yoga { - -const char* LayoutPassReasonToString(const LayoutPassReason value) { - switch (value) { - case LayoutPassReason::kInitial: - return "initial"; - case LayoutPassReason::kAbsLayout: - return "abs_layout"; - case LayoutPassReason::kStretch: - return "stretch"; - case LayoutPassReason::kMultilineStretch: - return "multiline_stretch"; - case LayoutPassReason::kFlexLayout: - return "flex_layout"; - case LayoutPassReason::kMeasureChild: - return "measure"; - case LayoutPassReason::kAbsMeasureChild: - return "abs_measure"; - case LayoutPassReason::kFlexMeasure: - return "flex_measure"; - default: - return "unknown"; - } -} - -namespace { - -struct Node { - std::function subscriber = nullptr; - Node* next = nullptr; - - Node(std::function&& subscriber) - : subscriber{std::move(subscriber)} {} -}; - -std::atomic subscribers{nullptr}; - -Node* push(Node* newHead) { - Node* oldHead; - do { - oldHead = subscribers.load(std::memory_order_relaxed); - if (newHead != nullptr) { - newHead->next = oldHead; - } - } while (!subscribers.compare_exchange_weak( - oldHead, newHead, std::memory_order_release, std::memory_order_relaxed)); - return oldHead; -} - -} // namespace - -void Event::reset() { - auto head = push(nullptr); - while (head != nullptr) { - auto current = head; - head = head->next; - delete current; - } -} - -void Event::subscribe(std::function&& subscriber) { - push(new Node{std::move(subscriber)}); -} - -void Event::publish(const YGNode& node, Type eventType, const Data& eventData) { - for (auto subscriber = subscribers.load(std::memory_order_relaxed); - subscriber != nullptr; - subscriber = subscriber->next) { - subscriber->subscriber(node, eventType, eventData); - } -} - -} // namespace yoga -} // namespace facebook diff --git a/Sources/yoga/event/event.h b/Sources/yoga/event/event.h deleted file mode 100644 index de15648f..00000000 --- a/Sources/yoga/event/event.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include -#include -#include "YGEnums.h" - -struct YGConfig; -struct YGNode; - -namespace facebook { -namespace yoga { - -enum struct LayoutType : int { - kLayout = 0, - kMeasure = 1, - kCachedLayout = 2, - kCachedMeasure = 3 -}; - -enum struct LayoutPassReason : int { - kInitial = 0, - kAbsLayout = 1, - kStretch = 2, - kMultilineStretch = 3, - kFlexLayout = 4, - kMeasureChild = 5, - kAbsMeasureChild = 6, - kFlexMeasure = 7, - COUNT -}; - -struct LayoutData { - int layouts; - int measures; - int maxMeasureCache; - int cachedLayouts; - int cachedMeasures; - int measureCallbacks; - std::array(LayoutPassReason::COUNT)> - measureCallbackReasonsCount; -}; - -const char* LayoutPassReasonToString(const LayoutPassReason value); - -struct YOGA_EXPORT Event { - enum Type { - NodeAllocation, - NodeDeallocation, - NodeLayout, - LayoutPassStart, - LayoutPassEnd, - MeasureCallbackStart, - MeasureCallbackEnd, - NodeBaselineStart, - NodeBaselineEnd, - }; - class Data; - using Subscriber = void(const YGNode&, Type, Data); - using Subscribers = std::vector>; - - template - struct TypedData {}; - - class Data { - const void* data_; - - public: - template - Data(const TypedData& data) : data_{&data} {} - - template - const TypedData& get() const { - return *static_cast*>(data_); - } - }; - - static void reset(); - - static void subscribe(std::function&& subscriber); - - template - static void publish(const YGNode& node, const TypedData& eventData = {}) { - publish(node, E, Data{eventData}); - } - - template - static void publish(const YGNode* node, const TypedData& eventData = {}) { - publish(*node, eventData); - } - -private: - static void publish(const YGNode&, Type, const Data&); -}; - -template <> -struct Event::TypedData { - YGConfig* config; -}; - -template <> -struct Event::TypedData { - YGConfig* config; -}; - -template <> -struct Event::TypedData { - void* layoutContext; -}; - -template <> -struct Event::TypedData { - void* layoutContext; - LayoutData* layoutData; -}; - -template <> -struct Event::TypedData { - void* layoutContext; - float width; - YGMeasureMode widthMeasureMode; - float height; - YGMeasureMode heightMeasureMode; - float measuredWidth; - float measuredHeight; - const LayoutPassReason reason; -}; - -template <> -struct Event::TypedData { - LayoutType layoutType; - void* layoutContext; -}; - -} // namespace yoga -} // namespace facebook diff --git a/Sources/yoga/include/yoga/YGEnums.h b/Sources/yoga/include/yoga/YGEnums.h index d34f7aa2..0976d78d 100644 --- a/Sources/yoga/include/yoga/YGEnums.h +++ b/Sources/yoga/include/yoga/YGEnums.h @@ -1,145 +1,155 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -// @generated by enums.py - #pragma once -#include "YGMacros.h" - -// clang-format off +#include "YGMacros.h" YG_EXTERN_C_BEGIN -YG_ENUM_SEQ_DECL( - YGAlign, - YGAlignAuto, - YGAlignFlexStart, - YGAlignCenter, - YGAlignFlexEnd, - YGAlignStretch, - YGAlignBaseline, - YGAlignSpaceBetween, - YGAlignSpaceAround) - -YG_ENUM_SEQ_DECL( - YGDimension, - YGDimensionWidth, - YGDimensionHeight) - -YG_ENUM_SEQ_DECL( - YGDirection, - YGDirectionInherit, - YGDirectionLTR, - YGDirectionRTL) - -YG_ENUM_SEQ_DECL( - YGDisplay, - YGDisplayFlex, - YGDisplayNone) - -YG_ENUM_SEQ_DECL( - YGEdge, - YGEdgeLeft, - YGEdgeTop, - YGEdgeRight, - YGEdgeBottom, - YGEdgeStart, - YGEdgeEnd, - YGEdgeHorizontal, - YGEdgeVertical, - YGEdgeAll) - -YG_ENUM_DECL( - YGErrata, - YGErrataNone = 0, - YGErrataStretchFlexBasis = 1, - YGErrataAll = 2147483647, - YGErrataClassic = 2147483646) -YG_DEFINE_ENUM_FLAG_OPERATORS(YGErrata) - -YG_ENUM_SEQ_DECL( - YGExperimentalFeature, - YGExperimentalFeatureWebFlexBasis, - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge, - YGExperimentalFeatureFixJNILocalRefOverflows) - -YG_ENUM_SEQ_DECL( - YGFlexDirection, - YGFlexDirectionColumn, - YGFlexDirectionColumnReverse, - YGFlexDirectionRow, - YGFlexDirectionRowReverse) - -YG_ENUM_SEQ_DECL( - YGGutter, - YGGutterColumn, - YGGutterRow, - YGGutterAll) - -YG_ENUM_SEQ_DECL( - YGJustify, +#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_SEQ_DECL( - YGLogLevel, - YGLogLevelError, - YGLogLevelWarn, - YGLogLevelInfo, - YGLogLevelDebug, - YGLogLevelVerbose, - YGLogLevelFatal) - -YG_ENUM_SEQ_DECL( - YGMeasureMode, - YGMeasureModeUndefined, - YGMeasureModeExactly, - YGMeasureModeAtMost) - -YG_ENUM_SEQ_DECL( - YGNodeType, - YGNodeTypeDefault, - YGNodeTypeText) - -YG_ENUM_SEQ_DECL( - YGOverflow, - YGOverflowVisible, - YGOverflowHidden, - YGOverflowScroll) - -YG_ENUM_SEQ_DECL( - YGPositionType, - YGPositionTypeStatic, - YGPositionTypeRelative, - YGPositionTypeAbsolute) - -YG_ENUM_DECL( - YGPrintOptions, - YGPrintOptionsLayout = 1, - YGPrintOptionsStyle = 2, - YGPrintOptionsChildren = 4) -YG_DEFINE_ENUM_FLAG_OPERATORS(YGPrintOptions) - -YG_ENUM_SEQ_DECL( - YGUnit, - YGUnitUndefined, - YGUnitPoint, - YGUnitPercent, - YGUnitAuto) - -YG_ENUM_SEQ_DECL( - YGWrap, - YGWrapNoWrap, - YGWrapWrap, - YGWrapWrapReverse) + YGJustifySpaceEvenly, +} YG_ENUM_END(YGJustify); +WIN_EXPORT const char *YGJustifyToString(const YGJustify value); + +#define YGLogLevelCount 6 +typedef YG_ENUM_BEGIN(YGLogLevel) { + YGLogLevelError, + YGLogLevelWarn, + YGLogLevelInfo, + YGLogLevelDebug, + YGLogLevelVerbose, + YGLogLevelFatal, +} YG_ENUM_END(YGLogLevel); +WIN_EXPORT const char *YGLogLevelToString(const YGLogLevel value); + +#define YGMeasureModeCount 3 +typedef YG_ENUM_BEGIN(YGMeasureMode) { + YGMeasureModeUndefined, + YGMeasureModeExactly, + YGMeasureModeAtMost, +} YG_ENUM_END(YGMeasureMode); +WIN_EXPORT const char *YGMeasureModeToString(const YGMeasureMode value); + +#define YGNodeTypeCount 2 +typedef YG_ENUM_BEGIN(YGNodeType) { + YGNodeTypeDefault, + YGNodeTypeText, +} YG_ENUM_END(YGNodeType); +WIN_EXPORT const char *YGNodeTypeToString(const YGNodeType value); + +#define YGOverflowCount 3 +typedef YG_ENUM_BEGIN(YGOverflow) { + YGOverflowVisible, + YGOverflowHidden, + YGOverflowScroll, +} YG_ENUM_END(YGOverflow); +WIN_EXPORT const char *YGOverflowToString(const YGOverflow value); + +#define YGPositionTypeCount 2 +typedef YG_ENUM_BEGIN(YGPositionType) { + YGPositionTypeRelative, + YGPositionTypeAbsolute, +} YG_ENUM_END(YGPositionType); +WIN_EXPORT const char *YGPositionTypeToString(const YGPositionType value); + +#define YGPrintOptionsCount 3 +typedef YG_ENUM_BEGIN(YGPrintOptions) { + YGPrintOptionsLayout = 1, + YGPrintOptionsStyle = 2, + YGPrintOptionsChildren = 4, +} YG_ENUM_END(YGPrintOptions); +WIN_EXPORT const char *YGPrintOptionsToString(const YGPrintOptions value); + +#define YGUnitCount 4 +typedef YG_ENUM_BEGIN(YGUnit) { + YGUnitUndefined, + YGUnitPoint, + YGUnitPercent, + YGUnitAuto, +} YG_ENUM_END(YGUnit); +WIN_EXPORT const char *YGUnitToString(const YGUnit value); + +#define YGWrapCount 3 +typedef YG_ENUM_BEGIN(YGWrap) { + YGWrapNoWrap, + YGWrapWrap, + YGWrapWrapReverse, +} YG_ENUM_END(YGWrap); +WIN_EXPORT const char *YGWrapToString(const YGWrap value); YG_EXTERN_C_END diff --git a/Sources/yoga/include/yoga/YGMacros.h b/Sources/yoga/include/yoga/YGMacros.h index cd137117..15ed81d3 100644 --- a/Sources/yoga/include/yoga/YGMacros.h +++ b/Sources/yoga/include/yoga/YGMacros.h @@ -1,5 +1,5 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -7,10 +7,6 @@ #pragma once -#ifdef __cplusplus -#include -#endif - #ifdef __cplusplus #define YG_EXTERN_C_BEGIN extern "C" { #define YG_EXTERN_C_END } @@ -19,120 +15,27 @@ #define YG_EXTERN_C_END #endif -#if defined(__cplusplus) -#define YG_DEPRECATED(message) [[deprecated(message)]] -#elif defined(_MSC_VER) -#define YG_DEPRECATED(message) __declspec(deprecated(message)) -#else -#define YG_DEPRECATED(message) __attribute__((deprecated(message))) -#endif - #ifdef _WINDLL #define WIN_EXPORT __declspec(dllexport) #else #define WIN_EXPORT #endif -#ifndef YOGA_EXPORT -#ifdef _MSC_VER -#define YOGA_EXPORT +#ifdef WINARMDLL +#define WIN_STRUCT(type) type * +#define WIN_STRUCT_REF(value) &value #else -#define YOGA_EXPORT __attribute__((visibility("default"))) -#endif +#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 mismatch for the Yoga ABI. +// 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 - -#ifdef __cplusplus -#define YG_DEFINE_ENUM_FLAG_OPERATORS(name) \ - extern "C++" { \ - constexpr inline name operator~(name a) { \ - return static_cast( \ - ~static_cast::type>(a)); \ - } \ - constexpr inline name operator|(name a, name b) { \ - return static_cast( \ - static_cast::type>(a) | \ - static_cast::type>(b)); \ - } \ - constexpr inline name operator&(name a, name b) { \ - return static_cast( \ - static_cast::type>(a) & \ - static_cast::type>(b)); \ - } \ - constexpr inline name operator^(name a, name b) { \ - return static_cast( \ - static_cast::type>(a) ^ \ - static_cast::type>(b)); \ - } \ - inline name& operator|=(name& a, name b) { \ - return reinterpret_cast( \ - reinterpret_cast::type&>(a) |= \ - static_cast::type>(b)); \ - } \ - inline name& operator&=(name& a, name b) { \ - return reinterpret_cast( \ - reinterpret_cast::type&>(a) &= \ - static_cast::type>(b)); \ - } \ - inline name& operator^=(name& a, name b) { \ - return reinterpret_cast( \ - reinterpret_cast::type&>(a) ^= \ - static_cast::type>(b)); \ - } \ - } -#else -#define YG_DEFINE_ENUM_FLAG_OPERATORS(name) -#endif - -#ifdef __cplusplus -namespace facebook { -namespace yoga { -namespace enums { - -template -constexpr int count(); // can't use `= delete` due to a defect in clang < 3.9 - -namespace detail { -template -constexpr int n() { - return sizeof...(xs); -} -} // namespace detail - -} // namespace enums -} // namespace yoga -} // namespace facebook -#endif - -#define YG_ENUM_DECL(NAME, ...) \ - typedef YG_ENUM_BEGIN(NAME){__VA_ARGS__} YG_ENUM_END(NAME); \ - WIN_EXPORT const char* NAME##ToString(NAME); - -#ifdef __cplusplus -#define YG_ENUM_SEQ_DECL(NAME, ...) \ - YG_ENUM_DECL(NAME, __VA_ARGS__) \ - YG_EXTERN_C_END \ - namespace facebook { \ - namespace yoga { \ - namespace enums { \ - template <> \ - constexpr int count() { \ - return detail::n<__VA_ARGS__>(); \ - } \ - } \ - } \ - } \ - YG_EXTERN_C_BEGIN -#else -#define YG_ENUM_SEQ_DECL YG_ENUM_DECL -#endif diff --git a/Sources/yoga/include/yoga/YGValue.h b/Sources/yoga/include/yoga/YGValue.h deleted file mode 100644 index a4f89f3b..00000000 --- a/Sources/yoga/include/yoga/YGValue.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "YGEnums.h" -#include "YGMacros.h" - -YG_EXTERN_C_BEGIN - -typedef struct YGValue { - float value; - YGUnit unit; -} YGValue; - -YOGA_EXPORT extern const YGValue YGValueAuto; -YOGA_EXPORT extern const YGValue YGValueUndefined; -YOGA_EXPORT extern const YGValue YGValueZero; - -YG_EXTERN_C_END - -#ifdef __cplusplus -#include -constexpr float YGUndefined = std::numeric_limits::quiet_NaN(); -#else -#include -#define YGUndefined NAN -#endif - -#ifdef __cplusplus -inline bool operator==(const YGValue& lhs, const YGValue& rhs) { - if (lhs.unit != rhs.unit) { - return false; - } - - switch (lhs.unit) { - case YGUnitUndefined: - case YGUnitAuto: - return true; - case YGUnitPoint: - case YGUnitPercent: - return lhs.value == rhs.value; - } - - return false; -} - -inline bool operator!=(const YGValue& lhs, const YGValue& rhs) { - return !(lhs == rhs); -} - -inline YGValue operator-(const YGValue& value) { - return {-value.value, value.unit}; -} -#endif diff --git a/Sources/yoga/include/yoga/Yoga.h b/Sources/yoga/include/yoga/Yoga.h index 81a01a67..689f9f3e 100644 --- a/Sources/yoga/include/yoga/Yoga.h +++ b/Sources/yoga/include/yoga/Yoga.h @@ -1,5 +1,5 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. +/** + * Copyright (c) 2014-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -18,9 +18,16 @@ #include #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" -#include "YGValue.h" YG_EXTERN_C_BEGIN @@ -29,353 +36,262 @@ typedef struct YGSize { float height; } YGSize; -typedef struct YGConfig* YGConfigRef; +typedef struct YGValue { + float value; + YGUnit unit; +} YGValue; + +extern const YGValue YGValueUndefined; +extern const YGValue YGValueAuto; + +typedef struct YGConfig *YGConfigRef; typedef struct YGNode* YGNodeRef; -typedef const struct YGNode* YGNodeConstRef; - -typedef YGSize (*YGMeasureFunc)( - YGNodeRef node, - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode); -typedef float (*YGBaselineFunc)(YGNodeRef node, float width, float height); + +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 void (*YGNodeCleanupFunc)(YGNodeRef node); -typedef int (*YGLogger)( - YGConfigRef config, - YGNodeRef node, - YGLogLevel level, - const char* format, - va_list args); -typedef YGNodeRef ( - *YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex); +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(YGConfigRef config); -WIN_EXPORT YGNodeRef YGNodeClone(YGNodeRef node); -WIN_EXPORT void YGNodeFree(YGNodeRef node); -WIN_EXPORT void YGNodeFreeRecursiveWithCleanupFunc( - YGNodeRef node, - YGNodeCleanupFunc cleanup); -WIN_EXPORT void YGNodeFreeRecursive(YGNodeRef node); -WIN_EXPORT void YGNodeReset(YGNodeRef node); - -WIN_EXPORT void YGNodeInsertChild( - YGNodeRef node, - YGNodeRef child, - uint32_t index); - -WIN_EXPORT void YGNodeSwapChild( - YGNodeRef node, - YGNodeRef child, - uint32_t index); - -WIN_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child); -WIN_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node); -WIN_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index); -WIN_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node); -WIN_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node); -WIN_EXPORT uint32_t YGNodeGetChildCount(YGNodeRef node); -WIN_EXPORT void YGNodeSetChildren( - YGNodeRef owner, - const YGNodeRef* children, - uint32_t count); - -WIN_EXPORT void YGNodeSetIsReferenceBaseline( - YGNodeRef node, - bool isReferenceBaseline); - -WIN_EXPORT bool YGNodeIsReferenceBaseline(YGNodeRef node); - -WIN_EXPORT void YGNodeCalculateLayout( - YGNodeRef node, - float availableWidth, - float availableHeight, - YGDirection ownerDirection); +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. -// -// Yoga knows when to mark all other nodes as dirty but because nodes with -// measure functions depend on information not known to Yoga they must perform -// this dirty marking manually. -WIN_EXPORT void YGNodeMarkDirty(YGNodeRef node); - -// Marks the current node and all its descendants as dirty. -// -// Intended to be used for Yoga benchmarks. Don't use in production, as calling -// `YGCalculateLayout` will cause the recalculation of each and every node. -WIN_EXPORT void YGNodeMarkDirtyAndPropagateToDescendants(YGNodeRef node); - -WIN_EXPORT void YGNodePrint(YGNodeRef node, YGPrintOptions options); - -WIN_EXPORT bool YGFloatIsUndefined(float value); - -WIN_EXPORT bool YGNodeCanUseCachedMeasurement( - YGMeasureMode widthMode, - float width, - YGMeasureMode heightMode, - float height, - YGMeasureMode lastWidthMode, - float lastWidth, - YGMeasureMode lastHeightMode, - float lastHeight, - float lastComputedWidth, - float lastComputedHeight, - float marginRow, - float marginColumn, - YGConfigRef config); - -WIN_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeRef srcNode); - -WIN_EXPORT void* YGNodeGetContext(YGNodeRef node); -WIN_EXPORT void YGNodeSetContext(YGNodeRef node, void* context); - -WIN_EXPORT YGConfigRef YGNodeGetConfig(YGNodeRef node); -WIN_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config); - -void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled); -bool YGNodeHasMeasureFunc(YGNodeRef node); -WIN_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc); -bool YGNodeHasBaselineFunc(YGNodeRef node); +// 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); + +#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); + +void* YGNodeGetContext(YGNodeRef node); +void YGNodeSetContext(YGNodeRef node, void* context); +YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node); +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); -WIN_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node); -WIN_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout); +bool YGNodeGetHasNewLayout(YGNodeRef node); +void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout); YGNodeType YGNodeGetNodeType(YGNodeRef node); void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType); -WIN_EXPORT bool YGNodeIsDirty(YGNodeRef node); - -WIN_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction); -WIN_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetFlexDirection( - YGNodeRef node, - YGFlexDirection flexDirection); -WIN_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetJustifyContent( - YGNodeRef node, - YGJustify justifyContent); -WIN_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetAlignContent( - YGNodeRef node, - YGAlign alignContent); -WIN_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems); -WIN_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf); -WIN_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetPositionType( - YGNodeRef node, - YGPositionType positionType); -WIN_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap); -WIN_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow); -WIN_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display); -WIN_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex); -WIN_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow); -WIN_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink); -WIN_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis); -WIN_EXPORT void YGNodeStyleSetFlexBasisPercent(YGNodeRef node, float flexBasis); -WIN_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node); -WIN_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetPosition( - YGNodeRef node, - YGEdge edge, - float position); -WIN_EXPORT void YGNodeStyleSetPositionPercent( - YGNodeRef node, - YGEdge edge, - float position); -WIN_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge); - -WIN_EXPORT void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float margin); -WIN_EXPORT void YGNodeStyleSetMarginPercent( - YGNodeRef node, - YGEdge edge, - float margin); -WIN_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge); -WIN_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge); - -WIN_EXPORT void YGNodeStyleSetPadding( - YGNodeRef node, - YGEdge edge, - float padding); -WIN_EXPORT void YGNodeStyleSetPaddingPercent( - YGNodeRef node, - YGEdge edge, - float padding); -WIN_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge); - -WIN_EXPORT void YGNodeStyleSetBorder(YGNodeRef node, YGEdge edge, float border); -WIN_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge); - -WIN_EXPORT void YGNodeStyleSetGap( - YGNodeRef node, - YGGutter gutter, - float gapLength); -WIN_EXPORT float YGNodeStyleGetGap(YGNodeConstRef node, YGGutter gutter); - -WIN_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width); -WIN_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width); -WIN_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node); -WIN_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height); -WIN_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height); -WIN_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node); -WIN_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth); -WIN_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth); -WIN_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight); -WIN_EXPORT void YGNodeStyleSetMinHeightPercent(YGNodeRef node, float minHeight); -WIN_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth); -WIN_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth); -WIN_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node); - -WIN_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight); -WIN_EXPORT void YGNodeStyleSetMaxHeightPercent(YGNodeRef node, float maxHeight); -WIN_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef 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. +bool YGNodeIsDirty(YGNodeRef node); +bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node); + +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 +// - 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(YGNodeRef node, float aspectRatio); -WIN_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node); - -WIN_EXPORT float YGNodeLayoutGetLeft(YGNodeRef node); -WIN_EXPORT float YGNodeLayoutGetTop(YGNodeRef node); -WIN_EXPORT float YGNodeLayoutGetRight(YGNodeRef node); -WIN_EXPORT float YGNodeLayoutGetBottom(YGNodeRef node); -WIN_EXPORT float YGNodeLayoutGetWidth(YGNodeRef node); -WIN_EXPORT float YGNodeLayoutGetHeight(YGNodeRef node); -WIN_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeRef node); -WIN_EXPORT bool YGNodeLayoutGetHadOverflow(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(YGNodeRef node, YGEdge edge); -WIN_EXPORT float YGNodeLayoutGetBorder(YGNodeRef node, YGEdge edge); -WIN_EXPORT float YGNodeLayoutGetPadding(YGNodeRef node, YGEdge edge); - -WIN_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger); -WIN_EXPORT void YGAssert(bool condition, const char* message); -WIN_EXPORT void YGAssertWithNode( - YGNodeRef node, - bool condition, - const char* message); -WIN_EXPORT void YGAssertWithConfig( - YGConfigRef config, - 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( - YGConfigRef config, - float pixelsInPoint); -WIN_EXPORT float YGConfigGetPointScaleFactor(YGConfigRef config); - -// 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 YG_DEPRECATED( - "Please use " - "\"YGConfigGetErrata()\"") bool YGConfigGetUseLegacyStretchBehaviour(YGConfigRef - config); -WIN_EXPORT -YG_DEPRECATED( - "\"YGConfigSetUseLegacyStretchBehaviour\" will be removed in the next " - "release. Usage should be replaced with \"YGConfigSetErrata(YGErrataAll)\" " - "to opt out of all future breaking conformance fixes, or " - "\"YGConfigSetErrata(YGErrataStretchFlexBasis)\" to opt out of the " - "specific conformance fix previously disabled by " - "\"UseLegacyStretchBehaviour\".") -void YGConfigSetUseLegacyStretchBehaviour( - YGConfigRef config, - bool useLegacyStretchBehaviour); +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(YGConfigRef config); -WIN_EXPORT void YGConfigCopy(YGConfigRef dest, YGConfigRef src); +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( - YGConfigRef config, - YGExperimentalFeature feature, - bool enabled); -WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled( - YGConfigRef config, - YGExperimentalFeature feature); +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 preferred configuration for new projects. Usage -// of non web defaults should be considered as legacy. -WIN_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled); -WIN_EXPORT bool YGConfigGetUseWebDefaults(YGConfigRef config); +// 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( - YGConfigRef config, - YGCloneNodeFunc callback); +WIN_EXPORT void YGConfigSetNodeClonedFunc(const YGConfigRef config, + const YGNodeClonedFunc callback); // Export only for C# WIN_EXPORT YGConfigRef YGConfigGetDefault(void); -WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); -WIN_EXPORT void* YGConfigGetContext(YGConfigRef config); - -WIN_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata); -WIN_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config); +WIN_EXPORT void YGConfigSetContext(const YGConfigRef config, void *context); +WIN_EXPORT void *YGConfigGetContext(const YGConfigRef config); WIN_EXPORT float YGRoundValueToPixelGrid( - double value, - double pointScaleFactor, - bool forceCeil, - bool forceFloor); + const float value, + const float pointScaleFactor, + const bool forceCeil, + const bool forceFloor); YG_EXTERN_C_END diff --git a/Sources/yoga/log.cpp b/Sources/yoga/log.cpp deleted file mode 100644 index b947aeaf..00000000 --- a/Sources/yoga/log.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "log.h" -#include "YGConfig.h" -#include "YGNode.h" -#include "Yoga.h" - -namespace facebook { -namespace yoga { -namespace detail { - -namespace { - -void vlog( - YGConfig* config, - YGNode* node, - YGLogLevel level, - void* context, - const char* format, - va_list args) { - YGConfig* logConfig = config != nullptr ? config : YGConfigGetDefault(); - logConfig->log(logConfig, node, level, context, format, args); -} -} // namespace - -YOGA_EXPORT void Log::log( - YGNode* node, - YGLogLevel level, - void* context, - const char* format, - ...) noexcept { - va_list args; - va_start(args, format); - vlog( - node == nullptr ? nullptr : node->getConfig(), - node, - level, - context, - format, - args); - va_end(args); -} - -void Log::log( - YGConfig* config, - YGLogLevel level, - void* context, - const char* format, - ...) noexcept { - va_list args; - va_start(args, format); - vlog(config, nullptr, level, context, format, args); - va_end(args); -} - -} // namespace detail -} // namespace yoga -} // namespace facebook diff --git a/Sources/yoga/log.h b/Sources/yoga/log.h deleted file mode 100644 index 1d270e82..00000000 --- a/Sources/yoga/log.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include "YGEnums.h" - -struct YGNode; -struct YGConfig; - -namespace facebook { -namespace yoga { - -namespace detail { - -struct Log { - static void log( - YGNode* node, - YGLogLevel level, - void*, - const char* message, - ...) noexcept; - - static void log( - YGConfig* config, - YGLogLevel level, - void*, - const char* format, - ...) noexcept; -}; - -} // namespace detail -} // namespace yoga -} // namespace facebook