From c9e90fd7fc12521c54b1ba69381c61964a3550fd Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 4 May 2017 00:05:33 +0200 Subject: [PATCH 1/5] Fix type conversions. They were not correct before. Also clarified the two types of conversions: - `TryConvertImplicit` implements the implicit conversions allowed by the C# language - `TryConvert` tries every means at its disposal to convert a value to a type `AvaloniaObject` uses only implicit conversions. This allows one to write: ``` var control = new TextBlock { [Canvas.TopProperty] = 10 } ``` Without implicit conversions, this would fail because `Canvas.Top` is a `double` whereas `10` is an `int`, however only implicit conversions should be used here, otherwise the following would pass, which is probably not what would be wanted: ``` var control = new TextBlock { [TextBlock.TextProperty] = observable, // Text is now the type name of `observable` } ``` `DefaultValueConverter` uses `TryConvert`, i.e. every conversion possible. Fixes #972. --- src/Avalonia.Base/AvaloniaObject.cs | 6 +- src/Avalonia.Base/AvaloniaProperty.cs | 2 +- src/Avalonia.Base/PriorityValue.cs | 2 +- src/Avalonia.Base/Utilities/TypeUtilities.cs | 237 ++++++++++++------ .../Avalonia.Markup/DefaultValueConverter.cs | 64 ++--- .../Parsers/SelectorParserTests.cs | 17 ++ 6 files changed, 198 insertions(+), 130 deletions(-) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 7359dceae1..1492c14c5f 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -578,13 +578,13 @@ namespace Avalonia if (notification == null) { - return TypeUtilities.CastOrDefault(value, type); + return TypeUtilities.ConvertImplicitOrDefault(value, type); } else { if (notification.HasValue) { - notification.SetValue(TypeUtilities.CastOrDefault(notification.Value, type)); + notification.SetValue(TypeUtilities.ConvertImplicitOrDefault(notification.Value, type)); } return notification; @@ -735,7 +735,7 @@ namespace Avalonia ThrowNotRegistered(property); } - if (!TypeUtilities.TryCast(property.PropertyType, value, out value)) + if (!TypeUtilities.TryConvertImplicit(property.PropertyType, value, out value)) { throw new ArgumentException(string.Format( "Invalid value for Property '{0}': '{1}' ({2})", diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index 61006b1173..fb78e3b2a0 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -476,7 +476,7 @@ namespace Avalonia /// True if the value is valid, otherwise false. public bool IsValidValue(object value) { - return TypeUtilities.TryCast(PropertyType, value, out value); + return TypeUtilities.TryConvertImplicit(PropertyType, value, out value); } /// diff --git a/src/Avalonia.Base/PriorityValue.cs b/src/Avalonia.Base/PriorityValue.cs index 57e2854014..21467f3962 100644 --- a/src/Avalonia.Base/PriorityValue.cs +++ b/src/Avalonia.Base/PriorityValue.cs @@ -249,7 +249,7 @@ namespace Avalonia value = (notification.HasValue) ? notification.Value : null; } - if (TypeUtilities.TryCast(_valueType, value, out castValue)) + if (TypeUtilities.TryConvertImplicit(_valueType, value, out castValue)) { var old = _value; diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs index 7295bfa7ab..dd93811498 100644 --- a/src/Avalonia.Base/Utilities/TypeUtilities.cs +++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs @@ -14,17 +14,61 @@ namespace Avalonia.Utilities /// public static class TypeUtilities { - private static readonly Dictionary> Conversions = new Dictionary>() + private static int[] Conversions = { - { typeof(decimal), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } }, - { typeof(double), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, - { typeof(float), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, - { typeof(ulong), new List { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } }, - { typeof(long), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } }, - { typeof(uint), new List { typeof(byte), typeof(ushort), typeof(char) } }, - { typeof(int), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } }, - { typeof(ushort), new List { typeof(byte), typeof(char) } }, - { typeof(short), new List { typeof(byte) } } + 0b101111111111101, // Boolean + 0b100001111111110, // Char + 0b101111111111111, // SByte + 0b101111111111111, // Byte + 0b101111111111111, // Int16 + 0b101111111111111, // UInt16 + 0b101111111111111, // Int32 + 0b101111111111111, // UInt32 + 0b101111111111111, // Int64 + 0b101111111111111, // UInt64 + 0b101111111111101, // Single + 0b101111111111101, // Double + 0b101111111111101, // Decimal + 0b110000000000000, // DateTime + 0b111111111111111, // String + }; + + private static int[] ImplicitConversions = + { + 0b000000000000001, // Boolean + 0b001110111100010, // Char + 0b001110101010100, // SByte + 0b001111111111000, // Byte + 0b001110101010000, // Int16 + 0b001111111100000, // UInt16 + 0b001110101000000, // Int32 + 0b001111110000000, // UInt32 + 0b001110100000000, // Int64 + 0b001111000000000, // UInt64 + 0b000110000000000, // Single + 0b000100000000000, // Double + 0b001000000000000, // Decimal + 0b010000000000000, // DateTime + 0b100000000000000, // String + }; + + private static Type[] InbuiltTypes = + { + typeof(Boolean), + typeof(Char), + typeof(SByte), + typeof(Byte), + typeof(Int16), + typeof(UInt16), + typeof(Int32), + typeof(UInt32), + typeof(Int64), + typeof(UInt64), + typeof(Single), + typeof(Double), + typeof(Decimal), + typeof(DateTime), + typeof(String), }; private static readonly Type[] NumericTypes = new[] @@ -54,49 +98,104 @@ namespace Avalonia.Utilities } /// - /// Try to cast a value to a type, using implicit conversions if possible. + /// Try to convert a value to a type by any means possible. /// /// The type to cast to. /// The value to cast. + /// The culture to use. /// If sucessful, contains the cast value. /// True if the cast was sucessful, otherwise false. - public static bool TryCast(Type to, object value, out object result) + public static bool TryConvert(Type to, object value, CultureInfo culture, out object result) { - Contract.Requires(to != null); - if (value == null) { result = null; return AcceptsNull(to); } - var from = value.GetType(); - if (value == AvaloniaProperty.UnsetValue) { result = value; return true; } - else if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo())) + + var from = value.GetType(); + var fromTypeInfo = from.GetTypeInfo(); + var toTypeInfo = to.GetTypeInfo(); + + if (toTypeInfo.IsAssignableFrom(fromTypeInfo)) { result = value; return true; } - else if (Conversions.ContainsKey(to) && Conversions[to].Contains(from)) + + if (to == typeof(string)) { - result = Convert.ChangeType(value, to); + result = Convert.ToString(value); return true; } - else + + if (toTypeInfo.IsEnum && from == typeof(string)) + { + if (Enum.IsDefined(to, (string)value)) + { + result = Enum.Parse(to, (string)value); + return true; + } + } + + if (!fromTypeInfo.IsEnum && toTypeInfo.IsEnum) { - var cast = from.GetRuntimeMethods() - .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to); + result = null; + + if (TryConvert(Enum.GetUnderlyingType(to), value, culture, out object enumValue)) + { + result = Enum.ToObject(to, enumValue); + return true; + } + } - if (cast != null) + if (fromTypeInfo.IsEnum && IsNumeric(to)) + { + try { - result = cast.Invoke(null, new[] { value }); + result = Convert.ChangeType((int)value, to, culture); return true; } + catch + { + result = null; + return false; + } + } + + var convertableFrom = Array.IndexOf(InbuiltTypes, from); + var convertableTo = Array.IndexOf(InbuiltTypes, to); + + if (convertableFrom != -1 && convertableTo != -1) + { + if ((Conversions[convertableFrom] & 1 << convertableTo) != 0) + { + try + { + result = Convert.ChangeType(value, to, culture); + return true; + } + catch + { + result = null; + return false; + } + } + } + + var cast = from.GetRuntimeMethods() + .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to); + + if (cast != null) + { + result = cast.Invoke(null, new[] { value }); + return true; } result = null; @@ -104,15 +203,14 @@ namespace Avalonia.Utilities } /// - /// Try to convert a value to a type, using if possible, - /// otherwise using . + /// Try to convert a value to a type using the implicit conversions allowed by the C# + /// language. /// /// The type to cast to. /// The value to cast. - /// The culture to use. /// If sucessful, contains the cast value. /// True if the cast was sucessful, otherwise false. - public static bool TryConvert(Type to, object value, CultureInfo culture, out object result) + public static bool TryConvertImplicit(Type to, object value, out object result) { if (value == null) { @@ -120,54 +218,44 @@ namespace Avalonia.Utilities return AcceptsNull(to); } - var from = value.GetType(); - if (value == AvaloniaProperty.UnsetValue) { result = value; return true; } - if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo())) - { - result = value; - return true; - } + var from = value.GetType(); + var fromTypeInfo = from.GetTypeInfo(); + var toTypeInfo = to.GetTypeInfo(); - if (to == typeof(string)) + if (toTypeInfo.IsAssignableFrom(fromTypeInfo)) { - result = Convert.ToString(value); + result = value; return true; } - if (to.GetTypeInfo().IsEnum && from == typeof(string)) - { - if (Enum.IsDefined(to, (string)value)) - { - result = Enum.Parse(to, (string)value); - return true; - } - } - - bool containsFrom = Conversions.ContainsKey(from); - bool containsTo = Conversions.ContainsKey(to); + var convertableFrom = Array.IndexOf(InbuiltTypes, from); + var convertableTo = Array.IndexOf(InbuiltTypes, to); - if ((containsFrom && containsTo) || (from == typeof(string) && containsTo)) + if (convertableFrom != -1 && convertableTo != -1) { - try - { - result = Convert.ChangeType(value, to, culture); - return true; - } - catch + if ((ImplicitConversions[convertableFrom] & 1 << convertableTo) != 0) { - result = null; - return false; + try + { + result = Convert.ChangeType(value, to, CultureInfo.InvariantCulture); + return true; + } + catch + { + result = null; + return false; + } } } var cast = from.GetRuntimeMethods() - .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to); + .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to); if (cast != null) { @@ -180,29 +268,28 @@ namespace Avalonia.Utilities } /// - /// Casts a value to a type, returning the default for that type if the value could not be - /// cast. + /// Convert a value to a type by any means possible, returning the default for that type + /// if the value could not be converted. /// /// The value to cast. /// The type to cast to.. + /// The culture to use. /// A value of . - public static object CastOrDefault(object value, Type type) + public static object ConvertOrDefault(object value, Type type, CultureInfo culture) { - var typeInfo = type.GetTypeInfo(); - object result; + return TryConvert(type, value, culture, out object result) ? result : Default(type); + } - if (TypeUtilities.TryCast(type, value, out result)) - { - return result; - } - else if (typeInfo.IsValueType) - { - return Activator.CreateInstance(type); - } - else - { - return null; - } + /// + /// Convert a value to a type using the implicit conversions allowed by the C# language or + /// return the default for the type if the value could not be converted. + /// + /// The value to cast. + /// The type to cast to.. + /// A value of . + public static object ConvertImplicitOrDefault(object value, Type type) + { + return TryConvertImplicit(type, value, out object result) ? result : Default(type); } /// diff --git a/src/Markup/Avalonia.Markup/DefaultValueConverter.cs b/src/Markup/Avalonia.Markup/DefaultValueConverter.cs index 86d37d8e13..b56291a653 100644 --- a/src/Markup/Avalonia.Markup/DefaultValueConverter.cs +++ b/src/Markup/Avalonia.Markup/DefaultValueConverter.cs @@ -3,10 +3,7 @@ using System; using System.Globalization; -using System.Linq; -using System.Reflection; using Avalonia.Data; -using Avalonia.Logging; using Avalonia.Utilities; namespace Avalonia.Markup @@ -32,32 +29,28 @@ namespace Avalonia.Markup /// The converted value. public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - object result; - - if (value != null && - (TypeUtilities.TryConvert(targetType, value, culture, out result) || - TryConvertEnum(value, targetType, culture, out result))) + if (value == null) { - return result; + return AvaloniaProperty.UnsetValue; } - if (value != null) + if (TypeUtilities.TryConvert(targetType, value, culture, out object result)) { - string message; + return result; + } - if (TypeUtilities.IsNumeric(targetType)) - { - message = $"'{value}' is not a valid number."; - } - else - { - message = $"Could not convert '{value}' to '{targetType.Name}'."; - } + string message; - return new BindingNotification(new InvalidCastException(message), BindingErrorType.Error); + if (TypeUtilities.IsNumeric(targetType)) + { + message = $"'{value}' is not a valid number."; + } + else + { + message = $"Could not convert '{value}' to '{targetType.Name}'."; } - return AvaloniaProperty.UnsetValue; + return new BindingNotification(new InvalidCastException(message), BindingErrorType.Error); } /// @@ -72,34 +65,5 @@ namespace Avalonia.Markup { return Convert(value, targetType, parameter, culture); } - - private bool TryConvertEnum(object value, Type targetType, CultureInfo cultur, out object result) - { - var valueTypeInfo = value.GetType().GetTypeInfo(); - var targetTypeInfo = targetType.GetTypeInfo(); - - if (valueTypeInfo.IsEnum && !targetTypeInfo.IsEnum) - { - var enumValue = (int)value; - - if (TypeUtilities.TryCast(targetType, enumValue, out result)) - { - return true; - } - } - else if (!valueTypeInfo.IsEnum && targetTypeInfo.IsEnum) - { - object intValue; - - if (TypeUtilities.TryCast(typeof(int), value, out intValue)) - { - result = Enum.ToObject(targetType, intValue); - return true; - } - } - - result = null; - return false; - } } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs new file mode 100644 index 0000000000..8c0b043907 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorParserTests.cs @@ -0,0 +1,17 @@ +using System; +using Avalonia.Controls; +using Avalonia.Markup.Xaml.Parsers; +using Xunit; + +namespace Avalonia.Markup.Xaml.UnitTests.Parsers +{ + public class SelectorParserTests + { + [Fact] + public void Parses_Boolean_Property_Selector() + { + var target = new SelectorParser((type, ns) => typeof(TextBlock)); + var result = target.Parse("TextBlock[IsPointerOver=True]"); + } + } +} From 068c63be9c10bd563058f7b1043321f48b3b4072 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 7 May 2017 17:38:49 +0200 Subject: [PATCH 2/5] We require VS2017 --- docs/guidelines/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guidelines/build.md b/docs/guidelines/build.md index 12047ff357..822496814b 100644 --- a/docs/guidelines/build.md +++ b/docs/guidelines/build.md @@ -2,7 +2,7 @@ ## Windows -Avalonia requires at least Visual Studio 2015 to build on Windows. +Avalonia requires at least Visual Studio 2017 to build on Windows. ### Install GTK Sharp From 88b0342e3d3110590a44c5976fddb1d46d9ed189 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 7 May 2017 17:55:55 +0200 Subject: [PATCH 3/5] Fix GetVisualRoot logic It was plain wrong. --- src/Avalonia.Visuals/VisualTree/VisualExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs index 2af267aa97..11fbae4321 100644 --- a/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs +++ b/src/Avalonia.Visuals/VisualTree/VisualExtensions.cs @@ -189,7 +189,7 @@ namespace Avalonia.VisualTree { Contract.Requires(visual != null); - return visual.VisualRoot as IRenderRoot ?? visual.VisualRoot; + return visual as IRenderRoot ?? visual.VisualRoot; } /// From 2673fd090b2fe8e70088081fea4f9a4394cb0073 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 8 May 2017 23:43:56 +0200 Subject: [PATCH 4/5] NCrunch is noisy. I wish you'd stop making this useless changes. --- .ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject | 5 +++++ .../Avalonia.Controls.UnitTests.net461.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject | 5 +++++ ...Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject | 5 +++++ ...a.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject | 5 +++++ .../Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject | 5 +++++ .ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject | 5 +++++ .ncrunch/Direct3DInteropSample.v3.ncrunchproject | 5 +++++ 11 files changed, 55 insertions(+) create mode 100644 .ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject create mode 100644 .ncrunch/Direct3DInteropSample.v3.ncrunchproject diff --git a/.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject b/.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/.ncrunch/Direct3DInteropSample.v3.ncrunchproject b/.ncrunch/Direct3DInteropSample.v3.ncrunchproject new file mode 100644 index 0000000000..6800b4a3fe --- /dev/null +++ b/.ncrunch/Direct3DInteropSample.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file From b87b3bb6da248ce9dce55c59467e2ded898c5b8c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 9 May 2017 21:01:19 +0300 Subject: [PATCH 5/5] Updated Skia to 1.57.1 --- build/SkiaSharp.props | 2 +- packages.cake | 21 +++++++++++--------- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 4 ++-- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index bd6b4ebc53..a4b94cacfa 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,5 +1,5 @@  - + diff --git a/packages.cake b/packages.cake index f030c73a06..2fb089ba96 100644 --- a/packages.cake +++ b/packages.cake @@ -425,10 +425,7 @@ public class Packages { new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version }, new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }, - //netstandard1.3 - new NuSpecDependency() { Id = "Avalonia", TargetFramework = "netstandard1.3", Version = parameters.Version }, - new NuSpecDependency() { Id = "SkiaSharp", TargetFramework = "netstandard1.3", Version = SkiaSharpVersion }, - new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netstandard1.3", Version = "1.6.0" } + new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpVersion } }, Files = new [] { @@ -446,11 +443,17 @@ public class Packages Id = "Avalonia.Desktop", Dependencies = new [] { - new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version }, - new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version }, - new NuSpecDependency() { Id = "Avalonia.Gtk", Version = parameters.Version }, - new NuSpecDependency() { Id = "Avalonia.Cairo", Version = parameters.Version }, - new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = parameters.Version } + //Full .NET + new NuSpecDependency() { Id = "Avalonia.Direct2D1", TargetFramework="net45", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Gtk", TargetFramework="net45", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Cairo", TargetFramework="net45", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="net45", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", TargetFramework="net45", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="net45", Version = parameters.Version }, + //.NET Core + new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp1.1", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", TargetFramework="netcoreapp1.1", Version = parameters.Version }, + new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp1.1", Version = parameters.Version } }, Files = new NuSpecContent[] { diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 1125863e72..4a9f2c6572 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -285,7 +285,7 @@ namespace Avalonia.Skia paint.StrokeCap = SKStrokeCap.Butt; if (pen.LineJoin == PenLineJoin.Miter) - paint.StrokeJoin = SKStrokeJoin.Mitter; + paint.StrokeJoin = SKStrokeJoin.Miter; else if (pen.LineJoin == PenLineJoin.Round) paint.StrokeJoin = SKStrokeJoin.Round; else @@ -397,7 +397,7 @@ namespace Avalonia.Skia public void PopOpacityMask() { - Canvas.SaveLayer(new SKPaint { XferMode = SKXferMode.DstIn }); + Canvas.SaveLayer(new SKPaint { BlendMode = SKBlendMode.DstIn }); using (var paintWrapper = maskStack.Pop()) { Canvas.DrawPaint(paintWrapper.Paint); diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index 133d9cd789..8568c80c04 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -42,7 +42,7 @@ namespace Avalonia.Skia _paint.Typeface = skiaTypeface; _paint.TextSize = (float)(typeface?.FontSize ?? 12); _paint.TextAlign = textAlignment.ToSKTextAlign(); - _paint.XferMode = SKXferMode.Src; + _paint.BlendMode = SKBlendMode.Src; _wrapping = wrapping; _constraint = constraint;