diff --git a/CSSLayout/CSSLayout.c b/CSSLayout/CSSLayout.c index 0e1d37d6..33a5ad5c 100644 --- a/CSSLayout/CSSLayout.c +++ b/CSSLayout/CSSLayout.c @@ -98,6 +98,8 @@ typedef struct CSSNode { static void _CSSNodeMarkDirty(const CSSNodeRef node); +static CSSLogger gLogger = &printf; + static float computedEdgeValue(const float edges[CSSEdgeCount], const CSSEdge edge, const float defaultValue) { CSS_ASSERT(edge <= CSSEdgeEnd, "Cannot get computed value of multi-edge shorthands"); @@ -375,19 +377,19 @@ static bool eq(const float a, const float b) { static void indent(const uint32_t n) { for (uint32_t i = 0; i < n; i++) { - printf(" "); + gLogger(" "); } } static void printNumberIfNotZero(const char *str, const float number) { if (!eq(number, 0)) { - printf("%s: %g, ", str, number); + gLogger("%s: %g, ", str, number); } } static void printNumberIfNotUndefined(const char *str, const float number) { if (!CSSValueIsUndefined(number)) { - printf("%s: %g, ", str, number); + gLogger("%s: %g, ", str, number); } } @@ -398,66 +400,66 @@ static bool eqFour(const float four[4]) { static void _CSSNodePrint(const CSSNodeRef node, const CSSPrintOptions options, const uint32_t level) { indent(level); - printf("{"); + gLogger("{"); if (node->print) { node->print(node->context); } if (options & CSSPrintOptionsLayout) { - printf("layout: {"); - printf("width: %g, ", node->layout.dimensions[CSSDimensionWidth]); - printf("height: %g, ", node->layout.dimensions[CSSDimensionHeight]); - printf("top: %g, ", node->layout.position[CSSEdgeTop]); - printf("left: %g", node->layout.position[CSSEdgeLeft]); - printf("}, "); + gLogger("layout: {"); + gLogger("width: %g, ", node->layout.dimensions[CSSDimensionWidth]); + gLogger("height: %g, ", node->layout.dimensions[CSSDimensionHeight]); + gLogger("top: %g, ", node->layout.position[CSSEdgeTop]); + gLogger("left: %g", node->layout.position[CSSEdgeLeft]); + gLogger("}, "); } if (options & CSSPrintOptionsStyle) { if (node->style.flexDirection == CSSFlexDirectionColumn) { - printf("flexDirection: 'column', "); + gLogger("flexDirection: 'column', "); } else if (node->style.flexDirection == CSSFlexDirectionColumnReverse) { - printf("flexDirection: 'column-reverse', "); + gLogger("flexDirection: 'column-reverse', "); } else if (node->style.flexDirection == CSSFlexDirectionRow) { - printf("flexDirection: 'row', "); + gLogger("flexDirection: 'row', "); } else if (node->style.flexDirection == CSSFlexDirectionRowReverse) { - printf("flexDirection: 'row-reverse', "); + gLogger("flexDirection: 'row-reverse', "); } if (node->style.justifyContent == CSSJustifyCenter) { - printf("justifyContent: 'center', "); + gLogger("justifyContent: 'center', "); } else if (node->style.justifyContent == CSSJustifyFlexEnd) { - printf("justifyContent: 'flex-end', "); + gLogger("justifyContent: 'flex-end', "); } else if (node->style.justifyContent == CSSJustifySpaceAround) { - printf("justifyContent: 'space-around', "); + gLogger("justifyContent: 'space-around', "); } else if (node->style.justifyContent == CSSJustifySpaceBetween) { - printf("justifyContent: 'space-between', "); + gLogger("justifyContent: 'space-between', "); } if (node->style.alignItems == CSSAlignCenter) { - printf("alignItems: 'center', "); + gLogger("alignItems: 'center', "); } else if (node->style.alignItems == CSSAlignFlexEnd) { - printf("alignItems: 'flex-end', "); + gLogger("alignItems: 'flex-end', "); } else if (node->style.alignItems == CSSAlignStretch) { - printf("alignItems: 'stretch', "); + gLogger("alignItems: 'stretch', "); } if (node->style.alignContent == CSSAlignCenter) { - printf("alignContent: 'center', "); + gLogger("alignContent: 'center', "); } else if (node->style.alignContent == CSSAlignFlexEnd) { - printf("alignContent: 'flex-end', "); + gLogger("alignContent: 'flex-end', "); } else if (node->style.alignContent == CSSAlignStretch) { - printf("alignContent: 'stretch', "); + gLogger("alignContent: 'stretch', "); } if (node->style.alignSelf == CSSAlignFlexStart) { - printf("alignSelf: 'flex-start', "); + gLogger("alignSelf: 'flex-start', "); } else if (node->style.alignSelf == CSSAlignCenter) { - printf("alignSelf: 'center', "); + gLogger("alignSelf: 'center', "); } else if (node->style.alignSelf == CSSAlignFlexEnd) { - printf("alignSelf: 'flex-end', "); + gLogger("alignSelf: 'flex-end', "); } else if (node->style.alignSelf == CSSAlignStretch) { - printf("alignSelf: 'stretch', "); + gLogger("alignSelf: 'stretch', "); } printNumberIfNotUndefined("flexGrow", node->style.flexGrow); @@ -465,11 +467,11 @@ _CSSNodePrint(const CSSNodeRef node, const CSSPrintOptions options, const uint32 printNumberIfNotUndefined("flexBasis", node->style.flexBasis); if (node->style.overflow == CSSOverflowHidden) { - printf("overflow: 'hidden', "); + gLogger("overflow: 'hidden', "); } else if (node->style.overflow == CSSOverflowVisible) { - printf("overflow: 'visible', "); + gLogger("overflow: 'visible', "); } else if (node->style.overflow == CSSOverflowScroll) { - printf("overflow: 'scroll', "); + gLogger("overflow: 'scroll', "); } if (eqFour(node->style.margin)) { @@ -518,7 +520,7 @@ _CSSNodePrint(const CSSNodeRef node, const CSSPrintOptions options, const uint32 printNumberIfNotUndefined("minHeight", node->style.minDimensions[CSSDimensionHeight]); if (node->style.positionType == CSSPositionTypeAbsolute) { - printf("position: 'absolute', "); + gLogger("position: 'absolute', "); } printNumberIfNotUndefined("left", @@ -533,14 +535,14 @@ _CSSNodePrint(const CSSNodeRef node, const CSSPrintOptions options, const uint32 const uint32_t childCount = CSSNodeListCount(node->children); if (options & CSSPrintOptionsChildren && childCount > 0) { - printf("children: [\n"); + gLogger("children: [\n"); for (uint32_t i = 0; i < childCount; i++) { _CSSNodePrint(CSSNodeGetChild(node, i), options, level + 1); } indent(level); - printf("]},\n"); + gLogger("]},\n"); } else { - printf("},\n"); + gLogger("},\n"); } } @@ -2363,6 +2365,10 @@ void CSSNodeCalculateLayout(const CSSNodeRef node, } } +void CSSLayoutSetLogger(CSSLogger logger) { + gLogger = logger; +} + #ifdef CSS_ASSERT_FAIL_ENABLED static CSSAssertFailFunc gAssertFailFunc; diff --git a/CSSLayout/CSSLayout.h b/CSSLayout/CSSLayout.h index 7289492d..18cecdda 100644 --- a/CSSLayout/CSSLayout.h +++ b/CSSLayout/CSSLayout.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -121,6 +122,7 @@ typedef CSSSize (*CSSMeasureFunc)(void *context, float height, CSSMeasureMode heightMode); typedef void (*CSSPrintFunc)(void *context); +typedef int (*CSSLogger)(const char *format, ...); #ifdef CSS_ASSERT_FAIL_ENABLED typedef void (*CSSAssertFailFunc)(const char *message); @@ -210,6 +212,8 @@ CSS_NODE_LAYOUT_PROPERTY(float, Width); CSS_NODE_LAYOUT_PROPERTY(float, Height); CSS_NODE_LAYOUT_PROPERTY(CSSDirection, Direction); +WIN_EXPORT void CSSLayoutSetLogger(CSSLogger logger); + #ifdef CSS_ASSERT_FAIL_ENABLED // Assert WIN_EXPORT void CSSAssertSetFailFunc(CSSAssertFailFunc func); diff --git a/csharp/CSSLayout/CSSInterop.cpp b/csharp/CSSLayout/CSSInterop.cpp new file mode 100644 index 00000000..56c5597e --- /dev/null +++ b/csharp/CSSLayout/CSSInterop.cpp @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include "CSSInterop.h" + +static CSSInteropLoggerFunc gManagedFunc; + +static int unmanagedLogger(const char *format, ...) { + int result = 0; + if (gManagedFunc) { + va_list args; + va_start(args, format); + char buffer[256]; + result = vsnprintf(buffer, sizeof(buffer), format, args); + (*gManagedFunc)(buffer); + va_end(args); + } + return result; +} + +void CSSInteropSetLogger(CSSInteropLoggerFunc managedFunc) { + gManagedFunc = managedFunc; + CSSLayoutSetLogger(&unmanagedLogger); +} diff --git a/csharp/Facebook.CSSLayout/CSSPrintFunc.cs b/csharp/CSSLayout/CSSInterop.h old mode 100644 new mode 100755 similarity index 58% rename from csharp/Facebook.CSSLayout/CSSPrintFunc.cs rename to csharp/CSSLayout/CSSInterop.h index 1a308c03..7533cfd3 --- a/csharp/Facebook.CSSLayout/CSSPrintFunc.cs +++ b/csharp/CSSLayout/CSSInterop.h @@ -1,4 +1,4 @@ -/** +/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * @@ -7,9 +7,14 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -using System; +#pragma once -namespace Facebook.CSSLayout -{ - public delegate void CSSPrintFunc(IntPtr context); -} +#include + +CSS_EXTERN_C_BEGIN + +typedef void (*CSSInteropLoggerFunc)(const char *message); + +WIN_EXPORT void CSSInteropSetLogger(CSSInteropLoggerFunc managedFunc); + +CSS_EXTERN_C_END diff --git a/csharp/CSSLayout/CSSLayout.vcxproj b/csharp/CSSLayout/CSSLayout.vcxproj index 1037691d..199eb3e8 100755 --- a/csharp/CSSLayout/CSSLayout.vcxproj +++ b/csharp/CSSLayout/CSSLayout.vcxproj @@ -1,177 +1,183 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {0446C86B-F47B-4C46-B673-C7AE0CFF35D5} - Win32Proj - CSSLayout - 10.0.10586.0 - - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) - true - - - Windows - true - - - - - - - Level3 - Disabled - _DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) - true - - - Windows - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - - - - - - - - - - - - - - false - - - false - - - false - - - false - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {0446C86B-F47B-4C46-B673-C7AE0CFF35D5} + Win32Proj + CSSLayout + 10.0.14393.0 + + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + + + Level3 + Disabled + _DEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_WINDOWS;_USRDLL;CSSLAYOUT_EXPORTS;CSS_ASSERT_FAIL_ENABLED;FB_ASSERTIONS_ENABLED=0;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + + + + + + + \ No newline at end of file diff --git a/csharp/CSSLayout/CSSLayout.vcxproj.filters b/csharp/CSSLayout/CSSLayout.vcxproj.filters old mode 100644 new mode 100755 index bac85caa..07197766 --- a/csharp/CSSLayout/CSSLayout.vcxproj.filters +++ b/csharp/CSSLayout/CSSLayout.vcxproj.filters @@ -30,6 +30,9 @@ Header Files + + Header Files + @@ -44,5 +47,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/csharp/Facebook.CSSLayout/CSSAssert.cs b/csharp/Facebook.CSSLayout/CSSAssert.cs index adb0aada..606fbb4c 100644 --- a/csharp/Facebook.CSSLayout/CSSAssert.cs +++ b/csharp/Facebook.CSSLayout/CSSAssert.cs @@ -16,14 +16,16 @@ namespace Facebook.CSSLayout public delegate void FailFunc(string message); private static bool _assertInitialized; + private static FailFunc _failFunc; public static void Initialize() { if (!_assertInitialized) { - Native.CSSAssertSetFailFunc((message) => { + _failFunc = (message) => { throw new InvalidOperationException(message); - }); + }; + Native.CSSAssertSetFailFunc(_failFunc); _assertInitialized = true; } } diff --git a/csharp/Facebook.CSSLayout/CSSLogger.cs b/csharp/Facebook.CSSLayout/CSSLogger.cs new file mode 100644 index 00000000..e4959ff4 --- /dev/null +++ b/csharp/Facebook.CSSLayout/CSSLogger.cs @@ -0,0 +1,38 @@ +/** + * 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; + +namespace Facebook.CSSLayout +{ + internal static class CSSLogger + { + public delegate void Func(string message); + + private static bool _initialized; + private static Func _managedLogger = null; + + public static Func Logger = null; + + public static void Initialize() + { + if (!_initialized) + { + _managedLogger = (message) => { + if (Logger != null) + { + Logger(message); + } + }; + Native.CSSInteropSetLogger(_managedLogger); + _initialized = true; + } + } + } +} diff --git a/csharp/Facebook.CSSLayout/CSSNode.cs b/csharp/Facebook.CSSLayout/CSSNode.cs index 496e1f29..6eccf403 100644 --- a/csharp/Facebook.CSSLayout/CSSNode.cs +++ b/csharp/Facebook.CSSLayout/CSSNode.cs @@ -11,6 +11,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Text; namespace Facebook.CSSLayout { @@ -110,9 +111,9 @@ namespace Facebook.CSSLayout } CSSAssert.Initialize(); + CSSLogger.Initialize(); _cssNode = Native.CSSNodeNew(); _children = new List(4); - Native.CSSNodeSetPrintFunc(_cssNode, PrintInternal); } public void Free() @@ -704,9 +705,14 @@ namespace Facebook.CSSLayout return new CSSSize { width = measureResult.Width, height = measureResult.Height }; } - private void PrintInternal(IntPtr context) + public string Print(CSSPrintOptions options = CSSPrintOptions.Layout|CSSPrintOptions.Style|CSSPrintOptions.Children) { - System.Diagnostics.Debug.WriteLine(ToString()); + AssertNativeInstance(); + StringBuilder sb = new StringBuilder(); + CSSLogger.Logger = (message) => {sb.Append(message);}; + Native.CSSNodePrint(_cssNode, options); + CSSLogger.Logger = null; + return sb.ToString(); } public IEnumerator GetEnumerator() diff --git a/csharp/Facebook.CSSLayout/Native.cs b/csharp/Facebook.CSSLayout/Native.cs index 90d387ef..1066dd14 100644 --- a/csharp/Facebook.CSSLayout/Native.cs +++ b/csharp/Facebook.CSSLayout/Native.cs @@ -20,6 +20,9 @@ namespace Facebook.CSSLayout private const string DllName = "CSSLayout"; #endif + [DllImport(DllName)] + public static extern void CSSInteropSetLogger(CSSLogger.Func func); + [DllImport(DllName)] public static extern void CSSAssertSetFailFunc(CSSAssert.FailFunc func); @@ -81,12 +84,6 @@ namespace Facebook.CSSLayout [DllImport(DllName)] public static extern CSSMeasureFunc CSSNodeGetMeasureFunc(IntPtr node); - [DllImport(DllName)] - public static extern void CSSNodeSetPrintFunc(IntPtr node, CSSPrintFunc printFunc); - - [DllImport(DllName)] - public static extern CSSPrintFunc CSSNodeGePrintFunc(IntPtr node); - [DllImport(DllName)] public static extern void CSSNodeSetIsTextnode(IntPtr node, [MarshalAs(UnmanagedType.I1)] bool isTextNode); diff --git a/csharp/tests/Facebook.CSSLayout/CSSNodeTest.cs b/csharp/tests/Facebook.CSSLayout/CSSNodeTest.cs index 08c096f7..a9eef99d 100644 --- a/csharp/tests/Facebook.CSSLayout/CSSNodeTest.cs +++ b/csharp/tests/Facebook.CSSLayout/CSSNodeTest.cs @@ -178,6 +178,24 @@ namespace Facebook.CSSLayout Assert.AreEqual(150, (int)node.LayoutHeight); } + [Test] + public void TestPrint() + { + CSSNode parent = new CSSNode(); + parent.StyleWidth = 100; + parent.StyleHeight = 120; + CSSNode child0 = new CSSNode(); + child0.StyleWidth = 30; + child0.StyleHeight = 40; + CSSNode child1 = new CSSNode(); + child1.StyleWidth = 35; + child1.StyleHeight = 45; + parent.Insert(0, child0); + parent.Insert(0, child1); + parent.CalculateLayout(); + Assert.AreEqual(parent.Print(), "{layout: {width: 100, height: 120, top: 0, left: 0}, flexDirection: 'column', alignItems: 'stretch', flexGrow: 0, flexShrink: 0, overflow: 'visible', width: 100, height: 120, children: [\n {layout: {width: 35, height: 45, top: 0, left: 0}, flexDirection: 'column', alignItems: 'stretch', flexGrow: 0, flexShrink: 0, overflow: 'visible', width: 35, height: 45, },\n {layout: {width: 30, height: 40, top: 45, left: 0}, flexDirection: 'column', alignItems: 'stretch', flexGrow: 0, flexShrink: 0, overflow: 'visible', width: 30, height: 40, },\n]},\n"); + } + private void ForceGC() { GC.Collect(GC.MaxGeneration);