diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs new file mode 100644 index 0000000000..1f50e661d8 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes +{ + class AvaloniaXamlIlFontFamilyAstNode: XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode + { + private readonly AvaloniaXamlIlWellKnownTypes _types; + private readonly string _text; + + public IXamlAstTypeReference Type { get; } + + public AvaloniaXamlIlFontFamilyAstNode(AvaloniaXamlIlWellKnownTypes types, + string text, + IXamlLineInfo lineInfo) : base(lineInfo) + { + _types = types; + _text = text; + Type = new XamlAstClrTypeReference(lineInfo, types.FontFamily, false); + } + + public XamlILNodeEmitResult Emit(XamlEmitContext context, IXamlILEmitter codeGen) + { + codeGen + .Ldloc(context.ContextLocal) + .Castclass(context.Configuration.TypeMappings.UriContextProvider) + .EmitCall(context.Configuration.TypeMappings.UriContextProvider.FindMethod( + "get_BaseUri", _types.Uri, false)) + .Ldstr(_text) + .Newobj(_types.FontFamilyConstructorUriName); + return XamlILNodeEmitResult.Type(0, _types.FontFamily); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 99ec3744bf..15413689f8 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -1,6 +1,8 @@ +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using XamlX; using XamlX.Ast; @@ -166,17 +168,41 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions public static bool CustomValueConverter(AstTransformationContext context, IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result) { - if (type.FullName == "System.TimeSpan" - && node is XamlAstTextNode tn - && !tn.Text.Contains(":")) + if (!(node is XamlAstTextNode textNode)) { - var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture); - result = new XamlStaticOrTargetedReturnMethodCallNode(tn, - type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double), - new[] - { - new XamlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds) - }); + result = null; + return false; + } + + var text = textNode.Text; + + var types = context.GetAvaloniaTypes(); + + if (type.FullName == "System.TimeSpan") + { + var tsText = text.Trim(); + + if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan)) + { + // // shorthand seconds format (ie. "0.25") + if (!tsText.Contains(":") && double.TryParse(tsText, + NumberStyles.Float | NumberStyles.AllowThousands, + CultureInfo.InvariantCulture, out var seconds)) + timeSpan = TimeSpan.FromSeconds(seconds); + else + throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node); + } + + + result = new XamlStaticOrTargetedReturnMethodCallNode(node, + type.FindMethod("FromTicks", type, false, types.Long), + new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) }); + return true; + } + + if (type.Equals(types.FontFamily)) + { + result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node); return true; } @@ -185,9 +211,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions var scope = context.ParentNodes().OfType().FirstOrDefault(); if (scope == null) throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node); - if (!(node is XamlAstTextNode text)) - throw new XamlX.XamlLoadException("Property should be a text node", node); - result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text); + + result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node ); return true; } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index 3dec96dc43..58f4ddfe31 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using XamlX.Emit; using XamlX.IL; using XamlX.Transform; @@ -47,6 +48,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlType ReflectionBindingExtension { get; } public IXamlType RelativeSource { get; } + public IXamlType Long { get; } + public IXamlType Uri { get; } + public IXamlType FontFamily { get; } + public IXamlConstructor FontFamilyConstructorUriName { get; } + public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg) { @@ -104,6 +110,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers ItemsRepeater = cfg.TypeSystem.GetType("Avalonia.Controls.ItemsRepeater"); ReflectionBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension"); RelativeSource = cfg.TypeSystem.GetType("Avalonia.Data.RelativeSource"); + Long = cfg.TypeSystem.GetType("System.Int64"); + Uri = cfg.TypeSystem.GetType("System.Uri"); + FontFamily = cfg.TypeSystem.GetType("Avalonia.Media.FontFamily"); + FontFamilyConstructorUriName = FontFamily.FindConstructor(new List { Uri, XamlIlTypes.String }); } }