From 91230ae177fdfa6b73cf8aa505e2d91e3bea062f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 3 May 2017 09:22:35 -0700 Subject: [PATCH] Move YGLogger into YGConfig and associate YGNodeRef with log events Summary: Moves the `YGLogger` into `YGConfig` and pass the `YGNodeRef` into the logger to be able to associate the log messages and assertions with the specific node. Tackles facebook/yoga#530 and facebook/yoga#446 Closes https://github.com/facebook/yoga/pull/531 Reviewed By: astreet Differential Revision: D4970149 Pulled By: emilsjolander fbshipit-source-id: b7fcdaa273143ea2fa35861620b2e4d79f04f0af --- YogaKit/Source/YGLayout.h | 9 +- .../Facebook.Yoga.Shared.projitems | 3 + csharp/Facebook.Yoga/Logger.cs | 17 + csharp/Facebook.Yoga/Native.cs | 102 +--- csharp/Facebook.Yoga/YGConfigHandle.cs | 84 ++++ csharp/Facebook.Yoga/YGNodeHandle.cs | 80 ++++ csharp/Facebook.Yoga/YogaBaselineFunc.cs | 2 +- csharp/Facebook.Yoga/YogaConfig.cs | 76 ++- csharp/Facebook.Yoga/YogaLogLevel.cs | 1 + csharp/Facebook.Yoga/YogaLogger.cs | 48 +- csharp/Facebook.Yoga/YogaMeasureFunc.cs | 2 +- csharp/Facebook.Yoga/YogaNode.cs | 118 +---- csharp/Yoga/YGInterop.cpp | 22 +- csharp/Yoga/YGInterop.h | 9 +- csharp/tests/Facebook.Yoga/YogaConfigTest.cs | 2 + csharp/tests/Facebook.Yoga/YogaNodeTest.cs | 24 +- csharp/tests/Facebook.Yoga/test_macos.sh | 2 +- enums.py | 1 + java/com/facebook/yoga/YogaConfig.java | 11 + java/com/facebook/yoga/YogaLogLevel.java | 4 +- java/com/facebook/yoga/YogaLogger.java | 2 +- java/com/facebook/yoga/YogaNode.java | 6 - java/jni/YGJNI.cpp | 114 +++-- .../tests/com/facebook/yoga/YogaNodeTest.java | 32 -- javascript/sources/YGEnums.js | 3 +- tests/YGDefaultValuesTest.cpp | 4 +- tests/YGDirtyMarkingTest.cpp | 14 +- tests/YGLoggerTest.cpp | 71 ++- tests/YGMeasureTest.cpp | 26 +- tests/YGMemoryFuncTest.cpp | 13 +- yoga/YGEnums.c | 63 +-- yoga/YGEnums.h | 3 +- yoga/YGMacros.h | 16 +- yoga/YGNodeList.c | 6 +- yoga/Yoga.c | 444 +++++++++++------- yoga/Yoga.h | 35 +- 36 files changed, 863 insertions(+), 606 deletions(-) create mode 100644 csharp/Facebook.Yoga/Logger.cs create mode 100644 csharp/Facebook.Yoga/YGConfigHandle.cs create mode 100644 csharp/Facebook.Yoga/YGNodeHandle.cs diff --git a/YogaKit/Source/YGLayout.h b/YogaKit/Source/YGLayout.h index fdd933b9..5d6ace7d 100644 --- a/YogaKit/Source/YGLayout.h +++ b/YogaKit/Source/YGLayout.h @@ -11,8 +11,10 @@ #import #import -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"); typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { YGDimensionFlexibilityFlexibleWidth = 1 << 0, @@ -108,7 +110,8 @@ typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { 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 +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin + dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility NS_SWIFT_NAME(applyLayout(preservingOrigin:dimensionFlexibility:)); /** diff --git a/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems b/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems index c35d0354..cf020c6c 100644 --- a/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems +++ b/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems @@ -10,9 +10,12 @@ + + + diff --git a/csharp/Facebook.Yoga/Logger.cs b/csharp/Facebook.Yoga/Logger.cs new file mode 100644 index 00000000..df6e36fa --- /dev/null +++ b/csharp/Facebook.Yoga/Logger.cs @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +namespace Facebook.Yoga +{ + public delegate void Logger( + YogaConfig config, + YogaNode node, + YogaLogLevel level, + string message); +} diff --git a/csharp/Facebook.Yoga/Native.cs b/csharp/Facebook.Yoga/Native.cs index 9ec74145..484f5578 100644 --- a/csharp/Facebook.Yoga/Native.cs +++ b/csharp/Facebook.Yoga/Native.cs @@ -26,96 +26,9 @@ namespace Facebook.Yoga private const string DllName = "yoga"; #endif - internal class YGNodeHandle : SafeHandle - { -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - private GCHandle _managed; -#endif - - private YGNodeHandle() : base(IntPtr.Zero, true) - { - } - - public override bool IsInvalid - { - get - { - return this.handle == IntPtr.Zero; - } - } - - protected override bool ReleaseHandle() - { -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - ReleaseManaged(); -#endif - Native.YGNodeFree(this.handle); - GC.KeepAlive(this); - return true; - } - -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - public void SetContext(YogaNode node) - { - if (!_managed.IsAllocated) - { -#if ENABLE_IL2CPP - // Weak causes 'GCHandle value belongs to a different domain' error - _managed = GCHandle.Alloc(node); -#else - _managed = GCHandle.Alloc(node, GCHandleType.Weak); -#endif - Native.YGNodeSetContext(this.handle, GCHandle.ToIntPtr(_managed)); - } - } - - public void ReleaseManaged() - { - if (_managed.IsAllocated) - { - _managed.Free(); - } - } - - public static YogaNode GetManaged(IntPtr ygNodePtr) - { - var node = - GCHandle.FromIntPtr(Native.YGNodeGetContext(ygNodePtr)).Target as YogaNode; - if (node == null) - { - throw new InvalidOperationException("YogaNode is already deallocated"); - } - - return node; - } -#endif - } - - internal class YGConfigHandle : SafeHandle - { - private YGConfigHandle() : base(IntPtr.Zero, true) - { - } - - public override bool IsInvalid - { - get - { - return this.handle == IntPtr.Zero; - } - } - - protected override bool ReleaseHandle() - { - Native.YGConfigFree(this.handle); - GC.KeepAlive(this); - return true; - } - } - [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGInteropSetLogger( - [MarshalAs(UnmanagedType.FunctionPtr)] YogaLogger.Func func); + [MarshalAs(UnmanagedType.FunctionPtr)] YogaLogger logger); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern YGNodeHandle YGNodeNew(); @@ -129,6 +42,9 @@ namespace Facebook.Yoga [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGNodeReset(YGNodeHandle node); + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + public static extern YGConfigHandle YGConfigGetDefault(); + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern YGConfigHandle YGConfigNew(); @@ -445,15 +361,19 @@ namespace Facebook.Yoga #endregion -#region AOT +#region Context -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr YGNodeGetContext(IntPtr node); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGNodeSetContext(IntPtr node, IntPtr managed); -#endif + + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr YGConfigGetContext(IntPtr config); + + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + public static extern void YGConfigSetContext(IntPtr config, IntPtr managed); #endregion } diff --git a/csharp/Facebook.Yoga/YGConfigHandle.cs b/csharp/Facebook.Yoga/YGConfigHandle.cs new file mode 100644 index 00000000..6ef45163 --- /dev/null +++ b/csharp/Facebook.Yoga/YGConfigHandle.cs @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Facebook.Yoga +{ + internal class YGConfigHandle : SafeHandle + { + internal static readonly YGConfigHandle Default = Native.YGConfigGetDefault(); + private GCHandle _managedConfigHandle; + + private YGConfigHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + if (this.handle != Default.handle) + { + ReleaseManaged(); + if (!IsInvalid) + { + Native.YGConfigFree(this.handle); + } + } + GC.KeepAlive(this); + return true; + } + + public void SetContext(YogaConfig config) + { + if (!_managedConfigHandle.IsAllocated) + { +#if UNITY_5_4_OR_NEWER + // Weak causes 'GCHandle value belongs to a different domain' error + _managedConfigHandle = GCHandle.Alloc(config); +#else + _managedConfigHandle = GCHandle.Alloc(config, GCHandleType.Weak); +#endif + var managedConfigPtr = GCHandle.ToIntPtr(_managedConfigHandle); + Native.YGConfigSetContext(this.handle, managedConfigPtr); + } + } + + private void ReleaseManaged() + { + if (_managedConfigHandle.IsAllocated) + { + _managedConfigHandle.Free(); + } + } + + public static YogaConfig GetManaged(IntPtr unmanagedConfigPtr) + { + if (unmanagedConfigPtr != IntPtr.Zero) + { + var managedConfigPtr = Native.YGConfigGetContext(unmanagedConfigPtr); + var config = GCHandle.FromIntPtr(managedConfigPtr).Target as YogaConfig; + if (config == null) + { + throw new InvalidOperationException("YogaConfig is already deallocated"); + } + return config; + } + return null; + } + } +} diff --git a/csharp/Facebook.Yoga/YGNodeHandle.cs b/csharp/Facebook.Yoga/YGNodeHandle.cs new file mode 100644 index 00000000..8339633e --- /dev/null +++ b/csharp/Facebook.Yoga/YGNodeHandle.cs @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Facebook.Yoga +{ + internal class YGNodeHandle : SafeHandle + { + private GCHandle _managedNodeHandle; + + private YGNodeHandle() : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + ReleaseManaged(); + if (!IsInvalid) + { + Native.YGNodeFree(this.handle); + GC.KeepAlive(this); + } + return true; + } + + public void SetContext(YogaNode node) + { + if (!_managedNodeHandle.IsAllocated) + { +#if UNITY_5_4_OR_NEWER + // Weak causes 'GCHandle value belongs to a different domain' error + _managedNodeHandle = GCHandle.Alloc(node); +#else + _managedNodeHandle = GCHandle.Alloc(node, GCHandleType.Weak); +#endif + var managedNodePtr = GCHandle.ToIntPtr(_managedNodeHandle); + Native.YGNodeSetContext(this.handle, managedNodePtr); + } + } + + public void ReleaseManaged() + { + if (_managedNodeHandle.IsAllocated) + { + _managedNodeHandle.Free(); + } + } + + public static YogaNode GetManaged(IntPtr unmanagedNodePtr) + { + if (unmanagedNodePtr != IntPtr.Zero) + { + var managedNodePtr = Native.YGNodeGetContext(unmanagedNodePtr); + var node = GCHandle.FromIntPtr(managedNodePtr).Target as YogaNode; + if (node == null) + { + throw new InvalidOperationException("YogaNode is already deallocated"); + } + return node; + } + return null; + } + } +} diff --git a/csharp/Facebook.Yoga/YogaBaselineFunc.cs b/csharp/Facebook.Yoga/YogaBaselineFunc.cs index 78575434..7eba4ac9 100644 --- a/csharp/Facebook.Yoga/YogaBaselineFunc.cs +++ b/csharp/Facebook.Yoga/YogaBaselineFunc.cs @@ -13,5 +13,5 @@ using System.Runtime.InteropServices; namespace Facebook.Yoga { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate float YogaBaselineFunc(IntPtr node, float width, float height); + public delegate float YogaBaselineFunc(IntPtr unmanagedNodePtr, float width, float height); } diff --git a/csharp/Facebook.Yoga/YogaConfig.cs b/csharp/Facebook.Yoga/YogaConfig.cs index c35773ff..252692eb 100644 --- a/csharp/Facebook.Yoga/YogaConfig.cs +++ b/csharp/Facebook.Yoga/YogaConfig.cs @@ -8,29 +8,92 @@ */ using System; +using System.Runtime.InteropServices; + +#if __IOS__ +using ObjCRuntime; +#endif +#if ENABLE_IL2CPP +using AOT; +#endif namespace Facebook.Yoga { public class YogaConfig { - private Native.YGConfigHandle _ygConfig; + internal static readonly YogaConfig Default = new YogaConfig(YGConfigHandle.Default); + private static YogaLogger _managedLogger; - public YogaConfig() + private YGConfigHandle _ygConfig; + private Logger _logger; + + private YogaConfig(YGConfigHandle ygConfig) { - _ygConfig = Native.YGConfigNew(); + _ygConfig = ygConfig; if (_ygConfig.IsInvalid) { throw new InvalidOperationException("Failed to allocate native memory"); } + + _ygConfig.SetContext(this); + + if (_ygConfig == YGConfigHandle.Default) + { + _managedLogger = LoggerInternal; + Native.YGInteropSetLogger(_managedLogger); + } } - internal Native.YGConfigHandle Handle + public YogaConfig() + : this(Native.YGConfigNew()) + { + } + + internal YGConfigHandle Handle { get { return _ygConfig; } } +#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ + [MonoPInvokeCallback(typeof(YogaLogger))] +#endif + private static void LoggerInternal( + IntPtr unmanagedConfigPtr, + IntPtr unmanagedNodePtr, + YogaLogLevel level, + string message) + { + var config = YGConfigHandle.GetManaged(unmanagedConfigPtr); + if (config == null || config._logger == null) + { + // Default logger + Console.WriteLine(message); + } + else + { + var node = YGNodeHandle.GetManaged(unmanagedNodePtr); + config._logger(config, node, level, message); + } + + if (level == YogaLogLevel.Error || level == YogaLogLevel.Fatal) + { + throw new InvalidOperationException(message); + } + } + + public Logger Logger + { + get { + return _logger; + } + + set { + _logger = value; + } + } + public void SetExperimentalFeatureEnabled( YogaExperimentalFeature feature, bool enabled) @@ -68,5 +131,10 @@ namespace Facebook.Yoga { return Native.YGConfigGetInstanceCount(); } + + public static void SetDefaultLogger(Logger logger) + { + Default.Logger = logger; + } } } diff --git a/csharp/Facebook.Yoga/YogaLogLevel.cs b/csharp/Facebook.Yoga/YogaLogLevel.cs index ce41ba48..0fb8fa69 100644 --- a/csharp/Facebook.Yoga/YogaLogLevel.cs +++ b/csharp/Facebook.Yoga/YogaLogLevel.cs @@ -16,5 +16,6 @@ namespace Facebook.Yoga Info, Debug, Verbose, + Fatal, } } diff --git a/csharp/Facebook.Yoga/YogaLogger.cs b/csharp/Facebook.Yoga/YogaLogger.cs index d427abc0..97e2d559 100644 --- a/csharp/Facebook.Yoga/YogaLogger.cs +++ b/csharp/Facebook.Yoga/YogaLogger.cs @@ -10,48 +10,12 @@ using System; using System.Runtime.InteropServices; -#if __IOS__ -using ObjCRuntime; -#endif -#if ENABLE_IL2CPP -using AOT; -#endif - namespace Facebook.Yoga { - internal static class YogaLogger - { - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void Func(YogaLogLevel level, string message); - - private static bool _initialized; - private static Func _managedLogger = LoggerInternal; - - public static Func Logger = null; - -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - [MonoPInvokeCallback(typeof(Func))] -#endif - public static void LoggerInternal(YogaLogLevel level, string message) - { - if (Logger != null) - { - Logger(level, message); - } - - if (level == YogaLogLevel.Error) - { - throw new InvalidOperationException(message); - } - } - - public static void Initialize() - { - if (!_initialized) - { - Native.YGInteropSetLogger(_managedLogger); - _initialized = true; - } - } - } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void YogaLogger( + IntPtr unmanagedConfigPtr, + IntPtr unmanagedNotePtr, + YogaLogLevel level, + string message); } diff --git a/csharp/Facebook.Yoga/YogaMeasureFunc.cs b/csharp/Facebook.Yoga/YogaMeasureFunc.cs index 0474292a..8a828e53 100644 --- a/csharp/Facebook.Yoga/YogaMeasureFunc.cs +++ b/csharp/Facebook.Yoga/YogaMeasureFunc.cs @@ -14,7 +14,7 @@ namespace Facebook.Yoga { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate YogaSize YogaMeasureFunc( - IntPtr node, + IntPtr unmanagedNodePtr, float width, YogaMeasureMode widthMode, float height, diff --git a/csharp/Facebook.Yoga/YogaNode.cs b/csharp/Facebook.Yoga/YogaNode.cs index 4d2aec2b..250a5db1 100644 --- a/csharp/Facebook.Yoga/YogaNode.cs +++ b/csharp/Facebook.Yoga/YogaNode.cs @@ -10,11 +10,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ -using System.Runtime.InteropServices; -#endif #if __IOS__ using ObjCRuntime; #endif @@ -26,49 +24,26 @@ namespace Facebook.Yoga { public partial class YogaNode : IEnumerable { - private readonly Native.YGNodeHandle _ygNode; + private readonly YGNodeHandle _ygNode; private readonly YogaConfig _config; private WeakReference _parent; private List _children; private MeasureFunction _measureFunction; private BaselineFunction _baselineFunction; - private object _data; -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - private static YogaMeasureFunc _managedMeasure; - private static YogaBaselineFunc _managedBaseline; -#else private YogaMeasureFunc _managedMeasure; private YogaBaselineFunc _managedBaseline; -#endif + private object _data; - public YogaNode() + public YogaNode(YogaConfig config = null) { - YogaLogger.Initialize(); - - _ygNode = Native.YGNodeNew(); + _config = config == null ? YogaConfig.Default : config; + _ygNode = Native.YGNodeNewWithConfig(_config.Handle); if (_ygNode.IsInvalid) { throw new InvalidOperationException("Failed to allocate native memory"); } - } - public YogaNode(YogaConfig config) - { - YogaLogger.Initialize(); - - if (config != null) - { - _config = config; - _ygNode = Native.YGNodeNewWithConfig(_config.Handle); - } - else - { - _ygNode = Native.YGNodeNew(); - } - if (_ygNode.IsInvalid) - { - throw new InvalidOperationException("Failed to allocate native memory"); - } + _ygNode.SetContext(this); } public YogaNode(YogaNode srcNode) @@ -83,10 +58,9 @@ namespace Facebook.Yoga _baselineFunction = null; _data = null; - Native.YGNodeReset(_ygNode); -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ _ygNode.ReleaseManaged(); -#endif + Native.YGNodeReset(_ygNode); + _ygNode.SetContext(this); } public bool IsDirty @@ -609,38 +583,15 @@ namespace Facebook.Yoga public void SetMeasureFunction(MeasureFunction measureFunction) { _measureFunction = measureFunction; - if (measureFunction != null) - { -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - _managedMeasure = MeasureInternalAOT; - _ygNode.SetContext(this); -#else - _managedMeasure = MeasureInternal; -#endif - } - else - { - _managedMeasure = null; - } + _managedMeasure = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null; Native.YGNodeSetMeasureFunc(_ygNode, _managedMeasure); } public void SetBaselineFunction(BaselineFunction baselineFunction) { _baselineFunction = baselineFunction; - if (baselineFunction != null) - { -#if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ - _managedBaseline = BaselineInternalAOT; - _ygNode.SetContext(this); -#else - _managedBaseline = BaselineInternal; -#endif - } - else - { - _managedBaseline = null; - } + _managedBaseline = + baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null; Native.YGNodeSetBaselineFunc(_ygNode, _managedBaseline); } @@ -655,63 +606,46 @@ namespace Facebook.Yoga #if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ [MonoPInvokeCallback(typeof(YogaMeasureFunc))] - private static YogaSize MeasureInternalAOT( - IntPtr ygNodePtr, - float width, - YogaMeasureMode widthMode, - float height, - YogaMeasureMode heightMode) - { - var node = Native.YGNodeHandle.GetManaged(ygNodePtr); - return node.MeasureInternal(IntPtr.Zero, width, widthMode, height, heightMode); - } #endif - - private YogaSize MeasureInternal( - IntPtr node, + private static YogaSize MeasureInternal( + IntPtr unmanagedNodePtr, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode) { - if (_measureFunction == null) + var node = YGNodeHandle.GetManaged(unmanagedNodePtr); + if (node == null || node._measureFunction == null) { throw new InvalidOperationException("Measure function is not defined."); } - - return _measureFunction(this, width, widthMode, height, heightMode); + return node._measureFunction(node, width, widthMode, height, heightMode); } #if (UNITY_IOS && !UNITY_EDITOR) || ENABLE_IL2CPP || __IOS__ [MonoPInvokeCallback(typeof(YogaBaselineFunc))] - private static float BaselineInternalAOT( - IntPtr ygNodePtr, +#endif + private static float BaselineInternal( + IntPtr unmanagedNodePtr, float width, float height) { - var node = Native.YGNodeHandle.GetManaged(ygNodePtr); - return node.BaselineInternal(IntPtr.Zero, width, height); - } -#endif - - private float BaselineInternal(IntPtr node, float width, float height) - { - if (_baselineFunction == null) + var node = YGNodeHandle.GetManaged(unmanagedNodePtr); + if (node == null || node._baselineFunction == null) { throw new InvalidOperationException("Baseline function is not defined."); } - - return _baselineFunction(this, width, height); + return node._baselineFunction(node, width, height); } public string Print(YogaPrintOptions options = YogaPrintOptions.Layout|YogaPrintOptions.Style|YogaPrintOptions.Children) { StringBuilder sb = new StringBuilder(); - YogaLogger.Func orig = YogaLogger.Logger; - YogaLogger.Logger = (level, message) => {sb.Append(message);}; + Logger orig = _config.Logger; + _config.Logger = (config, node, level, message) => {sb.Append(message);}; Native.YGNodePrint(_ygNode, options); - YogaLogger.Logger = orig; + _config.Logger = orig; return sb.ToString(); } diff --git a/csharp/Yoga/YGInterop.cpp b/csharp/Yoga/YGInterop.cpp index fc2043dc..293b8ef4 100644 --- a/csharp/Yoga/YGInterop.cpp +++ b/csharp/Yoga/YGInterop.cpp @@ -9,19 +9,23 @@ #include "YGInterop.h" -static YGInteropLoggerFunc gManagedFunc; +static YGInteropLogger gManagedLogger; -static int unmanagedLogger(YGLogLevel level, const char *format, va_list args) { +static int unmanagedLogger(const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + const char *format, + va_list args) { int result = 0; - if (gManagedFunc) { - char buffer[256]; - result = vsnprintf(buffer, sizeof(buffer), format, args); - (*gManagedFunc)(level, buffer); + if (gManagedLogger) { + char message[8192]; + result = vsnprintf(message, sizeof(message), format, args); + (*gManagedLogger)(config, node, level, message); } return result; } -void YGInteropSetLogger(YGInteropLoggerFunc managedFunc) { - gManagedFunc = managedFunc; - YGSetLogger(&unmanagedLogger); +void YGInteropSetLogger(YGInteropLogger managedLogger) { + gManagedLogger = managedLogger; + YGSetLogger(YGConfigGetDefault(), &unmanagedLogger); } diff --git a/csharp/Yoga/YGInterop.h b/csharp/Yoga/YGInterop.h index 7494977f..5fda7202 100644 --- a/csharp/Yoga/YGInterop.h +++ b/csharp/Yoga/YGInterop.h @@ -13,8 +13,13 @@ YG_EXTERN_C_BEGIN -typedef void (*YGInteropLoggerFunc)(YGLogLevel level, const char *message); +typedef int (*YGInteropLogger)(const void *unmanagedConfigPtr, + const void *unmanagedNodePtr, + YGLogLevel level, + const char *message); -WIN_EXPORT void YGInteropSetLogger(YGInteropLoggerFunc managedFunc); +WIN_EXPORT YGConfigRef YGConfigGetDefault(); + +WIN_EXPORT void YGInteropSetLogger(YGInteropLogger managedLogger); YG_EXTERN_C_END diff --git a/csharp/tests/Facebook.Yoga/YogaConfigTest.cs b/csharp/tests/Facebook.Yoga/YogaConfigTest.cs index 0f678da6..97fc9e42 100644 --- a/csharp/tests/Facebook.Yoga/YogaConfigTest.cs +++ b/csharp/tests/Facebook.Yoga/YogaConfigTest.cs @@ -69,6 +69,7 @@ namespace Facebook.Yoga Assert.AreEqual(YogaFlexDirection.Row, node1.FlexDirection); } +#if !UNITY_5_4_OR_NEWER public static void ForceGC() { YogaNodeTest.ForceGC(); @@ -132,5 +133,6 @@ namespace Facebook.Yoga return node; } +#endif } } diff --git a/csharp/tests/Facebook.Yoga/YogaNodeTest.cs b/csharp/tests/Facebook.Yoga/YogaNodeTest.cs index 3151ef24..a0a76759 100644 --- a/csharp/tests/Facebook.Yoga/YogaNodeTest.cs +++ b/csharp/tests/Facebook.Yoga/YogaNodeTest.cs @@ -248,6 +248,26 @@ namespace Facebook.Yoga Assert.AreEqual(0, child2.LayoutY); } + [Test] + public void TestPrintOneNode() + { + YogaNode node = new YogaNode(); + node.Width = 100; + node.Height = 120; + node.CalculateLayout(); + Assert.AreEqual("
", node.Print()); + } + + [Test] + public void TestPrintWithLogger() + { + YogaNode node = new YogaNode(new YogaConfig{Logger = (c, n, l, m) => {}}); + node.Width = 110; + node.Height = 105; + node.CalculateLayout(); + Assert.AreEqual("
", node.Print()); + } + [Test] public void TestPrint() { @@ -309,9 +329,10 @@ namespace Facebook.Yoga Assert.AreEqual(90.Pt(), node4.MaxHeight); } +#if !UNITY_5_4_OR_NEWER public static void ForceGC() { - GC.Collect(GC.MaxGeneration); + GC.Collect(); GC.WaitForPendingFinalizers(); } @@ -438,6 +459,7 @@ namespace Facebook.Yoga return MeasureOutput.Make(120, 130); }); } +#endif [Test] public void TestLayoutMargin() { diff --git a/csharp/tests/Facebook.Yoga/test_macos.sh b/csharp/tests/Facebook.Yoga/test_macos.sh index 1d04177d..3a89b7a3 100755 --- a/csharp/tests/Facebook.Yoga/test_macos.sh +++ b/csharp/tests/Facebook.Yoga/test_macos.sh @@ -24,5 +24,5 @@ ROOT=`buck root|tail -1` DYLIB=`buck targets --show-output $TARGET|tail -1|awk '{print $2}'` cp $ROOT/$DYLIB . -mcs -debug -t:library -r:$NUNIT/nunit.framework.dll -out:YogaTest.dll *.cs ../../../csharp/Facebook.Yoga/*cs +mcs -debug -d:YOGA_ENABLE_GC_TEST -t:library -r:$NUNIT/nunit.framework.dll -out:YogaTest.dll *.cs ../../../csharp/Facebook.Yoga/*cs MONO_PATH=$NUNIT mono --arch=64 --debug $NUNIT/nunit-console.exe YogaTest.dll diff --git a/enums.py b/enums.py index 731121c5..0e8a4f37 100644 --- a/enums.py +++ b/enums.py @@ -90,6 +90,7 @@ ENUMS = { 'Info', 'Debug', 'Verbose', + 'Fatal', ], 'ExperimentalFeature': [ # Mimic web flex-basis behavior. diff --git a/java/com/facebook/yoga/YogaConfig.java b/java/com/facebook/yoga/YogaConfig.java index 6cad34ba..9869271a 100644 --- a/java/com/facebook/yoga/YogaConfig.java +++ b/java/com/facebook/yoga/YogaConfig.java @@ -20,6 +20,7 @@ public class YogaConfig { } long mNativePointer; + private YogaLogger mLogger; private native long jni_YGConfigNew(); public YogaConfig() { @@ -67,4 +68,14 @@ public class YogaConfig { public void setUseLegacyStretchBehaviour(boolean useLegacyStretchBehaviour) { jni_YGConfigSetUseLegacyStretchBehaviour(mNativePointer, useLegacyStretchBehaviour); } + + private native void jni_YGConfigSetLogger(long nativePointer, Object logger); + public void setLogger(YogaLogger logger) { + mLogger = logger; + jni_YGConfigSetLogger(mNativePointer, logger); + } + + public YogaLogger getLogger() { + return mLogger; + } } diff --git a/java/com/facebook/yoga/YogaLogLevel.java b/java/com/facebook/yoga/YogaLogLevel.java index 4fd8a769..27a349b0 100644 --- a/java/com/facebook/yoga/YogaLogLevel.java +++ b/java/com/facebook/yoga/YogaLogLevel.java @@ -17,7 +17,8 @@ public enum YogaLogLevel { WARN(1), INFO(2), DEBUG(3), - VERBOSE(4); + VERBOSE(4), + FATAL(5); private int mIntValue; @@ -36,6 +37,7 @@ public enum YogaLogLevel { case 2: return INFO; case 3: return DEBUG; case 4: return VERBOSE; + case 5: return FATAL; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/java/com/facebook/yoga/YogaLogger.java b/java/com/facebook/yoga/YogaLogger.java index a856b7be..86bab37d 100644 --- a/java/com/facebook/yoga/YogaLogger.java +++ b/java/com/facebook/yoga/YogaLogger.java @@ -18,5 +18,5 @@ import com.facebook.proguard.annotations.DoNotStrip; @DoNotStrip public interface YogaLogger { @DoNotStrip - void log(YogaLogLevel level, String message); + void log(YogaNode node, YogaLogLevel level, String message); } diff --git a/java/com/facebook/yoga/YogaNode.java b/java/com/facebook/yoga/YogaNode.java index 3af33cdf..c50078e6 100644 --- a/java/com/facebook/yoga/YogaNode.java +++ b/java/com/facebook/yoga/YogaNode.java @@ -28,12 +28,6 @@ public class YogaNode { * Get native instance count. Useful for testing only. */ static native int jni_YGNodeGetInstanceCount(); - static native void jni_YGLog(int level, String message); - - private static native void jni_YGSetLogger(Object logger); - public static void setLogger(YogaLogger logger) { - jni_YGSetLogger(logger); - } private YogaNode mParent; private List mChildren; diff --git a/java/jni/YGJNI.cpp b/java/jni/YGJNI.cpp index ca0af8c0..bf2d4c33 100644 --- a/java/jni/YGJNI.cpp +++ b/java/jni/YGJNI.cpp @@ -14,8 +14,12 @@ using namespace facebook::jni; using namespace std; -static inline weak_ref *YGNodeJobject(YGNodeRef node) { - return reinterpret_cast *>(YGNodeGetContext(node)); +struct JYogaNode : public JavaClass { + static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNode;"; +}; + +static inline weak_ref *YGNodeJobject(YGNodeRef node) { + return reinterpret_cast *>(YGNodeGetContext(node)); } static void YGTransferLayoutDirection(YGNodeRef node, alias_ref javaNode) { @@ -24,7 +28,7 @@ static void YGTransferLayoutDirection(YGNodeRef node, alias_ref javaNod } static void YGTransferLayoutOutputsRecursive(YGNodeRef root) { - if(YGNodeGetHasNewLayout(root)){ + if (YGNodeGetHasNewLayout(root)) { if (auto obj = YGNodeJobject(root)->lockLocal()) { static auto widthField = obj->getClass()->getField("mWidth"); static auto heightField = obj->getClass()->getField("mHeight"); @@ -54,28 +58,28 @@ static void YGTransferLayoutOutputsRecursive(YGNodeRef root) { const int PADDING = 2; const int BORDER = 4; - int hasEdgeSetFlag = (int)obj->getFieldValue(edgeSetFlagField); + int hasEdgeSetFlag = (int) obj->getFieldValue(edgeSetFlagField); obj->setFieldValue(widthField, YGNodeLayoutGetWidth(root)); obj->setFieldValue(heightField, YGNodeLayoutGetHeight(root)); obj->setFieldValue(leftField, YGNodeLayoutGetLeft(root)); obj->setFieldValue(topField, YGNodeLayoutGetTop(root)); - if((hasEdgeSetFlag & MARGIN) == MARGIN){ + if ((hasEdgeSetFlag & MARGIN) == MARGIN) { obj->setFieldValue(marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft)); obj->setFieldValue(marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop)); obj->setFieldValue(marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight)); obj->setFieldValue(marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom)); } - if((hasEdgeSetFlag & PADDING) == PADDING){ + if ((hasEdgeSetFlag & PADDING) == PADDING) { obj->setFieldValue(paddingLeftField, YGNodeLayoutGetPadding(root, YGEdgeLeft)); obj->setFieldValue(paddingTopField, YGNodeLayoutGetPadding(root, YGEdgeTop)); obj->setFieldValue(paddingRightField, YGNodeLayoutGetPadding(root, YGEdgeRight)); obj->setFieldValue(paddingBottomField, YGNodeLayoutGetPadding(root, YGEdgeBottom)); } - if((hasEdgeSetFlag & BORDER) == BORDER){ + if ((hasEdgeSetFlag & BORDER) == BORDER) { obj->setFieldValue(borderLeftField, YGNodeLayoutGetBorder(root, YGEdgeLeft)); obj->setFieldValue(borderTopField, YGNodeLayoutGetBorder(root, YGEdgeTop)); obj->setFieldValue(borderRightField, YGNodeLayoutGetBorder(root, YGEdgeRight)); @@ -90,7 +94,7 @@ static void YGTransferLayoutOutputsRecursive(YGNodeRef root) { YGTransferLayoutOutputsRecursive(YGNodeGetChild(root, i)); } } else { - YGLog(YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); + YGLog(root, YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); } } } @@ -99,7 +103,7 @@ static void YGPrint(YGNodeRef node) { if (auto obj = YGNodeJobject(node)->lockLocal()) { cout << obj->toString() << endl; } else { - YGLog(YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); + YGLog(node, YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); } } @@ -136,7 +140,7 @@ static YGSize YGJNIMeasureFunc(YGNodeRef node, return YGSize{*measuredWidth, *measuredHeight}; } else { - YGLog(YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); + YGLog(node, YGLogLevelError, "Java YGNode was GCed during layout calculation\n"); return YGSize{ widthMode == YGMeasureModeUndefined ? 0 : width, heightMode == YGMeasureModeUndefined ? 0 : height, @@ -148,20 +152,28 @@ struct JYogaLogLevel : public JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaLogLevel;"; }; -static global_ref *jLogger; -static int YGLog(YGLogLevel level, const char *format, va_list args) { +static int YGJNILogFunc(const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + const char *format, + va_list args) { char buffer[256]; int result = vsnprintf(buffer, sizeof(buffer), format, args); - static auto logFunc = findClassStatic("com/facebook/yoga/YogaLogger") - ->getMethod, jstring)>("log"); + static auto logFunc = + findClassStatic("com/facebook/yoga/YogaLogger") + ->getMethod, local_ref, jstring)>("log"); static auto logLevelFromInt = JYogaLogLevel::javaClassStatic()->getStaticMethod("fromInt"); - logFunc(jLogger->get(), - logLevelFromInt(JYogaLogLevel::javaClassStatic(), static_cast(level)), - Environment::current()->NewStringUTF(buffer)); + if (auto obj = YGNodeJobject(node)->lockLocal()) { + auto jlogger = reinterpret_cast *>(YGConfigGetContext(config)); + logFunc(jlogger->get(), + obj, + logLevelFromInt(JYogaLogLevel::javaClassStatic(), static_cast(level)), + Environment::current()->NewStringUTF(buffer)); + } return result; } @@ -174,27 +186,6 @@ static inline YGConfigRef _jlong2YGConfigRef(jlong addr) { return reinterpret_cast(static_cast(addr)); } -void jni_YGSetLogger(alias_ref clazz, alias_ref logger) { - if (jLogger) { - jLogger->releaseAlias(); - delete jLogger; - } - - if (logger) { - jLogger = new global_ref(make_global(logger)); - YGSetLogger(YGLog); - } else { - jLogger = NULL; - YGSetLogger(NULL); - } -} - -void jni_YGLog(alias_ref clazz, jint level, jstring message) { - const char *nMessage = Environment::current()->GetStringUTFChars(message, 0); - YGLog(static_cast(level), "%s", nMessage); - Environment::current()->ReleaseStringUTFChars(message, nMessage); -} - jlong jni_YGNodeNew(alias_ref thiz) { const YGNodeRef node = YGNodeNew(); YGNodeSetContext(node, new weak_ref(make_weak(thiz))); @@ -225,7 +216,9 @@ void jni_YGNodeReset(alias_ref thiz, jlong nativePointer) { void jni_YGNodePrint(alias_ref thiz, jlong nativePointer) { const YGNodeRef node = _jlong2YGNodeRef(nativePointer); - YGNodePrint(node, (YGPrintOptions) (YGPrintOptionsStyle | YGPrintOptionsLayout | YGPrintOptionsChildren)); + YGNodePrint(node, + (YGPrintOptions)(YGPrintOptionsStyle | YGPrintOptionsLayout | + YGPrintOptionsChildren)); } void jni_YGNodeInsertChild(alias_ref, jlong nativePointer, jlong childPointer, jint index) { @@ -393,26 +386,56 @@ void jni_YGConfigFree(alias_ref, jlong nativePointer) { YGConfigFree(config); } -void jni_YGConfigSetExperimentalFeatureEnabled(alias_ref, jlong nativePointer, jint feature, jboolean enabled) { +void jni_YGConfigSetExperimentalFeatureEnabled(alias_ref, + jlong nativePointer, + jint feature, + jboolean enabled) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); - YGConfigSetExperimentalFeatureEnabled(config, static_cast(feature), enabled); + YGConfigSetExperimentalFeatureEnabled(config, + static_cast(feature), + enabled); } -void jni_YGConfigSetUseWebDefaults(alias_ref, jlong nativePointer, jboolean useWebDefaults) { +void jni_YGConfigSetUseWebDefaults(alias_ref, + jlong nativePointer, + jboolean useWebDefaults) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); YGConfigSetUseWebDefaults(config, useWebDefaults); } -void jni_YGConfigSetPointScaleFactor(alias_ref, jlong nativePointer, jfloat pixelsInPoint) { +void jni_YGConfigSetPointScaleFactor(alias_ref, + jlong nativePointer, + jfloat pixelsInPoint) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); YGConfigSetPointScaleFactor(config, pixelsInPoint); } -void jni_YGConfigSetUseLegacyStretchBehaviour(alias_ref, jlong nativePointer, jboolean useLegacyStretchBehaviour) { +void jni_YGConfigSetUseLegacyStretchBehaviour(alias_ref, + jlong nativePointer, + jboolean useLegacyStretchBehaviour) { const YGConfigRef config = _jlong2YGConfigRef(nativePointer); YGConfigSetUseLegacyStretchBehaviour(config, useLegacyStretchBehaviour); } +void jni_YGConfigSetLogger(alias_ref, jlong nativePointer, alias_ref logger) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + + auto context = YGConfigGetContext(config); + if (context) { + auto jlogger = reinterpret_cast *>(context); + jlogger->releaseAlias(); + delete jlogger; + } + + if (logger) { + YGConfigSetContext(config, new global_ref(make_global(logger))); + YGConfigSetLogger(config, YGJNILogFunc); + } else { + YGConfigSetContext(config, NULL); + YGConfigSetLogger(config, NULL); + } +} + jint jni_YGNodeGetInstanceCount(alias_ref clazz) { return YGNodeGetInstanceCount(); } @@ -498,8 +521,6 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodeStyleGetAspectRatio), YGMakeNativeMethod(jni_YGNodeStyleSetAspectRatio), YGMakeNativeMethod(jni_YGNodeGetInstanceCount), - YGMakeNativeMethod(jni_YGSetLogger), - YGMakeNativeMethod(jni_YGLog), YGMakeNativeMethod(jni_YGNodePrint), }); registerNatives("com/facebook/yoga/YogaConfig", @@ -510,6 +531,7 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults), YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor), YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour), + YGMakeNativeMethod(jni_YGConfigSetLogger), }); }); } diff --git a/java/tests/com/facebook/yoga/YogaNodeTest.java b/java/tests/com/facebook/yoga/YogaNodeTest.java index 95b0b56f..0e0d37df 100644 --- a/java/tests/com/facebook/yoga/YogaNodeTest.java +++ b/java/tests/com/facebook/yoga/YogaNodeTest.java @@ -124,38 +124,6 @@ public class YogaNodeTest { assertEquals(Float.MAX_VALUE, node.getLayoutHeight(), 0.01f); } - private YogaLogLevel mLogLevel; - private String mLogMessage; - - @Test - public void testLogger() { - YogaNode.setLogger(new YogaLogger() { - public void log(YogaLogLevel level, String message) { - mLogLevel = level; - mLogMessage = message; - } - }); - YogaNode.jni_YGLog(YogaLogLevel.DEBUG.intValue(), "Hello"); - assertEquals(YogaLogLevel.DEBUG, mLogLevel); - assertEquals("Hello", mLogMessage); - } - - @Test - public void testUpdateLogger() { - YogaNode.setLogger(new YogaLogger() { - public void log(YogaLogLevel level, String message) {} - }); - YogaNode.setLogger(new YogaLogger() { - public void log(YogaLogLevel level, String message) { - mLogLevel = level; - mLogMessage = message; - } - }); - YogaNode.jni_YGLog(YogaLogLevel.VERBOSE.intValue(), "Flexbox"); - assertEquals(YogaLogLevel.VERBOSE, mLogLevel); - assertEquals("Flexbox", mLogMessage); - } - @Test public void testCopyStyle() { final YogaNode node0 = new YogaNode(); diff --git a/javascript/sources/YGEnums.js b/javascript/sources/YGEnums.js index e19aeb9a..bb30b61b 100644 --- a/javascript/sources/YGEnums.js +++ b/javascript/sources/YGEnums.js @@ -59,12 +59,13 @@ module.exports = { JUSTIFY_SPACE_BETWEEN: 3, JUSTIFY_SPACE_AROUND: 4, - LOG_LEVEL_COUNT: 5, + LOG_LEVEL_COUNT: 6, LOG_LEVEL_ERROR: 0, LOG_LEVEL_WARN: 1, LOG_LEVEL_INFO: 2, LOG_LEVEL_DEBUG: 3, LOG_LEVEL_VERBOSE: 4, + LOG_LEVEL_FATAL: 5, MEASURE_MODE_COUNT: 3, MEASURE_MODE_UNDEFINED: 0, diff --git a/tests/YGDefaultValuesTest.cpp b/tests/YGDefaultValuesTest.cpp index 5fcd9fd9..bc2ea2eb 100644 --- a/tests/YGDefaultValuesTest.cpp +++ b/tests/YGDefaultValuesTest.cpp @@ -92,7 +92,7 @@ TEST(YogaTest, assert_default_values) { } TEST(YogaTest, assert_webdefault_values) { - YGConfig * config = YGConfigNew(); + YGConfig *config = YGConfigNew(); YGConfigSetUseWebDefaults(config, true); const YGNodeRef root = YGNodeNewWithConfig(config); @@ -105,7 +105,7 @@ TEST(YogaTest, assert_webdefault_values) { } TEST(YogaTest, assert_webdefault_values_reset) { - YGConfig * config = YGConfigNew(); + YGConfig *config = YGConfigNew(); YGConfigSetUseWebDefaults(config, true); const YGNodeRef root = YGNodeNewWithConfig(config); YGNodeReset(root); diff --git a/tests/YGDirtyMarkingTest.cpp b/tests/YGDirtyMarkingTest.cpp index 7b26f0fc..953de26a 100644 --- a/tests/YGDirtyMarkingTest.cpp +++ b/tests/YGDirtyMarkingTest.cpp @@ -70,27 +70,27 @@ TEST(YogaTest, dirty_propagation_only_if_prop_changed) { YGNodeFreeRecursive(root); } -TEST(YogaTest, dirty_mark_all_children_as_dirty_when_display_changes){ +TEST(YogaTest, dirty_mark_all_children_as_dirty_when_display_changes) { const YGNodeRef root = YGNodeNew(); YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); YGNodeStyleSetHeight(root, 100); - + const YGNodeRef child0 = YGNodeNew(); YGNodeStyleSetFlexGrow(child0, 1); const YGNodeRef child1 = YGNodeNew(); YGNodeStyleSetFlexGrow(child1, 1); - + const YGNodeRef child1_child0 = YGNodeNew(); const YGNodeRef child1_child0_child0 = YGNodeNew(); YGNodeStyleSetWidth(child1_child0_child0, 8); YGNodeStyleSetHeight(child1_child0_child0, 16); - + YGNodeInsertChild(child1_child0, child1_child0_child0, 0); - + YGNodeInsertChild(child1, child1_child0, 0); YGNodeInsertChild(root, child0, 0); YGNodeInsertChild(root, child1, 0); - + YGNodeStyleSetDisplay(child0, YGDisplayFlex); YGNodeStyleSetDisplay(child1, YGDisplayNone); YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); @@ -114,7 +114,7 @@ TEST(YogaTest, dirty_mark_all_children_as_dirty_when_display_changes){ YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); ASSERT_FLOAT_EQ(8, YGNodeLayoutGetWidth(child1_child0_child0)); ASSERT_FLOAT_EQ(16, YGNodeLayoutGetHeight(child1_child0_child0)); - + YGNodeFreeRecursive(root); } diff --git a/tests/YGLoggerTest.cpp b/tests/YGLoggerTest.cpp index 141600b2..846722ad 100644 --- a/tests/YGLoggerTest.cpp +++ b/tests/YGLoggerTest.cpp @@ -8,33 +8,44 @@ */ #include -#include #include +#include namespace { - char writeBuffer[4096]; - int _unmanagedLogger(YGLogLevel level, const char *format, va_list args) { - return vsnprintf(writeBuffer + strlen(writeBuffer), sizeof(writeBuffer) - strlen(writeBuffer), format, args); - } +char writeBuffer[4096]; +int _unmanagedLogger(const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + const char *format, + va_list args) { + return vsnprintf(writeBuffer + strlen(writeBuffer), + sizeof(writeBuffer) - strlen(writeBuffer), + format, + args); +} } TEST(YogaTest, logger_default_node_should_print_no_style_info) { writeBuffer[0] = '\0'; - YGSetLogger(_unmanagedLogger); - const YGNodeRef root = YGNodeNew(); + const YGConfigRef config = YGConfigNew(); + YGConfigSetLogger(config, _unmanagedLogger); + const YGNodeRef root = YGNodeNewWithConfig(config); YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR); - YGNodePrint(root, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); - YGSetLogger(NULL); + YGNodePrint(root, + (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren | + YGPrintOptionsStyle)); + YGConfigSetLogger(config, NULL); YGNodeFree(root); - - const char * expected = "
"; + + const char *expected = "
"; ASSERT_STREQ(expected, writeBuffer); } TEST(YogaTest, logger_node_with_percentage_absolute_position_and_margin) { writeBuffer[0] = '\0'; - YGSetLogger(_unmanagedLogger); - const YGNodeRef root = YGNodeNew(); + const YGConfigRef config = YGConfigNew(); + YGConfigSetLogger(config, _unmanagedLogger); + const YGNodeRef root = YGNodeNewWithConfig(config); YGNodeStyleSetPositionType(root, YGPositionTypeAbsolute); YGNodeStyleSetWidthPercent(root, 50); YGNodeStyleSetHeightPercent(root, 75); @@ -42,27 +53,37 @@ TEST(YogaTest, logger_node_with_percentage_absolute_position_and_margin) { YGNodeStyleSetMargin(root, YGEdgeRight, 10); YGNodeStyleSetMarginAuto(root, YGEdgeLeft); YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR); - YGNodePrint(root, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); - YGSetLogger(NULL); + YGNodePrint(root, + (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren | + YGPrintOptionsStyle)); + YGConfigSetLogger(config, NULL); YGNodeFree(root); - - const char * expected = "
"; + + const char *expected = "
"; ASSERT_STREQ(expected, writeBuffer); } TEST(YogaTest, logger_node_with_children_should_print_indented) { writeBuffer[0] = '\0'; - YGSetLogger(_unmanagedLogger); - const YGNodeRef root = YGNodeNew(); - const YGNodeRef child0 = YGNodeNew(); - const YGNodeRef child1 = YGNodeNew(); + const YGConfigRef config = YGConfigNew(); + YGConfigSetLogger(config, _unmanagedLogger); + const YGNodeRef root = YGNodeNewWithConfig(config); + const YGNodeRef child0 = YGNodeNewWithConfig(config); + const YGNodeRef child1 = YGNodeNewWithConfig(config); YGNodeInsertChild(root, child0, 0); YGNodeInsertChild(root, child1, 1); YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR); - YGNodePrint(root, (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); - YGSetLogger(NULL); + YGNodePrint(root, + (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren | + YGPrintOptionsStyle)); + YGConfigSetLogger(config, NULL); YGNodeFreeRecursive(root); - - const char * expected = "
\n
\n
\n
"; + + const char *expected = "
\n " + "
\n
\n
"; ASSERT_STREQ(expected, writeBuffer); } diff --git a/tests/YGMeasureTest.cpp b/tests/YGMeasureTest.cpp index 831fa7f7..b1214493 100644 --- a/tests/YGMeasureTest.cpp +++ b/tests/YGMeasureTest.cpp @@ -26,15 +26,12 @@ static YGSize _measure(YGNodeRef node, } static YGSize _simulate_wrapping_text(YGNodeRef node, - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode) { - if(widthMode == YGMeasureModeUndefined || width >= 68) - { - return YGSize{ - .width = 68, .height = 16 - }; + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode) { + if (widthMode == YGMeasureModeUndefined || width >= 68) { + return YGSize{.width = 68, .height = 16}; } return YGSize{ @@ -196,8 +193,7 @@ TEST(YogaTest, dont_measure_when_min_equals_max_mixed_height_percent) { YGNodeFreeRecursive(root); } -TEST(YogaTest, measure_enough_size_should_be_in_single_line) -{ +TEST(YogaTest, measure_enough_size_should_be_in_single_line) { const YGNodeRef root = YGNodeNew(); YGNodeStyleSetWidth(root, 100); @@ -215,8 +211,7 @@ TEST(YogaTest, measure_enough_size_should_be_in_single_line) YGNodeFreeRecursive(root); } -TEST(YogaTest, measure_not_enough_size_should_wrap) -{ +TEST(YogaTest, measure_not_enough_size_should_wrap) { const YGNodeRef root = YGNodeNew(); YGNodeStyleSetWidth(root, 55); @@ -234,8 +229,7 @@ TEST(YogaTest, measure_not_enough_size_should_wrap) YGNodeFreeRecursive(root); } -TEST(YogaTest, measure_zero_space_should_grow) -{ +TEST(YogaTest, measure_zero_space_should_grow) { const YGNodeRef root = YGNodeNew(); YGNodeStyleSetHeight(root, 200); YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn); @@ -539,7 +533,6 @@ TEST(YogaTest, measure_no_padding) { YGConfigFree(config); } - #if GTEST_HAS_DEATH_TEST TEST(YogaDeathTest, cannot_add_child_to_node_with_measure_func) { const YGNodeRef root = YGNodeNew(); @@ -570,4 +563,3 @@ TEST(YogaTest, can_nullify_measure_func_on_any_node) { ASSERT_TRUE(YGNodeGetMeasureFunc(root) == NULL); YGNodeFreeRecursive(root); } - diff --git a/tests/YGMemoryFuncTest.cpp b/tests/YGMemoryFuncTest.cpp index 20eff61a..c3f1a594 100644 --- a/tests/YGMemoryFuncTest.cpp +++ b/tests/YGMemoryFuncTest.cpp @@ -11,6 +11,7 @@ #include extern int32_t gNodeInstanceCount; +extern int32_t gConfigInstanceCount; static int testMallocCount; static int testCallocCount; @@ -38,7 +39,8 @@ static void testFree(void *ptr) { } TEST(YogaTest, memory_func_default) { - gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gConfigInstanceCount = 0; // Reset YGConfig instance count for memory func test YGSetMemoryFuncs(NULL, NULL, NULL, NULL); const YGNodeRef root = YGNodeNew(); const YGNodeRef root_child0 = YGNodeNew(); @@ -47,7 +49,8 @@ TEST(YogaTest, memory_func_default) { } TEST(YogaTest, memory_func_test_funcs) { - gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gConfigInstanceCount = 0; // Reset YGConfig instance count for memory func test YGSetMemoryFuncs(&testMalloc, &testCalloc, &testRealloc, &testFree); const YGNodeRef root = YGNodeNew(); for (int i = 0; i < 10; i++) { @@ -64,7 +67,8 @@ TEST(YogaTest, memory_func_test_funcs) { #if GTEST_HAS_DEATH_TEST TEST(YogaDeathTest, memory_func_assert_zero_nodes) { - gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gConfigInstanceCount = 0; // Reset YGConfig instance count for memory func test const YGNodeRef root = YGNodeNew(); ASSERT_DEATH(YGSetMemoryFuncs(&testMalloc, &testCalloc, &testRealloc, &testFree), "Cannot set memory functions: all node must be freed first"); @@ -72,7 +76,8 @@ TEST(YogaDeathTest, memory_func_assert_zero_nodes) { } TEST(YogaDeathTest, memory_func_assert_all_non_null) { - gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gNodeInstanceCount = 0; // Reset YGNode instance count for memory func test + gConfigInstanceCount = 0; // Reset YGConfig instance count for memory func test ASSERT_DEATH(YGSetMemoryFuncs(NULL, &testCalloc, &testRealloc, &testFree), "Cannot set memory functions: functions must be all NULL or Non-NULL"); } diff --git a/yoga/YGEnums.c b/yoga/YGEnums.c index 85e8fcf0..2af4869e 100644 --- a/yoga/YGEnums.c +++ b/yoga/YGEnums.c @@ -9,8 +9,8 @@ #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 +31,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 +41,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 +53,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 +63,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,16 +87,16 @@ const char *YGEdgeToString(const YGEdge value){ return "unknown"; } -const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){ - switch(value){ +const char *YGExperimentalFeatureToString(const YGExperimentalFeature value) { + switch (value) { case YGExperimentalFeatureWebFlexBasis: return "web-flex-basis"; } return "unknown"; } -const char *YGFlexDirectionToString(const YGFlexDirection value){ - switch(value){ +const char *YGFlexDirectionToString(const YGFlexDirection value) { + switch (value) { case YGFlexDirectionColumn: return "column"; case YGFlexDirectionColumnReverse: @@ -109,8 +109,8 @@ const char *YGFlexDirectionToString(const YGFlexDirection value){ 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: @@ -125,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: @@ -137,12 +137,14 @@ const char *YGLogLevelToString(const YGLogLevel value){ return "debug"; case YGLogLevelVerbose: return "verbose"; + case YGLogLevelFatal: + return "fatal"; } return "unknown"; } -const char *YGMeasureModeToString(const YGMeasureMode value){ - switch(value){ +const char *YGMeasureModeToString(const YGMeasureMode value) { + switch (value) { case YGMeasureModeUndefined: return "undefined"; case YGMeasureModeExactly: @@ -153,8 +155,8 @@ const char *YGMeasureModeToString(const YGMeasureMode 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: @@ -165,8 +167,8 @@ const char *YGOverflowToString(const YGOverflow value){ return "unknown"; } -const char *YGPositionTypeToString(const YGPositionType value){ - switch(value){ +const char *YGPositionTypeToString(const YGPositionType value) { + switch (value) { case YGPositionTypeRelative: return "relative"; case YGPositionTypeAbsolute: @@ -175,8 +177,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: @@ -187,8 +189,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: @@ -201,8 +203,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: @@ -212,4 +214,3 @@ const char *YGWrapToString(const YGWrap value){ } return "unknown"; } - diff --git a/yoga/YGEnums.h b/yoga/YGEnums.h index db64e3d7..8ec5829e 100644 --- a/yoga/YGEnums.h +++ b/yoga/YGEnums.h @@ -87,13 +87,14 @@ typedef YG_ENUM_BEGIN(YGJustify) { } YG_ENUM_END(YGJustify); WIN_EXPORT const char *YGJustifyToString(const YGJustify value); -#define YGLogLevelCount 5 +#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); diff --git a/yoga/YGMacros.h b/yoga/YGMacros.h index 2d8f7286..628811a9 100644 --- a/yoga/YGMacros.h +++ b/yoga/YGMacros.h @@ -24,7 +24,7 @@ #endif #ifdef WINARMDLL -#define WIN_STRUCT(type) type* +#define WIN_STRUCT(type) type * #define WIN_STRUCT_REF(value) &value #else #define WIN_STRUCT(type) type @@ -35,20 +35,6 @@ #define FB_ASSERTIONS_ENABLED 1 #endif -#if FB_ASSERTIONS_ENABLED -#define YG_ABORT() abort() -#else -#define YG_ABORT() -#endif - -#ifndef YG_ASSERT -#define YG_ASSERT(X, message) \ - if (!(X)) { \ - YGLog(YGLogLevelError, "%s", message); \ - YG_ABORT(); \ - } -#endif - #ifdef NS_ENUM // Cannot use NSInteger as NSInteger has a different size than int (which is the default type of a // enum). diff --git a/yoga/YGNodeList.c b/yoga/YGNodeList.c index d82753e2..216085cc 100644 --- a/yoga/YGNodeList.c +++ b/yoga/YGNodeList.c @@ -21,12 +21,12 @@ struct YGNodeList { YGNodeListRef YGNodeListNew(const uint32_t initialCapacity) { const YGNodeListRef list = gYGMalloc(sizeof(struct YGNodeList)); - YG_ASSERT(list != NULL, "Could not allocate memory for list"); + YGAssert(list != NULL, "Could not allocate memory for list"); list->capacity = initialCapacity; list->count = 0; list->items = gYGMalloc(sizeof(YGNodeRef) * list->capacity); - YG_ASSERT(list->items != NULL, "Could not allocate memory for items"); + YGAssert(list->items != NULL, "Could not allocate memory for items"); return list; } @@ -61,7 +61,7 @@ void YGNodeListInsert(YGNodeListRef *listp, const YGNodeRef node, const uint32_t if (list->count == list->capacity) { list->capacity *= 2; list->items = gYGRealloc(list->items, sizeof(YGNodeRef) * list->capacity); - YG_ASSERT(list->items != NULL, "Could not extend allocation for items"); + YGAssert(list->items != NULL, "Could not extend allocation for items"); } for (uint32_t i = list->count; i > index; i--) { diff --git a/yoga/Yoga.c b/yoga/Yoga.c index c24df508..63a56b7a 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -99,6 +99,8 @@ typedef struct YGConfig { bool useWebDefaults; bool useLegacyStretchBehaviour; float pointScaleFactor; + YGLogger logger; + void *context; } YGConfig; typedef struct YGNode { @@ -200,13 +202,33 @@ static YGNode gYGNodeDefaults = { }, }; +#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, - .pointScaleFactor = 1.0f + .pointScaleFactor = 1.0f, +#ifdef ANDROID + .logger = &YGAndroidLog, +#else + .logger = &YGDefaultLog, +#endif + .context = NULL, }; static void YGNodeMarkDirtyInternal(const YGNodeRef node); @@ -220,9 +242,16 @@ static YGValue YGValueZero = {.value = 0, .unit = YGUnitPoint}; #ifdef ANDROID #include -static int YGAndroidLog(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: + androidLevel = ANDROID_LOG_FATAL; + break; case YGLogLevelError: androidLevel = ANDROID_LOG_ERROR; break; @@ -239,14 +268,18 @@ static int YGAndroidLog(YGLogLevel level, const char *format, va_list args) { androidLevel = ANDROID_LOG_VERBOSE; break; } - const int result = __android_log_vprint(androidLevel, "YG-layout", format, args); + const int result = __android_log_vprint(androidLevel, "yoga", format, args); return result; } -static YGLogger gLogger = &YGAndroidLog; #else -static int YGDefaultLog(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) { switch (level) { case YGLogLevelError: + case YGLogLevelFatal: return vfprintf(stderr, format, args); case YGLogLevelWarn: case YGLogLevelInfo: @@ -256,14 +289,11 @@ static int YGDefaultLog(YGLogLevel level, const char *format, va_list args) { return vprintf(format, args); } } -static YGLogger gLogger = &YGDefaultLog; #endif static inline const YGValue *YGComputedEdgeValue(const YGValue edges[YGEdgeCount], const YGEdge edge, const YGValue *const defaultValue) { - YG_ASSERT(edge <= YGEdgeEnd, "Cannot get computed value of multi-edge shorthands"); - if (edges[edge].unit != YGUnitUndefined) { return &edges[edge]; } @@ -311,7 +341,7 @@ int32_t gConfigInstanceCount = 0; WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { const YGNodeRef node = gYGMalloc(sizeof(YGNode)); - YG_ASSERT(node, "Could not allocate memory for node"); + YGAssertWithConfig(config, node != NULL, "Could not allocate memory for node"); gNodeInstanceCount++; memcpy(node, &gYGNodeDefaults, sizeof(YGNode)); @@ -354,9 +384,10 @@ void YGNodeFreeRecursive(const YGNodeRef root) { } void YGNodeReset(const YGNodeRef node) { - YG_ASSERT(YGNodeGetChildCount(node) == 0, - "Cannot reset a node which still has children attached"); - YG_ASSERT(node->parent == NULL, "Cannot reset a node still attached to a parent"); + YGAssertWithNode(node, + YGNodeGetChildCount(node) == 0, + "Cannot reset a node which still has children attached"); + YGAssertWithNode(node, node->parent == NULL, "Cannot reset a node still attached to a parent"); YGNodeListFree(node->children); @@ -377,9 +408,15 @@ int32_t YGConfigGetInstanceCount(void) { return gConfigInstanceCount; } +// Export only for C# +YGConfigRef YGConfigGetDefault() { + return &gYGConfigDefaults; +} + YGConfigRef YGConfigNew(void) { const YGConfigRef config = gYGMalloc(sizeof(YGConfig)); - YG_ASSERT(config, "Could not allocate memory for config"); + YGLog(NULL, config != NULL, "Could not allocate memory for config"); + gConfigInstanceCount++; memcpy(config, &gYGConfigDefaults, sizeof(YGConfig)); return config; @@ -408,8 +445,9 @@ void YGNodeSetMeasureFunc(const YGNodeRef node, YGMeasureFunc measureFunc) { if (measureFunc == NULL) { node->measure = NULL; } else { - YG_ASSERT(YGNodeGetChildCount(node) == 0, - "Cannot set measure function: Nodes with measure functions cannot have children."); + YGAssertWithNode(node, + YGNodeGetChildCount(node) == 0, + "Cannot set measure function: Nodes with measure functions cannot have children."); node->measure = measureFunc; } } @@ -427,9 +465,11 @@ YGBaselineFunc YGNodeGetBaselineFunc(const YGNodeRef node) { } void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) { - YG_ASSERT(child->parent == NULL, "Child already has a parent, it must be removed first."); - YG_ASSERT(node->measure == NULL, - "Cannot add child: Nodes with measure functions cannot have children."); + YGAssertWithNode(node, child->parent == NULL, "Child already has a parent, it must be removed first."); + YGAssertWithNode(node, + node->measure == NULL, + "Cannot add child: Nodes with measure functions cannot have children."); + YGNodeListInsert(&node->children, child, index); child->parent = node; YGNodeMarkDirtyInternal(node); @@ -456,9 +496,11 @@ inline uint32_t YGNodeGetChildCount(const YGNodeRef node) { } void YGNodeMarkDirty(const YGNodeRef node) { - YG_ASSERT(node->measure != NULL, - "Only leaf nodes with custom measure functions" - "should manually mark themselves as dirty"); + YGAssertWithNode(node, + node->measure != NULL, + "Only leaf nodes with custom measure functions" + "should manually mark themselves as dirty"); + YGNodeMarkDirtyInternal(node); } @@ -488,14 +530,17 @@ float YGNodeStyleGetFlexGrow(const YGNodeRef node) { } float YGNodeStyleGetFlexShrink(const YGNodeRef node) { - return YGFloatIsUndefined(node->style.flexShrink) ? (node->config->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink) : node->style.flexShrink; + return YGFloatIsUndefined(node->style.flexShrink) + ? (node->config->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink) + : node->style.flexShrink; } static inline float YGNodeResolveFlexShrink(const YGNodeRef node) { if (!YGFloatIsUndefined(node->style.flexShrink)) { return node->style.flexShrink; } - if (!node->config->useWebDefaults && !YGFloatIsUndefined(node->style.flex) && node->style.flex < 0.0f) { + if (!node->config->useWebDefaults && !YGFloatIsUndefined(node->style.flex) && + node->style.flex < 0.0f) { return -node->style.flex; } return node->config->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; @@ -528,25 +573,23 @@ static inline const YGValue *YGNodeResolveFlexBasisPtr(const YGNodeRef node) { } \ } -#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(type, name, paramName, instanceName) \ - void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ - if (node->style.instanceName.value != paramName || \ - node->style.instanceName.unit != YGUnitPoint) { \ - node->style.instanceName.value = paramName; \ - node->style.instanceName.unit = \ - YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPoint; \ - YGNodeMarkDirtyInternal(node); \ - } \ - } \ - \ - void YGNodeStyleSet##name##Percent(const YGNodeRef node, const type paramName) { \ - if (node->style.instanceName.value != paramName || \ - node->style.instanceName.unit != YGUnitPercent) { \ - node->style.instanceName.value = paramName; \ - node->style.instanceName.unit = \ - YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \ - YGNodeMarkDirtyInternal(node); \ - } \ +#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(type, name, paramName, instanceName) \ + void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ + if (node->style.instanceName.value != paramName || \ + node->style.instanceName.unit != YGUnitPoint) { \ + node->style.instanceName.value = paramName; \ + node->style.instanceName.unit = YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPoint; \ + YGNodeMarkDirtyInternal(node); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent(const YGNodeRef node, const type paramName) { \ + if (node->style.instanceName.value != paramName || \ + node->style.instanceName.unit != YGUnitPercent) { \ + node->style.instanceName.value = paramName; \ + node->style.instanceName.unit = YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \ + YGNodeMarkDirtyInternal(node); \ + } \ } #define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(type, name, paramName, instanceName) \ @@ -653,27 +696,27 @@ static inline const YGValue *YGNodeResolveFlexBasisPtr(const YGNodeRef node) { return node->layout.instanceName; \ } -#define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \ - type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \ - YG_ASSERT(edge <= YGEdgeEnd, "Cannot get layout properties of multi-edge shorthands"); \ - \ - if (edge == YGEdgeLeft) { \ - if (node->layout.direction == YGDirectionRTL) { \ - return node->layout.instanceName[YGEdgeEnd]; \ - } else { \ - return node->layout.instanceName[YGEdgeStart]; \ - } \ - } \ - \ - if (edge == YGEdgeRight) { \ - if (node->layout.direction == YGDirectionRTL) { \ - return node->layout.instanceName[YGEdgeStart]; \ - } else { \ - return node->layout.instanceName[YGEdgeEnd]; \ - } \ - } \ - \ - return node->layout.instanceName[edge]; \ +#define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \ + type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \ + YGAssertWithNode(node, edge < YGEdgeEnd, "Cannot get layout properties of multi-edge shorthands"); \ + \ + if (edge == YGEdgeLeft) { \ + if (node->layout.direction == YGDirectionRTL) { \ + return node->layout.instanceName[YGEdgeEnd]; \ + } else { \ + return node->layout.instanceName[YGEdgeStart]; \ + } \ + } \ + \ + if (edge == YGEdgeRight) { \ + if (node->layout.direction == YGDirectionRTL) { \ + return node->layout.instanceName[YGEdgeStart]; \ + } else { \ + return node->layout.instanceName[YGEdgeEnd]; \ + } \ + } \ + \ + return node->layout.instanceName[edge]; \ } YG_NODE_PROPERTY_IMPL(void *, Context, context, context); @@ -772,42 +815,53 @@ static inline bool YGFloatsEqual(const float a, const float b) { return fabs(a - b) < 0.0001f; } -static void YGIndent(const uint32_t n) { +static void YGIndent(const YGNodeRef node, const uint32_t n) { for (uint32_t i = 0; i < n; i++) { - YGLog(YGLogLevelDebug, " "); + YGLog(node, YGLogLevelDebug, " "); } } -static void YGPrintNumberIfNotUndefinedf(const char *str, const float number) { +static void YGPrintNumberIfNotUndefinedf(const YGNodeRef node, + const char *str, + const float number) { if (!YGFloatIsUndefined(number)) { - YGLog(YGLogLevelDebug, "%s: %g; ", str, number); + YGLog(node, YGLogLevelDebug, "%s: %g; ", str, number); } } -static void YGPrintNumberIfNotUndefined(const char *str, const YGValue *const number) { +static void YGPrintNumberIfNotUndefined(const YGNodeRef node, + const char *str, + const YGValue *const number) { if (number->unit != YGUnitUndefined) { if (number->unit == YGUnitAuto) { - YGLog(YGLogLevelDebug, "%s: auto; ", str); + YGLog(node, YGLogLevelDebug, "%s: auto; ", str); } else { const char *unit = number->unit == YGUnitPoint ? "px" : "%"; - YGLog(YGLogLevelDebug, "%s: %g%s; ", str, number->value, unit); + YGLog(node, YGLogLevelDebug, "%s: %g%s; ", str, number->value, unit); } } } -static void YGPrintNumberIfNotAuto(const char *str, const YGValue *const number) { +static void YGPrintNumberIfNotAuto(const YGNodeRef node, + const char *str, + const YGValue *const number) { if (number->unit != YGUnitAuto) { - YGPrintNumberIfNotUndefined(str, number); + YGPrintNumberIfNotUndefined(node, str, number); } } -static void YGPrintEdgeIfNotUndefined(const char *str, const YGValue *edges, const YGEdge edge) { - YGPrintNumberIfNotUndefined(str, YGComputedEdgeValue(edges, YGEdgeLeft, &YGValueUndefined)); +static void YGPrintEdgeIfNotUndefined(const YGNodeRef node, + const char *str, + const YGValue *edges, + const YGEdge edge) { + YGPrintNumberIfNotUndefined(node, str, YGComputedEdgeValue(edges, YGEdgeLeft, &YGValueUndefined)); } -static void YGPrintNumberIfNotZero(const char *str, const YGValue *const number) { +static void YGPrintNumberIfNotZero(const YGNodeRef node, + const char *str, + const YGValue *const number) { if (!YGFloatsEqual(number->value, 0)) { - YGPrintNumberIfNotUndefined(str, number); + YGPrintNumberIfNotUndefined(node, str, number); } } @@ -816,14 +870,14 @@ static bool YGFourValuesEqual(const YGValue four[4]) { YGValueEqual(four[0], four[3]); } -static void YGPrintEdges(const char *str, const YGValue *edges) { +static void YGPrintEdges(const YGNodeRef node, const char *str, const YGValue *edges) { if (YGFourValuesEqual(edges)) { - YGPrintNumberIfNotZero(str, &edges[YGEdgeLeft]); + YGPrintNumberIfNotZero(node, str, &edges[YGEdgeLeft]); } else { for (YGEdge edge = YGEdgeLeft; edge < YGEdgeCount; edge++) { char buf[30]; snprintf(buf, sizeof(buf), "%s-%s", str, YGEdgeToString(edge)); - YGPrintNumberIfNotZero(buf, &edges[edge]); + YGPrintNumberIfNotZero(node, buf, &edges[edge]); } } } @@ -831,98 +885,103 @@ static void YGPrintEdges(const char *str, const YGValue *edges) { static void YGNodePrintInternal(const YGNodeRef node, const YGPrintOptions options, const uint32_t level) { - YGIndent(level); - YGLog(YGLogLevelDebug, "
print) { node->print(node); } if (options & YGPrintOptionsLayout) { - YGLog(YGLogLevelDebug, "layout=\""); - YGLog(YGLogLevelDebug, "width: %g; ", node->layout.dimensions[YGDimensionWidth]); - YGLog(YGLogLevelDebug, "height: %g; ", node->layout.dimensions[YGDimensionHeight]); - YGLog(YGLogLevelDebug, "top: %g; ", node->layout.position[YGEdgeTop]); - YGLog(YGLogLevelDebug, "left: %g;", node->layout.position[YGEdgeLeft]); - YGLog(YGLogLevelDebug, "\" "); + YGLog(node, YGLogLevelDebug, "layout=\""); + YGLog(node, YGLogLevelDebug, "width: %g; ", node->layout.dimensions[YGDimensionWidth]); + YGLog(node, YGLogLevelDebug, "height: %g; ", node->layout.dimensions[YGDimensionHeight]); + YGLog(node, YGLogLevelDebug, "top: %g; ", node->layout.position[YGEdgeTop]); + YGLog(node, YGLogLevelDebug, "left: %g;", node->layout.position[YGEdgeLeft]); + YGLog(node, YGLogLevelDebug, "\" "); } if (options & YGPrintOptionsStyle) { - YGLog(YGLogLevelDebug, "style=\""); + YGLog(node, YGLogLevelDebug, "style=\""); if (node->style.flexDirection != gYGNodeDefaults.style.flexDirection) { - YGLog(YGLogLevelDebug, + YGLog(node, + YGLogLevelDebug, "flex-direction: %s; ", YGFlexDirectionToString(node->style.flexDirection)); } if (node->style.justifyContent != gYGNodeDefaults.style.justifyContent) { - YGLog(YGLogLevelDebug, + YGLog(node, + YGLogLevelDebug, "justify-content: %s; ", YGJustifyToString(node->style.justifyContent)); } if (node->style.alignItems != gYGNodeDefaults.style.alignItems) { - YGLog(YGLogLevelDebug, "align-items: %s; ", YGAlignToString(node->style.alignItems)); + YGLog(node, YGLogLevelDebug, "align-items: %s; ", YGAlignToString(node->style.alignItems)); } if (node->style.alignContent != gYGNodeDefaults.style.alignContent) { - YGLog(YGLogLevelDebug, "align-content: %s; ", YGAlignToString(node->style.alignContent)); + YGLog(node, YGLogLevelDebug, "align-content: %s; ", YGAlignToString(node->style.alignContent)); } if (node->style.alignSelf != gYGNodeDefaults.style.alignSelf) { - YGLog(YGLogLevelDebug, "align-self: %s; ", YGAlignToString(node->style.alignSelf)); + YGLog(node, YGLogLevelDebug, "align-self: %s; ", YGAlignToString(node->style.alignSelf)); } - YGPrintNumberIfNotUndefinedf("flex-grow", node->style.flexGrow); - YGPrintNumberIfNotUndefinedf("flex-shrink", node->style.flexShrink); - YGPrintNumberIfNotAuto("flex-basis", &node->style.flexBasis); - YGPrintNumberIfNotUndefinedf("flex", node->style.flex); + YGPrintNumberIfNotUndefinedf(node, "flex-grow", node->style.flexGrow); + YGPrintNumberIfNotUndefinedf(node, "flex-shrink", node->style.flexShrink); + YGPrintNumberIfNotAuto(node, "flex-basis", &node->style.flexBasis); + YGPrintNumberIfNotUndefinedf(node, "flex", node->style.flex); if (node->style.flexWrap != gYGNodeDefaults.style.flexWrap) { - YGLog(YGLogLevelDebug, "flexWrap: %s; ", YGWrapToString(node->style.flexWrap)); + YGLog(node, YGLogLevelDebug, "flexWrap: %s; ", YGWrapToString(node->style.flexWrap)); } if (node->style.overflow != gYGNodeDefaults.style.overflow) { - YGLog(YGLogLevelDebug, "overflow: %s; ", YGOverflowToString(node->style.overflow)); + YGLog(node, YGLogLevelDebug, "overflow: %s; ", YGOverflowToString(node->style.overflow)); } if (node->style.display != gYGNodeDefaults.style.display) { - YGLog(YGLogLevelDebug, "display: %s; ", YGDisplayToString(node->style.display)); + YGLog(node, YGLogLevelDebug, "display: %s; ", YGDisplayToString(node->style.display)); } - YGPrintEdges("margin", node->style.margin); - YGPrintEdges("padding", node->style.padding); - YGPrintEdges("border", node->style.border); + YGPrintEdges(node, "margin", node->style.margin); + YGPrintEdges(node, "padding", node->style.padding); + YGPrintEdges(node, "border", node->style.border); - YGPrintNumberIfNotAuto("width", &node->style.dimensions[YGDimensionWidth]); - YGPrintNumberIfNotAuto("height", &node->style.dimensions[YGDimensionHeight]); - YGPrintNumberIfNotAuto("max-width", &node->style.maxDimensions[YGDimensionWidth]); - YGPrintNumberIfNotAuto("max-height", &node->style.maxDimensions[YGDimensionHeight]); - YGPrintNumberIfNotAuto("min-width", &node->style.minDimensions[YGDimensionWidth]); - YGPrintNumberIfNotAuto("min-height", &node->style.minDimensions[YGDimensionHeight]); + YGPrintNumberIfNotAuto(node, "width", &node->style.dimensions[YGDimensionWidth]); + YGPrintNumberIfNotAuto(node, "height", &node->style.dimensions[YGDimensionHeight]); + YGPrintNumberIfNotAuto(node, "max-width", &node->style.maxDimensions[YGDimensionWidth]); + YGPrintNumberIfNotAuto(node, "max-height", &node->style.maxDimensions[YGDimensionHeight]); + YGPrintNumberIfNotAuto(node, "min-width", &node->style.minDimensions[YGDimensionWidth]); + YGPrintNumberIfNotAuto(node, "min-height", &node->style.minDimensions[YGDimensionHeight]); if (node->style.positionType != gYGNodeDefaults.style.positionType) { - YGLog(YGLogLevelDebug, "position: %s; ", YGPositionTypeToString(node->style.positionType)); + YGLog(node, + YGLogLevelDebug, + "position: %s; ", + YGPositionTypeToString(node->style.positionType)); } - YGPrintEdgeIfNotUndefined("left", node->style.position, YGEdgeLeft); - YGPrintEdgeIfNotUndefined("right", node->style.position, YGEdgeRight); - YGPrintEdgeIfNotUndefined("top", node->style.position, YGEdgeTop); - YGPrintEdgeIfNotUndefined("bottom", node->style.position, YGEdgeBottom); - YGLog(YGLogLevelDebug, "\" "); + YGPrintEdgeIfNotUndefined(node, "left", node->style.position, YGEdgeLeft); + YGPrintEdgeIfNotUndefined(node, "right", node->style.position, YGEdgeRight); + YGPrintEdgeIfNotUndefined(node, "top", node->style.position, YGEdgeTop); + YGPrintEdgeIfNotUndefined(node, "bottom", node->style.position, YGEdgeBottom); + YGLog(node, YGLogLevelDebug, "\" "); if (node->measure != NULL) { - YGLog(YGLogLevelDebug, "has-custom-measure=\"true\""); + YGLog(node, YGLogLevelDebug, "has-custom-measure=\"true\""); } } - YGLog(YGLogLevelDebug, ">"); + YGLog(node, YGLogLevelDebug, ">"); const uint32_t childCount = YGNodeListCount(node->children); if (options & YGPrintOptionsChildren && childCount > 0) { for (uint32_t i = 0; i < childCount; i++) { - YGLog(YGLogLevelDebug, "\n"); + YGLog(node, YGLogLevelDebug, "\n"); YGNodePrintInternal(YGNodeGetChild(node, i), options, level + 1); } - YGIndent(level); - YGLog(YGLogLevelDebug, "\n"); + YGIndent(node, level); + YGLog(node, YGLogLevelDebug, "\n"); } - YGLog(YGLogLevelDebug, "
"); + YGLog(node, YGLogLevelDebug, ""); } void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) { @@ -1076,7 +1135,9 @@ static float YGBaseline(const YGNodeRef node) { const float baseline = node->baseline(node, node->layout.measuredDimensions[YGDimensionWidth], node->layout.measuredDimensions[YGDimensionHeight]); - YG_ASSERT(!YGFloatIsUndefined(baseline), "Expect custom baseline function to not return NaN") + YGAssertWithNode(node, + !YGFloatIsUndefined(baseline), + "Expect custom baseline function to not return NaN"); return baseline; } @@ -1459,8 +1520,12 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, YGConstrainMaxSizeForMode( child, YGFlexDirectionRow, parentWidth, parentWidth, &childWidthMeasureMode, &childWidth); - YGConstrainMaxSizeForMode( - child, YGFlexDirectionColumn, parentHeight, parentWidth, &childHeightMeasureMode, &childHeight); + YGConstrainMaxSizeForMode(child, + YGFlexDirectionColumn, + parentHeight, + parentWidth, + &childHeightMeasureMode, + &childHeight); // Measure the child YGLayoutNodeInternal(child, @@ -1640,7 +1705,7 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, const YGMeasureMode heightMeasureMode, const float parentWidth, const float parentHeight) { - YG_ASSERT(node->measure, "Expected node to have custom measure function"); + YGAssertWithNode(node, node->measure != NULL, "Expected node to have custom measure function"); const float paddingAndBorderAxisRow = YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); @@ -1876,13 +1941,14 @@ static void YGNodelayoutImpl(const YGNodeRef node, const float parentHeight, const bool performLayout, const YGConfigRef config) { - YG_ASSERT(YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined : true, - "availableWidth is indefinite so widthMeasureMode must be " - "YGMeasureModeUndefined"); - YG_ASSERT(YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined - : true, - "availableHeight is indefinite so heightMeasureMode must be " - "YGMeasureModeUndefined"); + YGAssertWithNode(node, + YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined : true, + "availableWidth is indefinite so widthMeasureMode must be " + "YGMeasureModeUndefined"); + YGAssertWithNode(node, + YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined : true, + "availableHeight is indefinite so heightMeasureMode must be " + "YGMeasureModeUndefined"); // Set the resolved resolution in the node's layout. const YGDirection direction = YGNodeResolveDirection(node, parentDirection); @@ -2203,10 +2269,12 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (measureModeMainDim != YGMeasureModeExactly) { if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) { availableInnerMainDim = minInnerMainDim; - } else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) { + } else if (!YGFloatIsUndefined(maxInnerMainDim) && + sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; } else { - if (!node->config->useLegacyStretchBehaviour && (totalFlexGrowFactors == 0 || YGResolveFlexGrow(node) == 0)) { + if (!node->config->useLegacyStretchBehaviour && + (totalFlexGrowFactors == 0 || YGResolveFlexGrow(node) == 0)) { // If we don't have any children to flex or we can't flex the node itself, // space we've used is all space we need availableInnerMainDim = sizeConsumedOnCurrentLine; @@ -2218,7 +2286,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (!YGFloatIsUndefined(availableInnerMainDim)) { remainingFreeSpace = availableInnerMainDim - sizeConsumedOnCurrentLine; } else if (sizeConsumedOnCurrentLine < 0) { - // availableInnerMainDim is indefinite which means the node is being sized based on its content. + // availableInnerMainDim is indefinite which means the node is being sized based on its + // content. // sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for // its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine. remainingFreeSpace = -sizeConsumedOnCurrentLine; @@ -3281,7 +3350,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, } void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint) { - YG_ASSERT(pixelsInPoint >= 0.0f, "Scale factor should not be less than zero"); + 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 @@ -3291,7 +3361,10 @@ void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInP } } -static float YGRoundValueToPixelGrid(const float value, const float pointScaleFactor, const bool forceCeil, const bool forceFloor) { +static float YGRoundValueToPixelGrid(const float value, + const float pointScaleFactor, + const bool forceCeil, + const bool forceFloor) { float fractial = fmodf(value, pointScaleFactor); if (YGFloatsEqual(fractial, 0)) { // Still remove fractial as fractial could be extremely small. @@ -3307,7 +3380,10 @@ static float YGRoundValueToPixelGrid(const float value, const float pointScaleFa } } -static void YGRoundToPixelGrid(const YGNodeRef node, const float pointScaleFactor, const float absoluteLeft, const float absoluteTop) { +static void YGRoundToPixelGrid(const YGNodeRef node, + const float pointScaleFactor, + const float absoluteLeft, + const float absoluteTop) { if (pointScaleFactor == 0.0f) { return; } @@ -3328,13 +3404,17 @@ static void YGRoundToPixelGrid(const YGNodeRef node, const float pointScaleFacto // lead to unwanted text truncation. const bool hasMeasure = node->measure != NULL; - node->layout.position[YGEdgeLeft] = YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, hasMeasure); - node->layout.position[YGEdgeTop] = YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, hasMeasure); + node->layout.position[YGEdgeLeft] = + YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, hasMeasure); + node->layout.position[YGEdgeTop] = + YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, hasMeasure); node->layout.dimensions[YGDimensionWidth] = - YGRoundValueToPixelGrid(absoluteNodeRight, pointScaleFactor, hasMeasure, false) - YGRoundValueToPixelGrid(absoluteNodeLeft, pointScaleFactor, false, hasMeasure); + YGRoundValueToPixelGrid(absoluteNodeRight, pointScaleFactor, hasMeasure, false) - + YGRoundValueToPixelGrid(absoluteNodeLeft, pointScaleFactor, false, hasMeasure); node->layout.dimensions[YGDimensionHeight] = - YGRoundValueToPixelGrid(absoluteNodeBottom, pointScaleFactor, hasMeasure, false) - YGRoundValueToPixelGrid(absoluteNodeTop, pointScaleFactor, false, hasMeasure); + YGRoundValueToPixelGrid(absoluteNodeBottom, pointScaleFactor, hasMeasure, false) - + YGRoundValueToPixelGrid(absoluteNodeTop, pointScaleFactor, false, hasMeasure); const uint32_t childCount = YGNodeListCount(node->children); for (uint32_t i = 0; i < childCount; i++) { @@ -3375,8 +3455,7 @@ void YGNodeCalculateLayout(const YGNodeRef node, height = YGResolveValue(node->resolvedDimensions[dim[YGFlexDirectionColumn]], parentHeight) + YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth); heightMeasureMode = YGMeasureModeExactly; - } else if (YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], parentHeight) >= - 0.0f) { + } else if (YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], parentHeight) >= 0.0f) { height = YGResolveValue(&node->style.maxDimensions[YGDimensionHeight], parentHeight); heightMeasureMode = YGMeasureModeAtMost; } else { @@ -3404,33 +3483,71 @@ void YGNodeCalculateLayout(const YGNodeRef node, } } -void YGSetLogger(YGLogger logger) { +void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { if (logger != NULL) { - gLogger = logger; + config->logger = logger; } else { #ifdef ANDROID - gLogger = &YGAndroidLog; + config->logger = &YGAndroidLog; #else - gLogger = &YGDefaultLog; + config->logger = &YGDefaultLog; #endif } } -void YGLog(YGLogLevel level, const char *format, ...) { +static void YGVLog(const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + const char *format, + va_list args) { + const YGConfigRef logConfig = config != NULL ? config : &gYGConfigDefaults; + logConfig->logger(logConfig, node, level, format, args); + + if (level == YGLogLevelFatal) { + abort(); + } +} + +void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...) { va_list args; va_start(args, format); - gLogger(level, format, args); + YGVLog(config, NULL, 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 == NULL ? NULL : node->config, node, level, format, args); + va_end(args); +} + +void YGAssert(const bool condition, const char *message) { + if (!condition) { + YGLog(NULL, YGLogLevelFatal, "%s\n", message); + } +} + +void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message) { + if (!condition) { + YGLog(node, YGLogLevelFatal, "%s\n", message); + } +} + +void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message) { + if (!condition) { + YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message); + } +} + void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config, - const YGExperimentalFeature feature, - const bool enabled) { + const YGExperimentalFeature feature, + const bool enabled) { config->experimentalFeatures[feature] = enabled; } inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config, - const YGExperimentalFeature feature) { + const YGExperimentalFeature feature) { return config->experimentalFeatures[feature]; } @@ -3438,7 +3555,8 @@ void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) { config->useWebDefaults = enabled; } -void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config, const bool useLegacyStretchBehaviour) { +void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config, + const bool useLegacyStretchBehaviour) { config->useLegacyStretchBehaviour = useLegacyStretchBehaviour; } @@ -3446,12 +3564,20 @@ bool YGConfigGetUseWebDefaults(const YGConfigRef config) { return config->useWebDefaults; } +void YGConfigSetContext(const YGConfigRef config, void *context) { + config->context = context; +} + +void *YGConfigGetContext(const YGConfigRef config) { + return config->context; +} + void YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree) { - YG_ASSERT(gNodeInstanceCount == 0 && gConfigInstanceCount == 0, - "Cannot set memory functions: all node must be freed first"); - YG_ASSERT((ygmalloc == NULL && yccalloc == NULL && ygrealloc == NULL && ygfree == NULL) || - (ygmalloc != NULL && yccalloc != NULL && ygrealloc != NULL && ygfree != NULL), - "Cannot set memory functions: functions must be all NULL or Non-NULL"); + YGAssert(gNodeInstanceCount == 0 && gConfigInstanceCount == 0, + "Cannot set memory functions: all node must be freed first"); + YGAssert((ygmalloc == NULL && yccalloc == NULL && ygrealloc == NULL && ygfree == NULL) || + (ygmalloc != NULL && yccalloc != NULL && ygrealloc != NULL && ygfree != NULL), + "Cannot set memory functions: functions must be all NULL or Non-NULL"); if (ygmalloc == NULL || yccalloc == NULL || ygrealloc == NULL || ygfree == NULL) { gYGMalloc = &malloc; diff --git a/yoga/Yoga.h b/yoga/Yoga.h index a26a1e9a..b18f3dbc 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -55,7 +55,11 @@ typedef YGSize (*YGMeasureFunc)(YGNodeRef node, YGMeasureMode heightMode); typedef float (*YGBaselineFunc)(YGNodeRef node, const float width, const float height); typedef void (*YGPrintFunc)(YGNodeRef node); -typedef int (*YGLogger)(YGLogLevel level, const char *format, va_list args); +typedef int (*YGLogger)(const YGConfigRef config, + const YGNodeRef node, + YGLogLevel level, + const char *format, + va_list args); typedef void *(*YGMalloc)(size_t size); typedef void *(*YGCalloc)(size_t count, size_t size); @@ -218,17 +222,27 @@ YG_NODE_LAYOUT_EDGE_PROPERTY(float, Margin); YG_NODE_LAYOUT_EDGE_PROPERTY(float, Border); YG_NODE_LAYOUT_EDGE_PROPERTY(float, Padding); -WIN_EXPORT void YGSetLogger(YGLogger logger); -WIN_EXPORT void YGLog(YGLogLevel level, const char *message, ...); +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); +// 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); @@ -245,9 +259,14 @@ WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(const 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); +// Export only for C# +WIN_EXPORT YGConfigRef YGConfigGetDefault(void); + +WIN_EXPORT void YGConfigSetContext(const YGConfigRef config, void *context); +WIN_EXPORT void *YGConfigGetContext(const YGConfigRef config); + WIN_EXPORT void YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree);