Browse Source

Move IsOnPlatform method to the xaml helpers class

release/11.0.0-preview3
Max Katz 4 years ago
parent
commit
06a68751a4
  1. 3
      samples/ControlCatalog/Pages/PlatformInfoPage.xaml.cs
  2. 48
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  3. 46
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs
  4. 11
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  5. 18
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs
  6. 28
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  7. 30
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs

3
samples/ControlCatalog/Pages/PlatformInfoPage.xaml.cs

@ -1,5 +1,4 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.ViewModels;

48
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

@ -48,10 +48,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
try
{
var thickness = Thickness.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Thickness, types.ThicknessFullConstructor,
new[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom });
return true;
}
catch
@ -65,10 +65,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
try
{
var point = Point.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Point, types.PointFullConstructor,
new[] { point.X, point.Y });
return true;
}
catch
@ -76,16 +76,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a point", node);
}
}
if (type.Equals(types.Vector))
{
try
{
var vector = Vector.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Vector, types.VectorFullConstructor,
new[] { vector.X, vector.Y });
return true;
}
catch
@ -93,16 +93,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a vector", node);
}
}
if (type.Equals(types.Size))
{
try
{
var size = Size.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Size, types.SizeFullConstructor,
new[] { size.Width, size.Height });
return true;
}
catch
@ -110,16 +110,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a size", node);
}
}
if (type.Equals(types.Matrix))
{
try
{
var matrix = Matrix.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Matrix, types.MatrixFullConstructor,
new[] { matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32 });
return true;
}
catch
@ -127,16 +127,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a matrix", node);
}
}
if (type.Equals(types.CornerRadius))
{
try
{
var cornerRadius = CornerRadius.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.CornerRadius, types.CornerRadiusFullConstructor,
new[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft });
return true;
}
catch
@ -144,7 +144,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a corner radius", node);
}
}
if (type.Equals(types.Color))
{
if (!Color.TryParse(text, out Color color))
@ -165,9 +165,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
try
{
var relativePoint = RelativePoint.Parse(text);
var relativePointTypeRef = new XamlAstClrTypeReference(node, types.RelativePoint, false);
result = new XamlAstNewClrObjectNode(node, relativePointTypeRef, types.RelativePointFullConstructor, new List<IXamlAstValueNode>
{
new XamlConstantNode(node, types.XamlIlTypes.Double, relativePoint.Point.X),
@ -188,9 +188,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
try
{
var gridLength = GridLength.Parse(text);
result = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
return true;
}
catch
@ -201,12 +201,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
if (type.Equals(types.Cursor))
{
if (TypeSystemHelpers.TryGetEnumValueNode(types.StandardCursorType, text, node, out var enumConstantNode))
if (TypeSystemHelpers.TryGetEnumValueNode(types.StandardCursorType, text, node, false, out var enumConstantNode))
{
var cursorTypeRef = new XamlAstClrTypeReference(node, types.Cursor, false);
result = new XamlAstNewClrObjectNode(node, cursorTypeRef, types.CursorTypeConstructor, new List<IXamlAstValueNode> { enumConstantNode });
return true;
}
}
@ -275,7 +275,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
private static bool ConvertDefinitionList(
IXamlAstValueNode node,
IXamlAstValueNode node,
string text,
AvaloniaXamlIlWellKnownTypes types,
IXamlType listType,

46
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs

@ -37,7 +37,7 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
}
IXamlAstNode defaultValue = null;
var values = new Dictionary<string, IXamlAstNode>();
var values = new Dictionary<XamlConstantNode, IXamlAstNode>();
var directives = objectNode.Children.OfType<XamlAstXmlDirective>().ToArray();
@ -75,23 +75,22 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
foreach (var platform in platformStr.Split(new[] { ',' },
StringSplitOptions.RemoveEmptyEntries))
{
values.Add(platform.Trim().ToUpperInvariant(), transformed);
values.Add(ConvertPlatformNode(platform.Trim().ToUpperInvariant(), onObj), transformed);
}
}
}
else
{
var platformStr = extProp.Property.GetClrProperty().Name.Trim().ToUpperInvariant();
var transformed = TransformNode(targetPropertyNode.Property, extProp.Values,
typeArgument, directives, extProp);
if (platformStr.Equals("default", StringComparison.OrdinalIgnoreCase))
if (platformStr.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase))
{
defaultValue = transformed;
}
else
else if (platformStr != "CONTENT")
{
values.Add(platformStr, transformed);
values.Add(ConvertPlatformNode(platformStr, extProp), transformed);
}
}
}
@ -104,6 +103,26 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
return node;
XamlConstantNode ConvertPlatformNode(string platform, IXamlLineInfo li)
{
var osTypeEnum = context.GetAvaloniaTypes().OperatingSystemType;
if (platform.Equals("MACOS", StringComparison.OrdinalIgnoreCase))
{
platform = "OSX";
}
if (platform.Equals("WINDOWS", StringComparison.OrdinalIgnoreCase))
{
platform = "WINNT";
}
if (TypeSystemHelpers.TryGetEnumValueNode(osTypeEnum, platform, li, true, out var enumConstantNode))
{
return enumConstantNode;
}
throw new XamlParseException($"Unable to parse platform name: \"{platform}\"", li);
}
XamlAstXamlPropertyValueNode TransformNode(
IXamlAstPropertyReference property,
IReadOnlyCollection<IXamlAstValueNode> values,
@ -140,11 +159,11 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
{
private IXamlAstNode _defaultValue;
private readonly IXamlAstNode[] _values;
private readonly string[] _valuePlatforms;
private readonly XamlConstantNode[] _valuePlatforms;
public XamlIlOnPlatformExtensionNode(
IXamlAstNode defaultValue,
IDictionary<string, IXamlAstNode> values,
IDictionary<XamlConstantNode, IXamlAstNode> values,
IXamlAstTypeReference targetType,
IXamlLineInfo info) : base(info)
{
@ -158,6 +177,7 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
{
_defaultValue = _defaultValue?.Visit(visitor);
VisitList(_values, visitor);
VisitList(_valuePlatforms, visitor);
}
public IXamlAstTypeReference Type { get; }
@ -165,11 +185,8 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter codeGen)
{
var operatingSystemClass =
context.Configuration.TypeSystem.GetType(
"Avalonia.Markup.Xaml.MarkupExtensions.OnPlatformExtensionHelper");
var isOSPlatformMethod = operatingSystemClass
.FindMethod(m => m.IsStatic && m.Parameters.Count == 1 && m.Name == "IsOSPlatform");
var osTypeEnum = context.GetAvaloniaTypes().OperatingSystemType;
var isOSPlatformMethod = context.GetAvaloniaTypes().IsOnPlatformMethod;
var ret = codeGen.DefineLabel();
@ -179,7 +196,8 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
var propertyNode = _values[index];
var next = codeGen.DefineLabel();
codeGen.Ldstr(platform);
codeGen.Ldloc(context.ContextLocal);
context.Emit(platform, codeGen, osTypeEnum);
codeGen.EmitCall(isOSPlatformMethod);
codeGen.Brfalse(next);
context.Emit(propertyNode, codeGen, null);

11
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -9,6 +9,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
class AvaloniaXamlIlWellKnownTypes
{
public IXamlType RuntimeHelpers { get; }
public IXamlType AvaloniaObject { get; }
public IXamlType IAvaloniaObject { get; }
public IXamlType BindingPriority { get; }
@ -102,8 +103,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType ResourceDictionary { get; }
public IXamlMethod ResourceDictionaryDeferredAdd { get; }
public IXamlType OperatingSystemType { get; }
public IXamlMethod IsOnPlatformMethod { get; }
public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
{
RuntimeHelpers = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
XamlIlTypes = cfg.WellKnownTypes;
AvaloniaObject = cfg.TypeSystem.GetType("Avalonia.AvaloniaObject");
IAvaloniaObject = cfg.TypeSystem.GetType("Avalonia.IAvaloniaObject");
@ -227,6 +233,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
cfg.TypeSystem.GetType("System.Func`2").MakeGenericType(
cfg.TypeSystem.GetType("System.IServiceProvider"),
XamlIlTypes.Object));
OperatingSystemType = cfg.TypeSystem.GetType("Avalonia.Platform.OperatingSystemType");
IsOnPlatformMethod = RuntimeHelpers.FindMethod(m => m.IsStatic && m.Parameters.Count == 2 && m.Name == "IsOnPlatform");
}
}
@ -239,7 +248,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx.Configuration));
return rv;
}
public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> ctx)
{
if (ctx.TryGetItem<AvaloniaXamlIlWellKnownTypes>(out var rv))

18
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs

@ -1,30 +1,12 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Metadata;
using Avalonia.Platform;
namespace Avalonia.Markup.Xaml.MarkupExtensions;
public static class OnPlatformExtensionHelper
{
// TEMPORARY, to replace with XAML compiler namespace helpers
public static bool IsOSPlatform(string platform)
{
var runtimeInfo = AvaloniaLocator.Current.GetRequiredService<IRuntimePlatform>().GetRuntimeInfo();
return platform switch
{
"WINDOWS" => runtimeInfo.OperatingSystem == OperatingSystemType.WinNT,
"MACOS" => runtimeInfo.OperatingSystem == OperatingSystemType.OSX,
_ => runtimeInfo.OperatingSystem.ToString().Equals(platform, StringComparison.OrdinalIgnoreCase)
};
//return RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform));
}
}
public class On
{
public string Platform { get; set; } = "Unknown";

28
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Platform;
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedParameter.Global
@ -18,7 +19,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
{
return DeferredTransformationFactoryV2<IControl>(builder, provider);
}
public static Func<IServiceProvider, object> DeferredTransformationFactoryV2<T>(Func<IServiceProvider, object> builder,
IServiceProvider provider)
{
@ -31,7 +32,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
var scope = parentScope != null ? new ChildNameScope(parentScope) : (INameScope)new NameScope();
var obj = builder(new DeferredParentServiceProvider(sp, resourceNodes, rootObject, scope));
scope.Complete();
if(typeof(T) == typeof(IControl))
return new ControlTemplateResult((IControl)obj, scope);
@ -107,9 +108,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
throw new ArgumentException("Don't know what to do with " + value.GetType());
}
public static IServiceProvider CreateInnerServiceProviderV1(IServiceProvider compiled)
public static IServiceProvider CreateInnerServiceProviderV1(IServiceProvider compiled)
=> new InnerServiceProvider(compiled);
class InnerServiceProvider : IServiceProvider
{
private readonly IServiceProvider _compiledProvider;
@ -136,7 +137,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
{
_nsInfo = nsInfo;
}
public Type Resolve(string qualifiedTypeName)
{
var sp = qualifiedTypeName.Split(new[] {':'}, 2);
@ -166,23 +167,27 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
return new RootServiceProvider(new NameScope());
}
#line default
class RootServiceProvider : IServiceProvider, IAvaloniaXamlIlParentStackProvider
{
private readonly INameScope _nameScope;
private readonly IRuntimePlatform _runtimePlatform;
public RootServiceProvider(INameScope nameScope)
{
_nameScope = nameScope;
_runtimePlatform = AvaloniaLocator.Current.GetRequiredService<IRuntimePlatform>();
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(INameScope))
return _nameScope;
if (serviceType == typeof(IAvaloniaXamlIlParentStackProvider))
return this;
if (serviceType == typeof(IRuntimePlatform))
return _runtimePlatform;
return null;
}
@ -195,5 +200,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
}
}
}
public static bool IsOnPlatform(IServiceProvider serviceProvider, OperatingSystemType platform)
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem == platform;
}
}
}

30
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs

@ -1,7 +1,4 @@
using System;
using System.Globalization;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Platform;
using Xunit;
@ -330,6 +327,31 @@ public class OnPlatformExtensionTests : XamlTestBase
}
}
[Fact]
public void BindingExtension_Works_Inside_Of_OnPlatform()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(OperatingSystemType.WinNT));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<UserControl.Resources>
<x:String x:Key='text'>foobar</x:String>
</UserControl.Resources>
<TextBlock Name='textBlock' Text='{OnPlatform Windows={CompiledBinding Source={StaticResource text}}}'/>
</UserControl>";
var window = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
}
private class TestRuntimePlatform : StandardRuntimePlatform
{
private readonly OperatingSystemType _operatingSystemType;

Loading…
Cancel
Save