Browse Source

Merge branch 'master' of https://github.com/AvaloniaUI/Avalonia into compiled-bindings

Jeremy Koritzinsky 5 years ago
parent
commit
c9d3274154
100 changed files with 3150 additions and 2478 deletions
  1. 1 1
      .gitmodules
  2. 2 0
      nukebuild/Build.cs
  3. 76 0
      nukebuild/BuildTasksPatcher.cs
  4. 3 0
      nukebuild/_build.csproj
  5. 30 39
      samples/ControlCatalog/Pages/TextBlockPage.xaml
  6. 1 0
      samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
  7. 1 0
      src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs
  8. 4 23
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  9. 1 1
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
  10. 23 22
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  11. 31 0
      src/Avalonia.Controls/ComboBox.cs
  12. 1 0
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  13. 8 7
      src/Avalonia.Controls/Primitives/AccessText.cs
  14. 28 7
      src/Avalonia.Controls/TextBlock.cs
  15. 0 4
      src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs
  16. 1 2
      src/Avalonia.Desktop/Avalonia.Desktop.csproj
  17. 29 11
      src/Avalonia.Themes.Default/ComboBox.xaml
  18. 117 82
      src/Avalonia.Themes.Fluent/ComboBox.xaml
  19. 50 20
      src/Avalonia.Themes.Fluent/ComboBoxItem.xaml
  20. 2 2
      src/Avalonia.Visuals/Media/FontManager.cs
  21. 85 27
      src/Avalonia.Visuals/Media/GlyphRun.cs
  22. 146 36
      src/Avalonia.Visuals/Media/TextDecoration.cs
  23. 0 17
      src/Avalonia.Visuals/Media/TextDecorationCollection.cs
  24. 1 1
      src/Avalonia.Visuals/Media/TextDecorationUnit.cs
  25. 2 4
      src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs
  26. 69 0
      src/Avalonia.Visuals/Media/TextFormatting/GenericTextParagraphProperties.cs
  27. 40 0
      src/Avalonia.Visuals/Media/TextFormatting/GenericTextRunProperties.cs
  28. 23 0
      src/Avalonia.Visuals/Media/TextFormatting/ShapeableTextCharacters.cs
  29. 164 0
      src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs
  30. 0 212
      src/Avalonia.Visuals/Media/TextFormatting/ShapedTextRun.cs
  31. 0 395
      src/Avalonia.Visuals/Media/TextFormatting/SimpleTextFormatter.cs
  32. 0 259
      src/Avalonia.Visuals/Media/TextFormatting/SimpleTextLine.cs
  33. 175 6
      src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs
  34. 0 71
      src/Avalonia.Visuals/Media/TextFormatting/TextFormat.cs
  35. 4 144
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatter.cs
  36. 544 0
      src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs
  37. 84 108
      src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs
  38. 12 5
      src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs
  39. 17 0
      src/Avalonia.Visuals/Media/TextFormatting/TextLineBreak.cs
  40. 235 0
      src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs
  41. 31 38
      src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs
  42. 16 17
      src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs
  43. 8 8
      src/Avalonia.Visuals/Media/TextFormatting/TextRange.cs
  44. 12 5
      src/Avalonia.Visuals/Media/TextFormatting/TextRun.cs
  45. 90 0
      src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs
  46. 5 3
      src/Avalonia.Visuals/Media/TextFormatting/TextShaper.cs
  47. 0 39
      src/Avalonia.Visuals/Media/TextFormatting/TextStyle.cs
  48. 0 24
      src/Avalonia.Visuals/Media/TextFormatting/TextStyleRun.cs
  49. 1 1
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs
  50. 1 1
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/CodepointEnumerator.cs
  51. 1 1
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/Grapheme.cs
  52. 1 1
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/GraphemeEnumerator.cs
  53. 1 1
      src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs
  54. 8 1
      src/Avalonia.Visuals/Media/TextWrapping.cs
  55. 6 6
      src/Avalonia.Visuals/Media/Typeface.cs
  56. 7 5
      src/Avalonia.Visuals/Platform/ITextShaperImpl.cs
  57. 2 3
      src/Avalonia.Visuals/Utilities/ReadOnlySlice.cs
  58. 30 0
      src/Avalonia.Visuals/Utilities/ValueSpan.cs
  59. 3 3
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  60. 21 13
      src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs
  61. 43 38
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  62. 8 8
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs
  63. 42 36
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  64. 52 44
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
  65. 16 14
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionTransformer.cs
  66. 5 5
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs
  67. 58 56
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs
  68. 9 9
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs
  69. 4 4
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlCompiledBindingsMetadataRemover.cs
  70. 15 13
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs
  71. 14 14
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs
  72. 29 29
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
  73. 13 13
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs
  74. 4 4
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs
  75. 49 47
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlPropertyPathTransformer.cs
  76. 27 18
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlRootObjectScopeTransformer.cs
  77. 61 57
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  78. 39 35
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  79. 40 38
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
  80. 9 9
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs
  81. 6 6
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs
  82. 41 39
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  83. 7 7
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs
  84. 9 10
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs
  85. 58 53
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  86. 97 93
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs
  87. 17 15
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs
  88. 17 13
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs
  89. 1 1
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  90. 1 1
      src/Skia/Avalonia.Skia/FormattedTextImpl.cs
  91. 8 6
      src/Skia/Avalonia.Skia/TextShaperImpl.cs
  92. 9 6
      src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
  93. 2 2
      tests/Avalonia.Direct2D1.UnitTests/Media/FontManagerImplTests.cs
  94. 6 6
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
  95. 0 45
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs
  96. 1 1
      tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs
  97. 3 5
      tests/Avalonia.Skia.UnitTests/Media/FontManagerImplTests.cs
  98. 2 2
      tests/Avalonia.Skia.UnitTests/Media/SKTypefaceCollectionCacheTests.cs
  99. 38 0
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/FormattableTextSource.cs
  100. 36 0
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/MultiBufferTextSource.cs

+ 1 - 1
.gitmodules

@@ -3,4 +3,4 @@
 	url = https://github.com/kekekeks/Numerge.git
 [submodule "src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github"]
 	path = src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
-	url = https://github.com/kekekeks/XamlIl.git
+	url = https://github.com/kekekeks/XamlX.git

+ 2 - 0
nukebuild/Build.cs

@@ -268,6 +268,8 @@ partial class Build : NukeBuild
         .DependsOn(CreateIntermediateNugetPackages)
         .Executes(() =>
         {
+            BuildTasksPatcher.PatchBuildTasksInPackage(Parameters.NugetIntermediateRoot / "Avalonia.Build.Tasks." +
+                                                       Parameters.Version + ".nupkg");
             var config = Numerge.MergeConfiguration.LoadFile(RootDirectory / "nukebuild" / "numerge.config");
             EnsureCleanDirectory(Parameters.NugetRoot);
             if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,

+ 76 - 0
nukebuild/BuildTasksPatcher.cs

@@ -0,0 +1,76 @@
+using System;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using ILRepacking;
+using Mono.Cecil;
+
+public class BuildTasksPatcher
+{
+    public static void PatchBuildTasksInPackage(string packagePath)
+    {
+        using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
+            ZipArchiveMode.Update))
+        {
+
+            foreach (var entry in archive.Entries.ToList())
+            {
+                if (entry.Name == "Avalonia.Build.Tasks.dll")
+                {
+                    var temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".dll");
+                    var output = temp + ".output";
+                    var patched = new MemoryStream();
+                    try
+                    {
+                        entry.ExtractToFile(temp, true);
+                        var repack = new ILRepacking.ILRepack(new RepackOptions()
+                        {
+                            Internalize = true,
+                            InputAssemblies = new[]
+                            {
+                                temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0]
+                                    .FullyQualifiedName
+                            },
+                            SearchDirectories = new string[0],
+                            OutputFile = output
+                        });
+                        repack.Repack();
+
+
+                        // 'hurr-durr assembly with the same name is already loaded' prevention
+                        using (var asm = AssemblyDefinition.ReadAssembly(output,
+                            new ReaderParameters { ReadWrite = true, InMemory = true, }))
+                        {
+                            asm.Name = new AssemblyNameDefinition(
+                                "Avalonia.Build.Tasks."
+                                + Guid.NewGuid().ToString().Replace("-", ""),
+                                new Version(0, 0, 0));
+                            asm.Write(patched);
+                            patched.Position = 0;
+                        }
+                    }
+                    finally
+                    {
+                        try
+                        {
+                            if (File.Exists(temp))
+                                File.Delete(temp);
+                            if (File.Exists(output))
+                                File.Delete(output);
+                        }
+                        catch
+                        {
+                            //ignore
+                        }
+                    }
+
+                    var fn = entry.FullName;
+                    entry.Delete();
+                    var newEntry = archive.CreateEntry(fn, CompressionLevel.Optimal);
+                    using (var s = newEntry.Open())
+                        patched.CopyTo(s);
+                }
+            }
+        }
+    }
+}

+ 3 - 0
nukebuild/_build.csproj

@@ -14,6 +14,9 @@
     <PackageReference Include="xunit.runner.console" Version="2.3.1" />
     <PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
     <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
+    <PackageReference Include="ILRepack.NETStandard" Version="2.0.4" />
+    <!-- Keep in sync with Avalonia.Build.Tasks -->
+    <PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" />
   </ItemGroup>
 
   <ItemGroup>

+ 30 - 39
samples/ControlCatalog/Pages/TextBlockPage.xaml

@@ -64,51 +64,42 @@
               <TextDecorationCollection>
                 <TextDecoration
                   Location="Overline"
-                  PenThicknessUnit="Pixel">
-                  <TextDecoration.Pen>
-                    <Pen Thickness="2">
-                      <Pen.Brush>
-                        <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
-                          <LinearGradientBrush.GradientStops>
-                            <GradientStop Offset="0" Color="Red"/>
-                            <GradientStop Offset="1" Color="Green"/>
-                          </LinearGradientBrush.GradientStops>
-                        </LinearGradientBrush>
-                      </Pen.Brush>
-                    </Pen>
-                  </TextDecoration.Pen>
+                  StrokeThicknessUnit="Pixel"
+                  StrokeThickness="2">
+                  <TextDecoration.Stroke>
+                    <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
+                      <LinearGradientBrush.GradientStops>
+                        <GradientStop Offset="0" Color="Red"/>
+                        <GradientStop Offset="1" Color="Green"/>
+                      </LinearGradientBrush.GradientStops>
+                    </LinearGradientBrush>
+                  </TextDecoration.Stroke>
                 </TextDecoration>
                 <TextDecoration
                   Location="Strikethrough"
-                  PenThicknessUnit="Pixel">
-                  <TextDecoration.Pen>
-                    <Pen Thickness="1">
-                      <Pen.Brush>
-                        <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
-                          <LinearGradientBrush.GradientStops>
-                            <GradientStop Offset="0" Color="Green"/>
-                            <GradientStop Offset="1" Color="Blue"/>
-                          </LinearGradientBrush.GradientStops>
-                        </LinearGradientBrush>
-                      </Pen.Brush>
-                    </Pen>
-                  </TextDecoration.Pen>
+                  StrokeThicknessUnit="Pixel"
+                  StrokeThickness="1">
+                  <TextDecoration.Stroke>
+                    <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
+                      <LinearGradientBrush.GradientStops>
+                        <GradientStop Offset="0" Color="Green"/>
+                        <GradientStop Offset="1" Color="Blue"/>
+                      </LinearGradientBrush.GradientStops>
+                    </LinearGradientBrush>
+                  </TextDecoration.Stroke>
                 </TextDecoration>
                 <TextDecoration
                   Location="Underline"
-                  PenThicknessUnit="Pixel">
-                  <TextDecoration.Pen>
-                    <Pen Thickness="2">
-                      <Pen.Brush>
-                        <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
-                          <LinearGradientBrush.GradientStops>
-                            <GradientStop Offset="0" Color="Blue"/>
-                            <GradientStop Offset="1" Color="Red"/>
-                          </LinearGradientBrush.GradientStops>
-                        </LinearGradientBrush>
-                      </Pen.Brush>
-                    </Pen>
-                  </TextDecoration.Pen>
+                  StrokeThicknessUnit="Pixel"
+                  StrokeThickness="2">
+                  <TextDecoration.Stroke>
+                    <LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
+                      <LinearGradientBrush.GradientStops>
+                        <GradientStop Offset="0" Color="Blue"/>
+                        <GradientStop Offset="1" Color="Red"/>
+                      </LinearGradientBrush.GradientStops>
+                    </LinearGradientBrush>
+                  </TextDecoration.Stroke>
                 </TextDecoration>
               </TextDecorationCollection>
             </TextBlock.TextDecorations>

+ 1 - 0
samples/interop/NativeEmbedSample/NativeEmbedSample.csproj

@@ -10,6 +10,7 @@
   <ItemGroup>
     <PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
     <ProjectReference Include="..\..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
+    <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
     <ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
     <ProjectReference Include="..\..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
     <PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />

+ 1 - 0
src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs

@@ -89,6 +89,7 @@ namespace Avalonia.Data.Core
                     return x;
                 }
             }
+            return null;
         }
 
         protected override void StopListeningCore()

+ 4 - 23
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@@ -5,7 +5,7 @@
         <OutputType>exe</OutputType>
         <GenerateDocumentationFile>false</GenerateDocumentationFile>
         <BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
-        <DefineConstants>$(DefineConstants);BUILDTASK;XAMLIL_CECIL_INTERNAL;XAMLIL_INTERNAL</DefineConstants>
+        <DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>
         <CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies>
         <NoWarn>NU1605</NoWarn>
     </PropertyGroup>
@@ -21,10 +21,10 @@
         <Link>XamlIlExtensions/%(RecursiveDir)%(FileName)%(Extension)</Link>
       </Compile>
       <Compile Remove="external/cecil/**/*.*" />
-      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlIl\**\*.cs">
+      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlX\**\*.cs">
         <Link>XamlIl/%(RecursiveDir)%(FileName)%(Extension)</Link>
       </Compile>
-      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs">
+      <Compile Include="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlX.IL.Cecil\**\*.cs">
         <Link>XamlIl.Cecil/%(RecursiveDir)%(FileName)%(Extension)</Link>
       </Compile>
       <Compile Include="../Markup/Avalonia.Markup\Markup\Parsers\SelectorGrammar.cs">
@@ -58,27 +58,8 @@
         <Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
       </Compile>
       <Compile Remove="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\**\obj\**\*.cs" />
-      <Compile Remove="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlIl\TypeSystem\SreTypeSystem.cs" />
+      <Compile Remove="../Markup/Avalonia.Markup.Xaml/XamlIl\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
       <PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" PrivateAssets="All" />
-      <PackageReference Condition="$(TargetFramework) == 'netstandard2.0'" Include="ILRepack.MSBuild.Task" Version="2.0.13" PrivateAssets="All" />
       <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
     </ItemGroup>
-
-  <Target Name="ILRepack" AfterTargets="Build" Condition="$(TargetFramework) == 'netstandard2.0'">
-
-    <PropertyGroup>
-      <WorkingDirectory>$(MSBuildThisFileDirectory)bin\$(Configuration)\$(TargetFramework)</WorkingDirectory>
-    </PropertyGroup>
-
-    <ItemGroup>
-      <InputAssemblies Include="Mono.Cecil.dll" />
-    </ItemGroup>
-    <ILRepack OutputType="$(OutputType)" MainAssembly="$(AssemblyName).dll" OutputAssembly="$(AssemblyName).dll" InputAssemblies="@(InputAssemblies)" WorkingDirectory="$(WorkingDirectory)" />
-    <ItemGroup>
-      <DeleteNonNeededResults Include="$(WorkingDirectory)\*.dll" />
-      <DeleteNonNeededResults Remove="$(WorkingDirectory)\Avalonia.Build.Tasks.dll" />
-    </ItemGroup>
-    <Delete Files="@(DeleteNonNeededResults)" />
-
-  </Target>
 </Project>

+ 1 - 1
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs

@@ -5,7 +5,7 @@ using Avalonia.Utilities;
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 using Mono.Collections.Generic;
-using XamlIl.TypeSystem;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Build.Tasks
 {

+ 23 - 22
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@@ -7,17 +7,18 @@ using System.Text;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
 using Microsoft.Build.Framework;
 using Mono.Cecil;
-using XamlIl.TypeSystem;
 using Avalonia.Utilities;
 using Mono.Cecil.Cil;
 using Mono.Cecil.Rocks;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Parsers;
-using XamlIl.Transform;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Parsers;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 using FieldAttributes = Mono.Cecil.FieldAttributes;
 using MethodAttributes = Mono.Cecil.MethodAttributes;
 using TypeAttributes = Mono.Cecil.TypeAttributes;
+using XamlX.IL;
 
 namespace Avalonia.Build.Tasks
 {
@@ -58,11 +59,11 @@ namespace Avalonia.Build.Tasks
                 TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
             asm.MainModule.Types.Add(indexerAccessorClosure);
 
-            var xamlLanguage = AvaloniaXamlIlLanguage.Configure(typeSystem);
+            var (xamlLanguage , emitConfig) = AvaloniaXamlIlLanguage.Configure(typeSystem);
             var compilerConfig = new AvaloniaXamlIlCompilerConfiguration(typeSystem,
                 typeSystem.TargetAssembly,
                 xamlLanguage,
-                XamlIlXmlnsMappings.Resolve(typeSystem, xamlLanguage),
+                XamlXmlnsMappings.Resolve(typeSystem, xamlLanguage),
                 AvaloniaXamlIlLanguage.CustomValueConverter,
                 new XamlIlClrPropertyInfoEmitter(typeSystem.CreateTypeBuilder(clrPropertiesDef)),
                 new XamlIlPropertyInfoAccessorFactoryEmitter(typeSystem.CreateTypeBuilder(indexerAccessorClosure)));
@@ -72,10 +73,10 @@ namespace Avalonia.Build.Tasks
                 TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
             asm.MainModule.Types.Add(contextDef);
 
-            var contextClass = XamlIlContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
-                xamlLanguage);
+            var contextClass = XamlILContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
+                xamlLanguage, emitConfig);
 
-            var compiler = new AvaloniaXamlIlCompiler(compilerConfig, contextClass) { EnableIlVerification = verifyIl };
+            var compiler = new AvaloniaXamlIlCompiler(compilerConfig, emitConfig, contextClass) { EnableIlVerification = verifyIl };
 
             var editorBrowsableAttribute = typeSystem
                 .GetTypeReference(typeSystem.FindType("System.ComponentModel.EditorBrowsableAttribute"))
@@ -135,35 +136,35 @@ namespace Avalonia.Build.Tasks
 
                         // StreamReader is needed here to handle BOM
                         var xaml = new StreamReader(new MemoryStream(res.FileContents)).ReadToEnd();
-                        var parsed = XDocumentXamlIlParser.Parse(xaml);
+                        var parsed = XDocumentXamlParser.Parse(xaml);
 
-                        var initialRoot = (XamlIlAstObjectNode)parsed.Root;
+                        var initialRoot = (XamlAstObjectNode)parsed.Root;
                         
                         
-                        var precompileDirective = initialRoot.Children.OfType<XamlIlAstXmlDirective>()
+                        var precompileDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
                             .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Precompile");
                         if (precompileDirective != null)
                         {
-                            var precompileText = (precompileDirective.Values[0] as XamlIlAstTextNode)?.Text.Trim()
+                            var precompileText = (precompileDirective.Values[0] as XamlAstTextNode)?.Text.Trim()
                                 .ToLowerInvariant();
                             if (precompileText == "false")
                                 continue;
                             if (precompileText != "true")
-                                throw new XamlIlParseException("Invalid value for x:Precompile", precompileDirective);
+                                throw new XamlParseException("Invalid value for x:Precompile", precompileDirective);
                         }
                         
-                        var classDirective = initialRoot.Children.OfType<XamlIlAstXmlDirective>()
+                        var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
                             .FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
-                        IXamlIlType classType = null;
+                        IXamlType classType = null;
                         if (classDirective != null)
                         {
-                            if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlIlAstTextNode tn))
-                                throw new XamlIlParseException("x:Class should have a string value", classDirective);
+                            if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlAstTextNode tn))
+                                throw new XamlParseException("x:Class should have a string value", classDirective);
                             classType = typeSystem.TargetAssembly.FindType(tn.Text);
                             if (classType == null)
-                                throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective);
+                                throw new XamlParseException($"Unable to find type `{tn.Text}`", classDirective);
                             compiler.OverrideRootType(parsed,
-                                new XamlIlAstClrTypeReference(classDirective, classType, false));
+                                new XamlAstClrTypeReference(classDirective, classType, false));
                             initialRoot.Children.Remove(classDirective);
                         }
                         
@@ -332,7 +333,7 @@ namespace Avalonia.Build.Tasks
                     catch (Exception e)
                     {
                         int lineNumber = 0, linePosition = 0;
-                        if (e is XamlIlParseException xe)
+                        if (e is XamlParseException xe)
                         {
                             lineNumber = xe.LineNumber;
                             linePosition = xe.LinePosition;

+ 31 - 0
src/Avalonia.Controls/ComboBox.cs

@@ -7,6 +7,7 @@ using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Templates;
 using Avalonia.Input;
 using Avalonia.Interactivity;
+using Avalonia.Layout;
 using Avalonia.LogicalTree;
 using Avalonia.Media;
 using Avalonia.VisualTree;
@@ -63,6 +64,18 @@ namespace Avalonia.Controls
         public static readonly StyledProperty<IBrush> PlaceholderForegroundProperty =
             AvaloniaProperty.Register<ComboBox, IBrush>(nameof(PlaceholderForeground));
 
+        /// <summary>
+        /// Defines the <see cref="HorizontalContentAlignment"/> property.
+        /// </summary>
+        public static readonly StyledProperty<HorizontalAlignment> HorizontalContentAlignmentProperty =
+            ContentControl.HorizontalContentAlignmentProperty.AddOwner<ComboBox>();
+
+        /// <summary>
+        /// Defines the <see cref="VerticalContentAlignment"/> property.
+        /// </summary>
+        public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
+            ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>();
+
         private bool _isDropDownOpen;
         private Popup _popup;
         private object _selectionBoxItem;
@@ -133,6 +146,24 @@ namespace Avalonia.Controls
             set { SetValue(VirtualizationModeProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the horizontal alignment of the content within the control.
+        /// </summary>
+        public HorizontalAlignment HorizontalContentAlignment
+        {
+            get { return GetValue(HorizontalContentAlignmentProperty); }
+            set { SetValue(HorizontalContentAlignmentProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the vertical alignment of the content within the control.
+        /// </summary>
+        public VerticalAlignment VerticalContentAlignment
+        {
+            get { return GetValue(VerticalContentAlignmentProperty); }
+            set { SetValue(VerticalContentAlignmentProperty, value); }
+        }
+
         /// <inheritdoc/>
         protected override IItemContainerGenerator CreateItemContainerGenerator()
         {

+ 1 - 0
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@@ -95,6 +95,7 @@ namespace Avalonia.Controls.Presenters
         static ContentPresenter()
         {
             AffectsRender<ContentPresenter>(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty);
+            AffectsArrange<ContentPresenter>(HorizontalContentAlignmentProperty, VerticalContentAlignmentProperty);
             AffectsMeasure<ContentPresenter>(BorderThicknessProperty, PaddingProperty);
             ContentProperty.Changed.AddClassHandler<ContentPresenter>((x, e) => x.ContentChanged(e));
             ContentTemplateProperty.Changed.AddClassHandler<ContentPresenter>((x, e) => x.ContentChanged(e));

+ 8 - 7
src/Avalonia.Controls/Primitives/AccessText.cs

@@ -110,7 +110,7 @@ namespace Avalonia.Controls.Primitives
 
             foreach (var textLine in TextLayout.TextLines)
             {
-                if (textLine.Text.End < textPosition)
+                if (textLine.TextRange.End < textPosition)
                 {
                     currentY += textLine.LineMetrics.Size.Height;
 
@@ -121,21 +121,22 @@ namespace Avalonia.Controls.Primitives
 
                 foreach (var textRun in textLine.TextRuns)
                 {
-                    if (!(textRun is ShapedTextRun shapedRun))
+                    if (!(textRun is ShapedTextCharacters shapedTextCharacters))
                     {
                         continue;
                     }
 
-                    if (shapedRun.GlyphRun.Characters.End < textPosition)
+                    if (shapedTextCharacters.GlyphRun.Characters.End < textPosition)
                     {
-                        currentX += shapedRun.GlyphRun.Bounds.Width;
+                        currentX += shapedTextCharacters.GlyphRun.Bounds.Width;
 
                         continue;
                     }
 
-                    var characterHit = shapedRun.GlyphRun.FindNearestCharacterHit(textPosition, out var width);
+                    var characterHit =
+                        shapedTextCharacters.GlyphRun.FindNearestCharacterHit(textPosition, out var width);
 
-                    var distance = shapedRun.GlyphRun.GetDistanceFromCharacterHit(characterHit);
+                    var distance = shapedTextCharacters.GlyphRun.GetDistanceFromCharacterHit(characterHit);
 
                     currentX += distance - width;
 
@@ -144,7 +145,7 @@ namespace Avalonia.Controls.Primitives
                         width = 0.0;
                     }
 
-                    return new Rect(currentX, currentY, width, shapedRun.GlyphRun.Bounds.Height);
+                    return new Rect(currentX, currentY, width, shapedTextCharacters.GlyphRun.Bounds.Height);
                 }
             }
 

+ 28 - 7
src/Avalonia.Controls/TextBlock.cs

@@ -70,6 +70,15 @@ namespace Avalonia.Controls
                 Brushes.Black,
                 inherits: true);
 
+        /// <summary>
+        /// Defines the <see cref="LineHeight"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> LineHeightProperty =
+            AvaloniaProperty.Register<TextBlock, double>(
+                nameof(LineHeight),
+                double.NaN,
+                validate: IsValidLineHeight);
+
         /// <summary>
         /// Defines the <see cref="MaxLines"/> property.
         /// </summary>
@@ -122,19 +131,19 @@ namespace Avalonia.Controls
         {
             ClipToBoundsProperty.OverrideDefaultValue<TextBlock>(true);
 
-            AffectsRender<TextBlock>(BackgroundProperty, ForegroundProperty, 
+            AffectsRender<TextBlock>(BackgroundProperty, ForegroundProperty,
                 TextAlignmentProperty, TextDecorationsProperty);
 
-            AffectsMeasure<TextBlock>(FontSizeProperty, FontWeightProperty, 
-                FontStyleProperty, TextWrappingProperty, FontFamilyProperty, 
-                TextTrimmingProperty, TextProperty, PaddingProperty);
+            AffectsMeasure<TextBlock>(FontSizeProperty, FontWeightProperty,
+                FontStyleProperty, TextWrappingProperty, FontFamilyProperty,
+                TextTrimmingProperty, TextProperty, PaddingProperty, LineHeightProperty, MaxLinesProperty);
 
             Observable.Merge(TextProperty.Changed, ForegroundProperty.Changed,
                 TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
                 TextTrimmingProperty.Changed, FontSizeProperty.Changed,
                 FontStyleProperty.Changed, FontWeightProperty.Changed,
                 FontFamilyProperty.Changed, TextDecorationsProperty.Changed,
-                PaddingProperty.Changed
+                PaddingProperty.Changed, MaxLinesProperty.Changed, LineHeightProperty.Changed
             ).AddClassHandler<TextBlock>((x, _) => x.InvalidateTextLayout());
         }
 
@@ -230,6 +239,15 @@ namespace Avalonia.Controls
             set { SetValue(ForegroundProperty, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the height of each line of content.
+        /// </summary>
+        public double LineHeight
+        {
+            get => GetValue(LineHeightProperty);
+            set => SetValue(LineHeightProperty, value);
+        }
+
         /// <summary>
         /// Gets or sets the maximum number of text lines.
         /// </summary>
@@ -395,7 +413,7 @@ namespace Avalonia.Controls
 
             var padding = Padding;
 
-            TextLayout?.Draw(context.PlatformImpl, new Point(padding.Left, padding.Top));
+            TextLayout?.Draw(context, new Point(padding.Left, padding.Top));
         }
 
         /// <summary>
@@ -422,7 +440,8 @@ namespace Avalonia.Controls
                 TextDecorations,
                 constraint.Width,
                 constraint.Height,
-                MaxLines);
+                maxLines: MaxLines,
+                lineHeight: LineHeight);
         }
 
         /// <summary>
@@ -471,5 +490,7 @@ namespace Avalonia.Controls
         }
 
         private static bool IsValidMaxLines(int maxLines) => maxLines >= 0;
+
+        private static bool IsValidLineHeight(double lineHeight) => double.IsNaN(lineHeight) || lineHeight > 0;
     }
 }

+ 0 - 4
src/Avalonia.Desktop/AppBuilderDesktopExtensions.cs

@@ -46,10 +46,6 @@ namespace Avalonia
             where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
              => builder.UseX11();
 
-        static void LoadDirect2D1<TAppBuilder>(TAppBuilder builder)
-            where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
-             => builder.UseDirect2D1();
-
         static void LoadSkia<TAppBuilder>(TAppBuilder builder)
             where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
              => builder.UseSkia();

+ 1 - 2
src/Avalonia.Desktop/Avalonia.Desktop.csproj

@@ -5,8 +5,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-      <ProjectReference Include="../../src/Windows/Avalonia.Win32/Avalonia.Win32.csproj" />
-      <ProjectReference Include="../../src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj" />
+      <ProjectReference Include="../../src/Windows/Avalonia.Win32/Avalonia.Win32.csproj" />      
       <ProjectReference Include="../../src/Skia/Avalonia.Skia/Avalonia.Skia.csproj" />
       <ProjectReference Include="../../src/Avalonia.Native/Avalonia.Native.csproj" />
       <ProjectReference Include="../../packages/Avalonia/Avalonia.csproj" />

+ 29 - 11
src/Avalonia.Themes.Default/ComboBox.xaml

@@ -1,10 +1,29 @@
 <Styles xmlns="https://github.com/avaloniaui">
+  <Design.PreviewWith>
+    <Border Padding="20">
+      <StackPanel Spacing="10">
+        <ComboBox PlaceholderText="Select an item">
+          <ComboBoxItem>Item 1</ComboBoxItem>
+          <ComboBoxItem>Item 2</ComboBoxItem>
+        </ComboBox>
+        <ComboBox IsEnabled="False"
+                  Width="200"
+                  SelectedIndex="1"
+                  HorizontalContentAlignment="Center">
+          <ComboBoxItem>Item 1</ComboBoxItem>
+          <ComboBoxItem>Item 2</ComboBoxItem>
+        </ComboBox>
+      </StackPanel>
+    </Border>
+  </Design.PreviewWith>
   <Style Selector="ComboBox">
-    <Setter Property="Background" Value="Transparent"/>
-    <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
-    <Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
-    <Setter Property="Padding" Value="4"/>
-    <Setter Property="MinHeight" Value="20"/>
+    <Setter Property="Background" Value="Transparent" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}" />
+    <Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}" />
+    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
+    <Setter Property="VerticalContentAlignment" Value="Center" />
+    <Setter Property="Padding" Value="4" />
+    <Setter Property="MinHeight" Value="20" />
     <Setter Property="Template">
       <ControlTemplate>
         <Border Name="border"
@@ -15,8 +34,8 @@
             <ContentControl Content="{TemplateBinding SelectionBoxItem}"
                             ContentTemplate="{TemplateBinding ItemTemplate}"
                             Margin="{TemplateBinding Padding}"
-                            HorizontalAlignment="Left"
-                            VerticalAlignment="Center"/>
+                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
+                            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
             <ToggleButton Name="toggle"
                           BorderThickness="0"
                           Background="Transparent"
@@ -30,7 +49,7 @@
                     Stretch="Uniform"
                     HorizontalAlignment="Center"
                     VerticalAlignment="Center"
-                    Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z"/>
+                    Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z" />
             </ToggleButton>
             <Popup Name="PART_Popup"
                    IsOpen="{TemplateBinding IsDropDownOpen, Mode=TwoWay}"
@@ -45,8 +64,7 @@
                                   Items="{TemplateBinding Items}"
                                   ItemsPanel="{TemplateBinding ItemsPanel}"
                                   ItemTemplate="{TemplateBinding ItemTemplate}"
-                                  VirtualizationMode="{TemplateBinding VirtualizationMode}"
-                              />
+                                  VirtualizationMode="{TemplateBinding VirtualizationMode}" />
                 </ScrollViewer>
               </Border>
             </Popup>
@@ -56,7 +74,7 @@
     </Setter>
   </Style>
   <Style Selector="ComboBox:pointerover /template/ Border#border">
-    <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}"/>
+    <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderHighBrush}" />
   </Style>
   <Style Selector="ComboBox:disabled /template/ Border#border">
     <Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}" />

+ 117 - 82
src/Avalonia.Themes.Fluent/ComboBox.xaml

@@ -1,4 +1,5 @@
-<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+<Styles xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <Design.PreviewWith>
     <Border Padding="20">
       <StackPanel Spacing="10">
@@ -6,8 +7,10 @@
           <ComboBoxItem>Item 1</ComboBoxItem>
           <ComboBoxItem>Item 2</ComboBoxItem>
         </ComboBox>
-
-        <ComboBox IsEnabled="False">
+        <ComboBox IsEnabled="False"
+                  Width="200"
+                  SelectedIndex="1"
+                  HorizontalContentAlignment="Center">
           <ComboBoxItem>Item 1</ComboBoxItem>
           <ComboBoxItem>Item 2</ComboBoxItem>
         </ComboBox>
@@ -25,6 +28,7 @@
   </Styles.Resources>
   <Style Selector="ComboBox">
     <Setter Property="Padding" Value="{DynamicResource ComboBoxPadding}" />
+    <Setter Property="FocusAdorner" Value="{x:Null}" />
     <Setter Property="MaxDropDownHeight" Value="504" />
     <Setter Property="Foreground" Value="{DynamicResource ComboBoxForeground}" />
     <Setter Property="Background" Value="{DynamicResource ComboBoxBackground}" />
@@ -32,6 +36,8 @@
     <Setter Property="BorderThickness" Value="{DynamicResource ComboBoxBorderThemeThickness}" />
     <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
     <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
+    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
+    <Setter Property="VerticalContentAlignment" Value="Center" />
     <Setter Property="HorizontalAlignment" Value="Left" />
     <Setter Property="VerticalAlignment" Value="Top" />
     <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
@@ -39,70 +45,76 @@
     <Setter Property="PlaceholderForeground" Value="{DynamicResource ComboBoxPlaceHolderForeground}" />
     <Setter Property="Template">
       <ControlTemplate>
-        <Grid RowDefinitions="Auto, *, Auto" ColumnDefinitions="*,32">
+        <Grid RowDefinitions="Auto, *, Auto"
+              ColumnDefinitions="*,32">
           <ContentPresenter x:Name="HeaderContentPresenter"
-                          Grid.Row="0"
-                          Grid.Column="0"
-                          Grid.ColumnSpan="2"
-                          TextBlock.FontWeight="{DynamicResource ComboBoxHeaderThemeFontWeight}"
-                          Margin="{DynamicResource ComboBoxTopHeaderMargin}"
-                          VerticalAlignment="Top" />
+                            Grid.Row="0"
+                            Grid.Column="0"
+                            Grid.ColumnSpan="2"
+                            TextBlock.FontWeight="{DynamicResource ComboBoxHeaderThemeFontWeight}"
+                            Margin="{DynamicResource ComboBoxTopHeaderMargin}"
+                            VerticalAlignment="Top" />
           <Border x:Name="Background"
-                          Grid.Row="1"
-                          Grid.Column="0"
-                          Grid.ColumnSpan="2"
-                          Background="{TemplateBinding Background}"
-                          BorderBrush="{TemplateBinding BorderBrush}"
-                          BorderThickness="{TemplateBinding BorderThickness}"
-                          CornerRadius="{DynamicResource ControlCornerRadius}"
-                          MinWidth="{DynamicResource ComboBoxThemeMinWidth}" />
+                  Grid.Row="1"
+                  Grid.Column="0"
+                  Grid.ColumnSpan="2"
+                  Background="{TemplateBinding Background}"
+                  BorderBrush="{TemplateBinding BorderBrush}"
+                  BorderThickness="{TemplateBinding BorderThickness}"
+                  CornerRadius="{DynamicResource ControlCornerRadius}"
+                  MinWidth="{DynamicResource ComboBoxThemeMinWidth}" />
 
           <Border x:Name="HighlightBackground"
-                          Grid.Row="1"
-                          Grid.Column="0"
-                          Grid.ColumnSpan="2"
-                          Background="{DynamicResource ComboBoxBackgroundUnfocused}"
-                          BorderBrush="{DynamicResource ComboBoxBackgroundBorderBrushUnfocused}"
-                          BorderThickness="{TemplateBinding BorderThickness}"
-                          CornerRadius="{DynamicResource ControlCornerRadius}"
-                          Opacity="0" />
-          <TextBlock  x:Name="PlaceholderTextBlock"
-                      Grid.Row="1"
-                      Grid.Column="0"
-                      HorizontalAlignment="Left"
-                      VerticalAlignment="Center"
-                      Margin="{TemplateBinding Padding}"
-                                 Foreground="{TemplateBinding PlaceholderForeground}"
-                                 Text="{TemplateBinding PlaceholderText}" IsVisible="{TemplateBinding SelectionBoxItem, Converter={x:Static ObjectConverters.IsNull}}"/>
+                  Grid.Row="1"
+                  Grid.Column="0"
+                  Grid.ColumnSpan="2"
+                  Background="{DynamicResource ComboBoxBackgroundUnfocused}"
+                  BorderBrush="{DynamicResource ComboBoxBackgroundBorderBrushUnfocused}"
+                  BorderThickness="{TemplateBinding BorderThickness}"
+                  CornerRadius="{DynamicResource ControlCornerRadius}" />
+          <TextBlock x:Name="PlaceholderTextBlock"
+                     Grid.Row="1"
+                     Grid.Column="0"
+                     HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+                     VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
+                     Margin="{TemplateBinding Padding}"
+                     Text="{TemplateBinding PlaceholderText}"
+                     IsVisible="{TemplateBinding SelectionBoxItem, Converter={x:Static ObjectConverters.IsNull}}" />
           <ContentControl x:Name="ContentPresenter"
                           Content="{TemplateBinding SelectionBoxItem}"
                           ContentTemplate="{TemplateBinding ItemTemplate}"
-                         Grid.Row="1"
-                         Grid.Column="0"
-                         Margin="{TemplateBinding Padding}"
-                         HorizontalAlignment="Left"
-                         VerticalAlignment="Center">
-          </ContentControl>
+                          Grid.Row="1"
+                          Grid.Column="0"
+                          Margin="{TemplateBinding Padding}"
+                          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
+                          VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
 
           <Border x:Name="DropDownOverlay"
-                          Grid.Row="1"
-                          Grid.Column="1"
-                          Background="Transparent"
-                          Margin="0,1,1,1"
-                          Width="30" IsVisible="False"
-                          HorizontalAlignment="Right" />
+                  Grid.Row="1"
+                  Grid.Column="1"
+                  Background="Transparent"
+                  Margin="0,1,1,1"
+                  Width="30"
+                  IsVisible="False"
+                  HorizontalAlignment="Right" />
 
           <Viewbox UseLayoutRounding="False"
-            MinHeight="{DynamicResource ComboBoxMinHeight}"
-              Grid.Row="1"
-              Grid.Column="1"
-              IsHitTestVisible="False"
-              Margin="0,0,10,0" Height="12" Width="12"
-              HorizontalAlignment="Right"
-              VerticalAlignment="Center">
+                   MinHeight="{DynamicResource ComboBoxMinHeight}"
+                   Grid.Row="1"
+                   Grid.Column="1"
+                   IsHitTestVisible="False"
+                   Margin="0,0,10,0"
+                   Height="12"
+                   Width="12"
+                   HorizontalAlignment="Right"
+                   VerticalAlignment="Center">
             <Panel>
-              <Panel Height="12" Width="12" />
-              <Path x:Name="DropDownGlyph" Stretch="Uniform" VerticalAlignment="Center" Data="M1939 486L2029 576L1024 1581L19 576L109 486L1024 1401L1939 486Z" />
+              <Panel Height="12"
+                     Width="12" />
+              <Path x:Name="DropDownGlyph"
+                    Stretch="Uniform"
+                    VerticalAlignment="Center"
+                    Data="M1939 486L2029 576L1024 1581L19 576L109 486L1024 1401L1939 486Z" />
             </Panel>
           </Viewbox>
           <Popup Name="PART_Popup"
@@ -114,20 +126,19 @@
                  StaysOpen="False">
             <Border x:Name="PopupBorder"
                     Background="{DynamicResource ComboBoxDropDownBackground}"
-                                BorderBrush="{DynamicResource ComboBoxDropDownBorderBrush}"
-                                BorderThickness="{DynamicResource ComboBoxDropdownBorderThickness}"
-                                Margin="0,-1,0,-1"
-                                Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
-                                HorizontalAlignment="Stretch"
-                                CornerRadius="{DynamicResource OverlayCornerRadius}">
+                    BorderBrush="{DynamicResource ComboBoxDropDownBorderBrush}"
+                    BorderThickness="{DynamicResource ComboBoxDropdownBorderThickness}"
+                    Margin="0,-1,0,-1"
+                    Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
+                    HorizontalAlignment="Stretch"
+                    CornerRadius="{DynamicResource OverlayCornerRadius}">
               <ScrollViewer>
                 <ItemsPresenter Name="PART_ItemsPresenter"
                                 Items="{TemplateBinding Items}"
                                 Margin="{DynamicResource ComboBoxDropdownContentMargin}"
                                 ItemsPanel="{TemplateBinding ItemsPanel}"
                                 ItemTemplate="{TemplateBinding ItemTemplate}"
-                                VirtualizationMode="{TemplateBinding VirtualizationMode}"
-                              />
+                                VirtualizationMode="{TemplateBinding VirtualizationMode}" />
               </ScrollViewer>
             </Border>
           </Popup>
@@ -136,57 +147,81 @@
     </Setter>
   </Style>
 
-  <!-- NormalState -->
+  <!--  NormalState  -->
   <Style Selector="ComboBox /template/ TextBlock#PlaceholderTextBlock">
-    <Setter Property="Foreground" Value="{DynamicResource ComboBoxPlaceHolderForeground}"/>
+    <Setter Property="Foreground" Value="{DynamicResource ComboBoxPlaceHolderForeground}" />
+  </Style>
+
+  <Style Selector="ComboBox /template/ Border#HighlightBackground">
+    <Setter Property="IsVisible" Value="False" />
   </Style>
 
   <Style Selector="ComboBox /template/ Path#DropDownGlyph">
-    <Setter Property="Fill" Value="{DynamicResource ComboBoxDropDownGlyphForeground}"/>
+    <Setter Property="Fill" Value="{DynamicResource ComboBoxDropDownGlyphForeground}" />
   </Style>
 
-  <!-- PointerOver State -->
+  <!--  PointerOver State  -->
   <Style Selector="ComboBox:pointerover /template/ Border#Background">
-    <Setter Property="Background" Value="{DynamicResource ComboBoxBackgroundPointerOver}"/>
+    <Setter Property="Background" Value="{DynamicResource ComboBoxBackgroundPointerOver}" />
     <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxBorderBrushPointerOver}" />
   </Style>
 
-  <!-- Pressed State -->
+  <!--  Pressed State  -->
   <Style Selector="ComboBox:pressed /template/ Border#Background">
-    <Setter Property="Background" Value="{DynamicResource ComboBoxBackgroundPressed}"/>
+    <Setter Property="Background" Value="{DynamicResource ComboBoxBackgroundPressed}" />
     <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxBorderBrushPressed}" />
   </Style>
 
-  <!-- Disabled State -->
+  <!--  Disabled State  -->
   <Style Selector="ComboBox:disabled /template/ Border#Background">
-    <Setter Property="Background" Value="{DynamicResource ComboBoxBackgroundDisabled}"/>
+    <Setter Property="Background" Value="{DynamicResource ComboBoxBackgroundDisabled}" />
     <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxBorderBrushDisabled}" />
   </Style>
 
   <Style Selector="ComboBox:disabled /template/ ContentPresenter#HeaderContentPresenter">
-    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}"/>
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}" />
   </Style>
 
   <Style Selector="ComboBox:disabled /template/ ContentControl#ContentPresenter">
-    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}"/>
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}" />
   </Style>
 
   <Style Selector="ComboBox:disabled /template/ TextBlock#PlaceholderTextBlock">
-    <Setter Property="Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}"/>
+    <Setter Property="Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}" />
   </Style>
 
-  <Style Selector="ComboBox:disabled /template/ TextBlock#PlaceholderTextBlock">
-    <Setter Property="Foreground" Value="{DynamicResource ComboBoxForegroundDisabled}"/>
+  <Style Selector="ComboBox:disabled /template/ Path#DropDownGlyph">
+    <Setter Property="Fill" Value="{DynamicResource ComboBoxDropDownGlyphForegroundDisabled}" />
   </Style>
 
-  <Style Selector="ComboBox:disabled /template/ Path#DropDownGlyph">
-    <Setter Property="Fill" Value="{DynamicResource ComboBoxDropDownGlyphForegroundDisabled}"/>
+  <!--  Focused State  -->
+  <Style Selector="ComboBox:focus-visible /template/ Border#HighlightBackground">
+    <Setter Property="IsVisible" Value="True" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxBackgroundBorderBrushFocused}" />
   </Style>
 
-  <!-- Focused State -->
+  <Style Selector="ComboBox:focus-visible /template/ ContentControl#ContentPresenter">
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundFocused}" />
+  </Style>
 
-  <!-- Focus Pressed State -->
+  <Style Selector="ComboBox:focus-visible /template/ TextBlock#PlaceholderTextBlock">
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundFocused}" />
+  </Style>
 
-  <!-- Unfocused State -->
+  <Style Selector="ComboBox:focus-visible /template/ Path#DropDownGlyph">
+    <Setter Property="Fill" Value="{DynamicResource ComboBoxDropDownGlyphForegroundFocused}" />
+  </Style>
 
+  <!--  Focus Pressed State  -->
+  <Style Selector="ComboBox:focused:pressed /template/ ContentControl#ContentPresenter">
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxForegroundFocusedPressed}" />
+  </Style>
+
+  <Style Selector="ComboBox:focused:pressed /template/ TextBlock#PlaceholderTextBlock">
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxPlaceHolderForegroundFocusedPressed}" />
+  </Style>
+
+  <Style Selector="ComboBox:focused:pressed /template/ Path#DropDownGlyph">
+    <Setter Property="Fill" Value="{DynamicResource ComboBoxDropDownGlyphForegroundFocusedPressed}" />
+  </Style>
 </Styles>

+ 50 - 20
src/Avalonia.Themes.Fluent/ComboBoxItem.xaml

@@ -1,17 +1,19 @@
 <Styles xmlns="https://github.com/avaloniaui">
   <Design.PreviewWith>
     <Border Padding="20">
-      <StackPanel Spacing="10">
-        <ComboBox>
+      <Border Background="{DynamicResource ComboBoxDropDownBackground}"
+              BorderBrush="{DynamicResource ComboBoxDropDownBorderBrush}"
+              BorderThickness="{DynamicResource ComboBoxDropdownBorderThickness}"
+              Margin="0,-1,0,-1"
+              Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
+              CornerRadius="{DynamicResource OverlayCornerRadius}">
+        <StackPanel HorizontalAlignment="Stretch">
           <ComboBoxItem>Item 1</ComboBoxItem>
-          <ComboBoxItem>Item 2</ComboBoxItem>
-        </ComboBox>
-
-        <ComboBox IsEnabled="False">
-          <ComboBoxItem>Item 1</ComboBoxItem>
-          <ComboBoxItem>Item 2</ComboBoxItem>
-        </ComboBox>
-      </StackPanel>
+          <ComboBoxItem>Item 2 long</ComboBoxItem>
+          <ComboBoxItem IsSelected="True">Item 3</ComboBoxItem>
+          <ComboBoxItem IsEnabled="False">Item 4</ComboBoxItem>
+        </StackPanel>
+      </Border>
     </Border>
   </Design.PreviewWith>
 
@@ -19,12 +21,11 @@
     <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForeground}" />
     <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackground}" />
     <Setter Property="Padding" Value="{DynamicResource ComboBoxItemThemePadding}" />
-    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemRevealBorderBrush}" />
-    <Setter Property="BorderThickness" Value="{DynamicResource ComboBoxItemRevealBorderThemeThickness}" />
     <Setter Property="HorizontalContentAlignment" Value="Stretch" />
     <Setter Property="Template">
       <ControlTemplate>
         <ContentPresenter Name="PART_ContentPresenter"
+                          TextBlock.Foreground="{TemplateBinding Foreground}"
                           Background="{TemplateBinding Background}"
                           BorderBrush="{TemplateBinding BorderBrush}"
                           BorderThickness="{TemplateBinding BorderThickness}"
@@ -32,28 +33,57 @@
                           Content="{TemplateBinding Content}"
                           HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                           VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
-                          Padding="{TemplateBinding Padding}"/>
+                          Padding="{TemplateBinding Padding}" />
       </ControlTemplate>
     </Setter>
   </Style>
 
+  <!--  PointerOver state  -->
   <Style Selector="ComboBoxItem:pointerover /template/ ContentPresenter">
-    <Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundPointerOver}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushPointerOver}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundPointerOver}" />
+  </Style>
+
+  <!--  Disabled state  -->
+  <Style Selector="ComboBoxItem:disabled /template/ ContentPresenter">
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundDisabled}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushDisabled}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundDisabled}" />
+  </Style>
+
+  <!--  Pressed state  -->
+  <Style Selector="ComboBoxItem:pressed /template/ ContentPresenter">
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundPressed}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushPressed}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundPressed}" />
   </Style>
 
+  <!--  Selected state  -->
   <Style Selector="ComboBoxItem:selected /template/ ContentPresenter">
-    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundSelected}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushSelected}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundSelected}" />
   </Style>
 
-  <Style Selector="ComboBoxItem:selected:focus /template/ ContentPresenter">
-    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush3}"/>
+  <!--  Selected Disabled state  -->
+  <Style Selector="ComboBoxItem:selected:disabled /template/ ContentPresenter">
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundSelectedDisabled}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushSelectedDisabled}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundSelectedDisabled}" />
   </Style>
 
+  <!--  Selected PointerOver state  -->
   <Style Selector="ComboBoxItem:selected:pointerover /template/ ContentPresenter">
-    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush3}"/>
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundSelectedPointerOver}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushSelectedPointerOver}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundSelectedPointerOver}" />
   </Style>
 
-  <Style Selector="ComboBoxItem:selected:focus:pointerover /template/ ContentPresenter">
-    <Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
+  <!--  Selected Pressed state  -->
+  <Style Selector="ComboBoxItem:selected:pressed /template/ ContentPresenter">
+    <Setter Property="Background" Value="{DynamicResource ComboBoxItemBackgroundSelectedPressed}" />
+    <Setter Property="BorderBrush" Value="{DynamicResource ComboBoxItemBorderBrushSelectedPressed}" />
+    <Setter Property="TextBlock.Foreground" Value="{DynamicResource ComboBoxItemForegroundSelectedPressed}" />
   </Style>
 </Styles>

+ 2 - 2
src/Avalonia.Visuals/Media/FontManager.cs

@@ -100,7 +100,7 @@ namespace Avalonia.Media
                     return typeface;
                 }
 
-                typeface = new Typeface(fontFamily, fontWeight, fontStyle);
+                typeface = new Typeface(fontFamily, fontStyle, fontWeight);
 
                 if (_typefaceCache.TryAdd(key, typeface))
                 {
@@ -143,7 +143,7 @@ namespace Avalonia.Media
             }
 
             var matchedTypeface = PlatformImpl.TryMatchCharacter(codepoint, fontWeight, fontStyle, fontFamily, culture, out var key) ?
-                _typefaceCache.GetOrAdd(key, new Typeface(key.FamilyName, key.Weight, key.Style)) :
+                _typefaceCache.GetOrAdd(key, new Typeface(key.FamilyName, key.Style, key.Weight)) :
                 null;
 
             return matchedTypeface;

+ 85 - 27
src/Avalonia.Visuals/Media/GlyphRun.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Collections.Generic;
 using Avalonia.Platform;
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media
 {
@@ -205,13 +205,16 @@ namespace Avalonia.Media
 
             var glyphIndex = FindGlyphIndex(characterHit.FirstCharacterIndex);
 
-            var currentCluster = _glyphClusters[glyphIndex];
-
-            if (characterHit.TrailingLength > 0)
+            if (!GlyphClusters.IsEmpty)
             {
-                while (glyphIndex < _glyphClusters.Length && _glyphClusters[glyphIndex] == currentCluster)
+                var currentCluster = GlyphClusters[glyphIndex];
+
+                if (characterHit.TrailingLength > 0)
                 {
-                    glyphIndex++;
+                    while (glyphIndex < GlyphClusters.Length && GlyphClusters[glyphIndex] == currentCluster)
+                    {
+                        glyphIndex++;
+                    }
                 }
             }
 
@@ -302,7 +305,7 @@ namespace Avalonia.Media
                 }
             }
 
-            var characterHit = FindNearestCharacterHit(GlyphClusters[index], out var width);
+            var characterHit = FindNearestCharacterHit(GlyphClusters.IsEmpty ? index : GlyphClusters[index], out var width);
 
             var offset = GetDistanceFromCharacterHit(new CharacterHit(characterHit.FirstCharacterIndex));
 
@@ -370,26 +373,31 @@ namespace Avalonia.Media
         /// </returns>
         public int FindGlyphIndex(int characterIndex)
         {
+            if (GlyphClusters.IsEmpty)
+            {
+                return characterIndex;
+            }
+
             if (IsLeftToRight)
             {
-                if (characterIndex < _glyphClusters[0])
+                if (characterIndex < GlyphClusters[0])
                 {
                     return 0;
                 }
 
-                if (characterIndex > _glyphClusters[_glyphClusters.Length - 1])
+                if (characterIndex > GlyphClusters[GlyphClusters.Length - 1])
                 {
                     return _glyphClusters.End;
                 }
             }
             else
             {
-                if (characterIndex < _glyphClusters[_glyphClusters.Length - 1])
+                if (characterIndex < GlyphClusters[GlyphClusters.Length - 1])
                 {
                     return _glyphClusters.End;
                 }
 
-                if (characterIndex > _glyphClusters[0])
+                if (characterIndex > GlyphClusters[0])
                 {
                     return 0;
                 }
@@ -397,7 +405,7 @@ namespace Avalonia.Media
 
             var comparer = IsLeftToRight ? s_ascendingComparer : s_descendingComparer;
 
-            var clusters = _glyphClusters.Buffer.Span;
+            var clusters = GlyphClusters.Buffer.Span;
 
             // Find the start of the cluster at the character index.
             var start = clusters.BinarySearch((ushort)characterIndex, comparer);
@@ -418,9 +426,19 @@ namespace Avalonia.Media
                 }
             }
 
-            while (start > 0 && clusters[start - 1] == clusters[start])
+            if (IsLeftToRight)
             {
-                start--;
+                while (start > 0 && clusters[start - 1] == clusters[start])
+                {
+                    start--;
+                }
+            }
+            else
+            {
+                while (start + 1 < clusters.Length && clusters[start + 1] == clusters[start])
+                {
+                    start++;
+                }
             }
 
             return start;
@@ -440,34 +458,74 @@ namespace Avalonia.Media
 
             var start = FindGlyphIndex(index);
 
-            var currentCluster = _glyphClusters[start];
+            if (GlyphClusters.IsEmpty)
+            {
+                width = GetGlyphWidth(index);
+
+                return new CharacterHit(start, 1);
+            }
 
-            var trailingLength = 0;
+            var cluster = GlyphClusters[start];
 
-            while (start < _glyphClusters.Length && _glyphClusters[start] == currentCluster)
+            var nextCluster = cluster;
+
+            var currentIndex = start;
+
+            while (nextCluster == cluster)
             {
-                if (GlyphAdvances.IsEmpty)
+                width += GetGlyphWidth(currentIndex);
+
+                if (IsLeftToRight)
                 {
-                    var glyph = GlyphIndices[start];
+                    currentIndex++;
 
-                    width += GlyphTypeface.GetGlyphAdvance(glyph) * Scale;
+                    if (currentIndex == GlyphClusters.Length)
+                    {
+                        break;
+                    }
                 }
                 else
                 {
-                    width += GlyphAdvances[start];
+                    currentIndex--;
+
+                    if (currentIndex < 0)
+                    {
+                        break;
+                    }
                 }
 
-                trailingLength++;
-                start++;
+                nextCluster = GlyphClusters[currentIndex];
+            }
+
+            int trailingLength;
+
+            if (nextCluster == cluster)
+            {
+                trailingLength = Characters.Start + Characters.Length - cluster;
+            }
+            else
+            {
+                trailingLength = nextCluster - cluster;
             }
 
-            if (start == _glyphClusters.Length &&
-                currentCluster + trailingLength != Characters.Start + Characters.Length)
+            return new CharacterHit(cluster, trailingLength);
+        }
+
+        /// <summary>
+        /// Gets a glyph's width.
+        /// </summary>
+        /// <param name="index">The glyph index.</param>
+        /// <returns>The glyph's width.</returns>
+        private double GetGlyphWidth(int index)
+        {
+            if (GlyphAdvances.IsEmpty)
             {
-                trailingLength = Characters.Start + Characters.Length - currentCluster;
+                var glyph = GlyphIndices[index];
+
+                return GlyphTypeface.GetGlyphAdvance(glyph) * Scale;
             }
 
-            return new CharacterHit(currentCluster, trailingLength);
+            return GlyphAdvances[index];
         }
 
         /// <summary>

+ 146 - 36
src/Avalonia.Visuals/Media/TextDecoration.cs

@@ -1,4 +1,5 @@
-using Avalonia.Media.Immutable;
+using Avalonia.Collections;
+using Avalonia.Media.TextFormatting;
 
 namespace Avalonia.Media
 {
@@ -14,28 +15,52 @@ namespace Avalonia.Media
             AvaloniaProperty.Register<TextDecoration, TextDecorationLocation>(nameof(Location));
 
         /// <summary>
-        /// Defines the <see cref="Pen"/> property.
+        /// Defines the <see cref="Stroke"/> property.
         /// </summary>
-        public static readonly StyledProperty<IPen> PenProperty =
-            AvaloniaProperty.Register<TextDecoration, IPen>(nameof(Pen));
+        public static readonly StyledProperty<IBrush> StrokeProperty =
+            AvaloniaProperty.Register<TextDecoration, IBrush>(nameof(Stroke));
 
         /// <summary>
-        /// Defines the <see cref="PenThicknessUnit"/> property.
+        /// Defines the <see cref="StrokeThicknessUnit"/> property.
         /// </summary>
-        public static readonly StyledProperty<TextDecorationUnit> PenThicknessUnitProperty =
-            AvaloniaProperty.Register<TextDecoration, TextDecorationUnit>(nameof(PenThicknessUnit));
+        public static readonly StyledProperty<TextDecorationUnit> StrokeThicknessUnitProperty =
+            AvaloniaProperty.Register<TextDecoration, TextDecorationUnit>(nameof(StrokeThicknessUnit));
 
         /// <summary>
-        /// Defines the <see cref="PenOffset"/> property.
+        /// Defines the <see cref="StrokeDashArray"/> property.
         /// </summary>
-        public static readonly StyledProperty<double> PenOffsetProperty =
-            AvaloniaProperty.Register<TextDecoration, double>(nameof(PenOffset));
+        public static readonly StyledProperty<AvaloniaList<double>> StrokeDashArrayProperty =
+            AvaloniaProperty.Register<TextDecoration, AvaloniaList<double>>(nameof(StrokeDashArray));
 
         /// <summary>
-        /// Defines the <see cref="PenOffsetUnit"/> property.
+        /// Defines the <see cref="StrokeDashOffset"/> property.
         /// </summary>
-        public static readonly StyledProperty<TextDecorationUnit> PenOffsetUnitProperty =
-            AvaloniaProperty.Register<TextDecoration, TextDecorationUnit>(nameof(PenOffsetUnit));
+        public static readonly StyledProperty<double> StrokeDashOffsetProperty =
+            AvaloniaProperty.Register<TextDecoration, double>(nameof(StrokeDashOffset));
+
+        /// <summary>
+        /// Defines the <see cref="StrokeThickness"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> StrokeThicknessProperty =
+            AvaloniaProperty.Register<TextDecoration, double>(nameof(StrokeThickness), 1);
+
+        /// <summary>
+        /// Defines the <see cref="StrokeLineCap"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PenLineCap> StrokeLineCapProperty =
+            AvaloniaProperty.Register<TextDecoration, PenLineCap>(nameof(StrokeLineCap));
+
+        /// <summary>
+        /// Defines the <see cref="StrokeOffset"/> property.
+        /// </summary>
+        public static readonly StyledProperty<double> StrokeOffsetProperty =
+            AvaloniaProperty.Register<TextDecoration, double>(nameof(StrokeOffset));
+
+        /// <summary>
+        /// Defines the <see cref="StrokeOffsetUnit"/> property.
+        /// </summary>
+        public static readonly StyledProperty<TextDecorationUnit> StrokeOffsetUnitProperty =
+            AvaloniaProperty.Register<TextDecoration, TextDecorationUnit>(nameof(StrokeOffsetUnit));
 
         /// <summary>
         /// Gets or sets the location.
@@ -50,54 +75,139 @@ namespace Avalonia.Media
         }
 
         /// <summary>
-        /// Gets or sets the pen.
+        /// Gets or sets the <see cref="IBrush"/> that specifies how the <see cref="TextDecoration"/> is painted.
         /// </summary>
-        /// <value>
-        ///     The pen.
-        /// </value>
-        public IPen Pen
+        public IBrush Stroke
+        {
+            get { return GetValue(StrokeProperty); }
+            set { SetValue(StrokeProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets the units in which the thickness of the <see cref="TextDecoration"/> is expressed.
+        /// </summary>
+        public TextDecorationUnit StrokeThicknessUnit
+        {
+            get => GetValue(StrokeThicknessUnitProperty);
+            set => SetValue(StrokeThicknessUnitProperty, value);
+        }
+
+        /// <summary>
+        /// Gets or sets a collection of <see cref="double"/> values that indicate the pattern of dashes and gaps
+        /// that is used to draw the <see cref="TextDecoration"/>.
+        /// </summary>
+        public AvaloniaList<double> StrokeDashArray
+        {
+            get { return GetValue(StrokeDashArrayProperty); }
+            set { SetValue(StrokeDashArrayProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets a value that specifies the distance within the dash pattern where a dash begins.
+        /// </summary>
+        public double StrokeDashOffset
+        {
+            get { return GetValue(StrokeDashOffsetProperty); }
+            set { SetValue(StrokeDashOffsetProperty, value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the thickness of the <see cref="TextDecoration"/>.
+        /// </summary>
+        public double StrokeThickness
         {
-            get => GetValue(PenProperty);
-            set => SetValue(PenProperty, value);
+            get { return GetValue(StrokeThicknessProperty); }
+            set { SetValue(StrokeThicknessProperty, value); }
         }
 
         /// <summary>
-        /// Gets the units in which the Thickness of the text decoration's <see cref="Pen"/> is expressed.
+        /// Gets or sets a <see cref="PenLineCap"/> enumeration value that describes the shape at the ends of a line.
         /// </summary>
-        public TextDecorationUnit PenThicknessUnit
+        public PenLineCap StrokeLineCap
         {
-            get => GetValue(PenThicknessUnitProperty);
-            set => SetValue(PenThicknessUnitProperty, value);
+            get { return GetValue(StrokeLineCapProperty); }
+            set { SetValue(StrokeLineCapProperty, value); }
         }
 
         /// <summary>
-        /// Gets or sets the pen offset.
+        /// The stroke's offset.
         /// </summary>
         /// <value>
         /// The pen offset.
         /// </value>
-        public double PenOffset
+        public double StrokeOffset
         {
-            get => GetValue(PenOffsetProperty);
-            set => SetValue(PenOffsetProperty, value);
+            get => GetValue(StrokeOffsetProperty);
+            set => SetValue(StrokeOffsetProperty, value);
         }
 
         /// <summary>
-        /// Gets the units in which the <see cref="PenOffset"/> value is expressed.
+        /// Gets the units in which the <see cref="StrokeOffset"/> value is expressed.
         /// </summary>
-        public TextDecorationUnit PenOffsetUnit
+        public TextDecorationUnit StrokeOffsetUnit
         {
-            get => GetValue(PenOffsetUnitProperty);
-            set => SetValue(PenOffsetUnitProperty, value);
+            get => GetValue(StrokeOffsetUnitProperty);
+            set => SetValue(StrokeOffsetUnitProperty, value);
         }
 
         /// <summary>
-        /// Creates an immutable clone of the <see cref="TextDecoration"/>.
+        /// Draws the <see cref="TextDecoration"/> at given origin.
         /// </summary>
-        /// <returns>The immutable clone.</returns>
-        public ImmutableTextDecoration ToImmutable()
+        /// <param name="drawingContext">The drawing context.</param>
+        /// <param name="shapedTextCharacters">The shaped characters that are decorated.</param>
+        /// <param name="origin">The origin.</param>
+        internal void Draw(DrawingContext drawingContext, ShapedTextCharacters shapedTextCharacters, Point origin)
         {
-            return new ImmutableTextDecoration(Location, Pen?.ToImmutable(), PenThicknessUnit, PenOffset, PenOffsetUnit);
+            var fontRenderingEmSize = shapedTextCharacters.Properties.FontRenderingEmSize;
+            var fontMetrics = shapedTextCharacters.FontMetrics;
+            var thickness = StrokeThickness;
+
+            switch (StrokeThicknessUnit)
+            {
+                case TextDecorationUnit.FontRecommended:
+                    switch (Location)
+                    {
+                        case TextDecorationLocation.Underline:
+                            thickness = fontMetrics.UnderlineThickness;
+                            break;
+                        case TextDecorationLocation.Strikethrough:
+                            thickness = fontMetrics.StrikethroughThickness;
+                            break;
+                    }
+
+                    break;
+                case TextDecorationUnit.FontRenderingEmSize:
+                    thickness = fontRenderingEmSize * thickness;
+                    break;
+            }
+
+            switch (Location)
+            {
+                case TextDecorationLocation.Overline:
+                    origin += new Point(0, fontMetrics.Ascent);
+                    break;
+                case TextDecorationLocation.Strikethrough:
+                    origin += new Point(0, -fontMetrics.StrikethroughPosition);
+                    break;
+                case TextDecorationLocation.Underline:
+                    origin += new Point(0, -fontMetrics.UnderlinePosition);
+                    break;
+            }
+
+            switch (StrokeOffsetUnit)
+            {
+                case TextDecorationUnit.FontRenderingEmSize:
+                    origin += new Point(0, StrokeOffset * fontRenderingEmSize);
+                    break;
+                case TextDecorationUnit.Pixel:
+                    origin += new Point(0, StrokeOffset);
+                    break;
+            }
+
+            var pen = new Pen(Stroke ?? shapedTextCharacters.Properties.ForegroundBrush, thickness,
+                new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeLineCap);
+
+            drawingContext.DrawLine(pen, origin, origin + new Point(shapedTextCharacters.Bounds.Width, 0));
         }
     }
 }

+ 0 - 17
src/Avalonia.Visuals/Media/TextDecorationCollection.cs

@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
 using Avalonia.Collections;
-using Avalonia.Media.Immutable;
 using Avalonia.Utilities;
 
 namespace Avalonia.Media
@@ -11,22 +10,6 @@ namespace Avalonia.Media
     /// </summary>
     public class TextDecorationCollection : AvaloniaList<TextDecoration>
     {
-        /// <summary>
-        /// Creates an immutable clone of the <see cref="TextDecorationCollection"/>.
-        /// </summary>
-        /// <returns>The immutable clone.</returns>
-        public ImmutableTextDecoration[] ToImmutable()
-        {
-            var immutable = new ImmutableTextDecoration[Count];
-
-            for (var i = 0; i < Count; i++)
-            {
-                immutable[i] = this[i].ToImmutable();
-            }
-
-            return immutable;
-        }
-
         /// <summary>
         /// Parses a <see cref="TextDecorationCollection"/> string.
         /// </summary>

+ 1 - 1
src/Avalonia.Visuals/Media/TextDecorationUnit.cs

@@ -1,7 +1,7 @@
 namespace Avalonia.Media
 {
     /// <summary>
-    /// Specifies the unit type of either a <see cref="TextDecoration.PenOffset"/> or a <see cref="Pen"/> thickness value.
+    /// Specifies the unit type of either a <see cref="TextDecoration.StrokeOffset"/> or a <see cref="TextDecoration.StrokeThickness"/> value.
     /// </summary>
     public enum TextDecorationUnit
     {

+ 2 - 4
src/Avalonia.Visuals/Media/TextFormatting/DrawableTextRun.cs

@@ -1,6 +1,4 @@
-using Avalonia.Platform;
-
-namespace Avalonia.Media.TextFormatting
+namespace Avalonia.Media.TextFormatting
 {
     /// <summary>
     /// A text run that supports drawing content.
@@ -17,6 +15,6 @@ namespace Avalonia.Media.TextFormatting
         /// </summary>
         /// <param name="drawingContext">The drawing context.</param>
         /// <param name="origin">The origin.</param>
-        public abstract void Draw(IDrawingContextImpl drawingContext, Point origin);
+        public abstract void Draw(DrawingContext drawingContext, Point origin);
     }
 }

+ 69 - 0
src/Avalonia.Visuals/Media/TextFormatting/GenericTextParagraphProperties.cs

@@ -0,0 +1,69 @@
+namespace Avalonia.Media.TextFormatting
+{
+    public class GenericTextParagraphProperties : TextParagraphProperties
+    {
+        private TextAlignment _textAlignment;
+        private TextWrapping _textWrapping;
+        private TextTrimming _textTrimming;
+        private double _lineHeight;
+
+        public GenericTextParagraphProperties(
+            TextRunProperties defaultTextRunProperties,
+            TextAlignment textAlignment = TextAlignment.Left,
+            TextWrapping textWrapping = TextWrapping.WrapWithOverflow,
+            TextTrimming textTrimming = TextTrimming.None,
+            double lineHeight = 0)
+        {
+            DefaultTextRunProperties = defaultTextRunProperties;
+
+            _textAlignment = textAlignment;
+
+            _textWrapping = textWrapping;
+
+            _textTrimming = textTrimming;
+
+            _lineHeight = lineHeight;
+        }
+
+        public override TextRunProperties DefaultTextRunProperties { get; }
+
+        public override TextAlignment TextAlignment => _textAlignment;
+
+        public override TextWrapping TextWrapping => _textWrapping;
+
+        public override TextTrimming TextTrimming => _textTrimming;
+
+        public override double LineHeight => _lineHeight;
+
+        /// <summary>
+        /// Set text alignment
+        /// </summary>
+        internal void SetTextAlignment(TextAlignment textAlignment)
+        {
+            _textAlignment = textAlignment;
+        }
+
+        /// <summary>
+        /// Set text wrap
+        /// </summary>
+        internal void SetTextWrapping(TextWrapping textWrapping)
+        {
+            _textWrapping = textWrapping;
+        }
+        /// <summary>
+        /// Set text trimming
+        /// </summary>
+        internal void SetTextTrimming(TextTrimming textTrimming)
+        {
+            _textTrimming = textTrimming;
+        }
+
+        /// <summary>
+        /// Set line height
+        /// </summary>
+        internal void SetLineHeight(double lineHeight)
+        {
+            _lineHeight = lineHeight;
+        }
+    }
+}

+ 40 - 0
src/Avalonia.Visuals/Media/TextFormatting/GenericTextRunProperties.cs

@@ -0,0 +1,40 @@
+using System.Globalization;
+
+namespace Avalonia.Media.TextFormatting
+{
+    /// <summary>
+    /// Generic implementation of TextRunProperties
+    /// </summary>
+    public class GenericTextRunProperties : TextRunProperties
+    {
+        public GenericTextRunProperties(Typeface typeface, double fontRenderingEmSize = 12,
+            TextDecorationCollection textDecorations = null, IBrush foregroundBrush = null, IBrush backgroundBrush = null,
+            CultureInfo cultureInfo = null)
+        {
+            Typeface = typeface;
+            FontRenderingEmSize = fontRenderingEmSize;
+            TextDecorations = textDecorations;
+            ForegroundBrush = foregroundBrush;
+            BackgroundBrush = backgroundBrush;
+            CultureInfo = cultureInfo;
+        }
+
+        /// <inheritdoc />
+        public override Typeface Typeface { get; }
+
+        /// <inheritdoc />
+        public override double FontRenderingEmSize { get; }
+
+        /// <inheritdoc />
+        public override TextDecorationCollection TextDecorations { get; }
+
+        /// <inheritdoc />
+        public override IBrush ForegroundBrush { get; }
+
+        /// <inheritdoc />
+        public override IBrush BackgroundBrush { get; }
+
+        /// <inheritdoc />
+        public override CultureInfo CultureInfo { get; }
+    }
+}

+ 23 - 0
src/Avalonia.Visuals/Media/TextFormatting/ShapeableTextCharacters.cs

@@ -0,0 +1,23 @@
+using Avalonia.Utilities;
+
+namespace Avalonia.Media.TextFormatting
+{
+    /// <summary>
+    /// A group of characters that can be shaped.
+    /// </summary>
+    public sealed class ShapeableTextCharacters : TextRun
+    {
+        public ShapeableTextCharacters(ReadOnlySlice<char> text, TextRunProperties properties)
+        {
+            TextSourceLength = text.Length;
+            Text = text;
+            Properties = properties;
+        }
+
+        public override int TextSourceLength { get; }
+
+        public override ReadOnlySlice<char> Text { get; }
+
+        public override TextRunProperties Properties { get; }
+    }
+}

+ 164 - 0
src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs

@@ -0,0 +1,164 @@
+using Avalonia.Media.TextFormatting.Unicode;
+using Avalonia.Utilities;
+
+namespace Avalonia.Media.TextFormatting
+{
+    /// <summary>
+    /// A text run that holds shaped characters.
+    /// </summary>
+    public sealed class ShapedTextCharacters : DrawableTextRun
+    {
+        public ShapedTextCharacters(GlyphRun glyphRun, TextRunProperties properties)
+        {
+            Text = glyphRun.Characters;
+            Properties = properties;
+            TextSourceLength = Text.Length;
+            FontMetrics = new FontMetrics(Properties.Typeface, Properties.FontRenderingEmSize);
+            GlyphRun = glyphRun;
+        }
+
+        /// <inheritdoc/>
+        public override ReadOnlySlice<char> Text { get; }
+
+        /// <inheritdoc/>
+        public override TextRunProperties Properties { get; }
+
+        /// <inheritdoc/>
+        public override int TextSourceLength { get; }
+
+        /// <inheritdoc/>
+        public override Rect Bounds => GlyphRun.Bounds;
+
+        /// <summary>
+        /// Gets the font metrics.
+        /// </summary>
+        /// <value>
+        /// The font metrics.
+        /// </value>
+        public FontMetrics FontMetrics { get; }
+
+        /// <summary>
+        /// Gets the glyph run.
+        /// </summary>
+        /// <value>
+        /// The glyphs.
+        /// </value>
+        public GlyphRun GlyphRun { get; }
+
+        /// <inheritdoc/>
+        public override void Draw(DrawingContext drawingContext, Point origin)
+        {
+            if (GlyphRun.GlyphIndices.Length == 0)
+            {
+                return;
+            }
+
+            if (Properties.Typeface == null)
+            {
+                return;
+            }
+
+            if (Properties.ForegroundBrush == null)
+            {
+                return;
+            }
+
+            if (Properties.BackgroundBrush != null)
+            {
+                drawingContext.DrawRectangle(Properties.BackgroundBrush, null,
+                new Rect(origin.X, origin.Y + FontMetrics.Ascent, Bounds.Width, Bounds.Height));
+            }
+
+            drawingContext.DrawGlyphRun(Properties.ForegroundBrush, GlyphRun, origin);
+
+            if (Properties.TextDecorations == null)
+            {
+                return;
+            }
+
+            foreach (var textDecoration in Properties.TextDecorations)
+            {
+                textDecoration.Draw(drawingContext, this, origin);
+            }
+        }
+
+        /// <summary>
+        /// Splits the <see cref="TextRun"/> at specified length.
+        /// </summary>
+        /// <param name="length">The length.</param>
+        /// <returns>The split result.</returns>
+        public SplitTextCharactersResult Split(int length)
+        {
+            var glyphCount = 0;
+
+            var firstCharacters = GlyphRun.Characters.Take(length);
+
+            var codepointEnumerator = new CodepointEnumerator(firstCharacters);
+
+            while (codepointEnumerator.MoveNext())
+            {
+                glyphCount++;
+            }
+
+            if (GlyphRun.Characters.Length == length)
+            {
+                return new SplitTextCharactersResult(this, null);
+            }
+
+            if (GlyphRun.GlyphIndices.Length == glyphCount)
+            {
+                return new SplitTextCharactersResult(this, null);
+            }
+
+            var firstGlyphRun = new GlyphRun(
+                Properties.Typeface.GlyphTypeface,
+                Properties.FontRenderingEmSize,
+                GlyphRun.GlyphIndices.Take(glyphCount),
+                GlyphRun.GlyphAdvances.Take(glyphCount),
+                GlyphRun.GlyphOffsets.Take(glyphCount),
+                GlyphRun.Characters.Take(length),
+                GlyphRun.GlyphClusters.Take(glyphCount));
+
+            var firstTextRun = new ShapedTextCharacters(firstGlyphRun, Properties);
+
+            var secondGlyphRun = new GlyphRun(
+                Properties.Typeface.GlyphTypeface,
+                Properties.FontRenderingEmSize,
+                GlyphRun.GlyphIndices.Skip(glyphCount),
+                GlyphRun.GlyphAdvances.Skip(glyphCount),
+                GlyphRun.GlyphOffsets.Skip(glyphCount),
+                GlyphRun.Characters.Skip(length),
+                GlyphRun.GlyphClusters.Skip(glyphCount));
+
+            var secondTextRun = new ShapedTextCharacters(secondGlyphRun, Properties);
+
+            return new SplitTextCharactersResult(firstTextRun, secondTextRun);
+        }
+
+        public readonly struct SplitTextCharactersResult
+        {
+            public SplitTextCharactersResult(ShapedTextCharacters first, ShapedTextCharacters second)
+            {
+                First = first;
+
+                Second = second;
+            }
+
+            /// <summary>
+            /// Gets the first text run.
+            /// </summary>
+            /// <value>
+            /// The first text run.
+            /// </value>
+            public ShapedTextCharacters First { get; }
+
+            /// <summary>
+            /// Gets the second text run.
+            /// </summary>
+            /// <value>
+            /// The second text run.
+            /// </value>
+            public ShapedTextCharacters Second { get; }
+        }
+    }
+}

+ 0 - 212
src/Avalonia.Visuals/Media/TextFormatting/ShapedTextRun.cs

@@ -1,212 +0,0 @@
-using Avalonia.Media.Immutable;
-using Avalonia.Media.TextFormatting.Unicode;
-using Avalonia.Platform;
-using Avalonia.Utility;
-
-namespace Avalonia.Media.TextFormatting
-{
-    /// <summary>
-    /// A text run that holds a shaped glyph run.
-    /// </summary>
-    public sealed class ShapedTextRun : DrawableTextRun
-    {
-        public ShapedTextRun(ReadOnlySlice<char> text, TextStyle style) : this(
-            TextShaper.Current.ShapeText(text, style.TextFormat), style)
-        {
-        }
-
-        public ShapedTextRun(GlyphRun glyphRun, TextStyle style)
-        {
-            Text = glyphRun.Characters;
-            Style = style;
-            GlyphRun = glyphRun;
-        }
-
-        /// <inheritdoc/>
-        public override Rect Bounds => GlyphRun.Bounds;
-
-        /// <summary>
-        /// Gets the glyph run.
-        /// </summary>
-        /// <value>
-        /// The glyphs.
-        /// </value>
-        public GlyphRun GlyphRun { get; }
-
-        /// <inheritdoc/>
-        public override void Draw(IDrawingContextImpl drawingContext, Point origin)
-        {
-            if (GlyphRun.GlyphIndices.Length == 0)
-            {
-                return;
-            }
-
-            if (Style.TextFormat.Typeface == null)
-            {
-                return;
-            }
-
-            if (Style.Foreground == null)
-            {
-                return;
-            }
-
-            drawingContext.DrawGlyphRun(Style.Foreground, GlyphRun, origin);
-
-            if (Style.TextDecorations == null)
-            {
-                return;
-            }
-
-            foreach (var textDecoration in Style.TextDecorations)
-            {
-                DrawTextDecoration(drawingContext, textDecoration, origin);
-            }
-        }
-
-        /// <summary>
-        /// Draws the <see cref="TextDecoration"/> at given origin.
-        /// </summary>
-        /// <param name="drawingContext">The drawing context.</param>
-        /// <param name="textDecoration">The text decoration.</param>
-        /// <param name="origin">The origin.</param>
-        private void DrawTextDecoration(IDrawingContextImpl drawingContext, ImmutableTextDecoration textDecoration, Point origin)
-        {
-            var textFormat = Style.TextFormat;
-
-            var fontMetrics = Style.TextFormat.FontMetrics;
-
-            var thickness = textDecoration.Pen?.Thickness ?? 1.0;
-
-            switch (textDecoration.PenThicknessUnit)
-            {
-                case TextDecorationUnit.FontRecommended:
-                    switch (textDecoration.Location)
-                    {
-                        case TextDecorationLocation.Underline:
-                            thickness = fontMetrics.UnderlineThickness;
-                            break;
-                        case TextDecorationLocation.Strikethrough:
-                            thickness = fontMetrics.StrikethroughThickness;
-                            break;
-                    }
-                    break;
-                case TextDecorationUnit.FontRenderingEmSize:
-                    thickness = textFormat.FontRenderingEmSize * thickness;
-                    break;
-            }
-
-            switch (textDecoration.Location)
-            {
-                case TextDecorationLocation.Overline:
-                    origin += new Point(0, textFormat.FontMetrics.Ascent);
-                    break;
-                case TextDecorationLocation.Strikethrough:
-                    origin += new Point(0, -textFormat.FontMetrics.StrikethroughPosition);
-                    break;
-                case TextDecorationLocation.Underline:
-                    origin += new Point(0, -textFormat.FontMetrics.UnderlinePosition);
-                    break;
-            }
-
-            switch (textDecoration.PenOffsetUnit)
-            {
-                case TextDecorationUnit.FontRenderingEmSize:
-                    origin += new Point(0, textDecoration.PenOffset * textFormat.FontRenderingEmSize);
-                    break;
-                case TextDecorationUnit.Pixel:
-                    origin += new Point(0, textDecoration.PenOffset);
-                    break;
-            }
-
-            var pen = new ImmutablePen(
-                textDecoration.Pen?.Brush ?? Style.Foreground.ToImmutable(),
-                thickness,
-                textDecoration.Pen?.DashStyle?.ToImmutable(),
-                textDecoration.Pen?.LineCap ?? default,
-                textDecoration.Pen?.LineJoin ?? PenLineJoin.Miter,
-                textDecoration.Pen?.MiterLimit ?? 10.0);
-
-            drawingContext.DrawLine(pen, origin, origin + new Point(GlyphRun.Bounds.Width, 0));
-        }
-
-        /// <summary>
-        /// Splits the <see cref="TextRun"/> at specified length.
-        /// </summary>
-        /// <param name="length">The length.</param>
-        /// <returns>The split result.</returns>
-        public SplitTextCharactersResult Split(int length)
-        {
-            var glyphCount = 0;
-
-            var firstCharacters = GlyphRun.Characters.Take(length);
-
-            var codepointEnumerator = new CodepointEnumerator(firstCharacters);
-
-            while (codepointEnumerator.MoveNext())
-            {
-                glyphCount++;
-            }
-
-            if (GlyphRun.Characters.Length == length)
-            {
-                return new SplitTextCharactersResult(this, null);
-            }
-
-            if (GlyphRun.GlyphIndices.Length == glyphCount)
-            {
-                return new SplitTextCharactersResult(this, null);
-            }
-
-            var firstGlyphRun = new GlyphRun(
-                Style.TextFormat.Typeface.GlyphTypeface,
-                Style.TextFormat.FontRenderingEmSize,
-                GlyphRun.GlyphIndices.Take(glyphCount),
-                GlyphRun.GlyphAdvances.Take(glyphCount),
-                GlyphRun.GlyphOffsets.Take(glyphCount),
-                GlyphRun.Characters.Take(length),
-                GlyphRun.GlyphClusters.Take(length));
-
-            var firstTextRun = new ShapedTextRun(firstGlyphRun, Style);
-
-            var secondGlyphRun = new GlyphRun(
-                Style.TextFormat.Typeface.GlyphTypeface,
-                Style.TextFormat.FontRenderingEmSize,
-                GlyphRun.GlyphIndices.Skip(glyphCount),
-                GlyphRun.GlyphAdvances.Skip(glyphCount),
-                GlyphRun.GlyphOffsets.Skip(glyphCount),
-                GlyphRun.Characters.Skip(length),
-                GlyphRun.GlyphClusters.Skip(length));
-
-            var secondTextRun = new ShapedTextRun(secondGlyphRun, Style);
-
-            return new SplitTextCharactersResult(firstTextRun, secondTextRun);
-        }
-
-        public readonly struct SplitTextCharactersResult
-        {
-            public SplitTextCharactersResult(ShapedTextRun first, ShapedTextRun second)
-            {
-                First = first;
-
-                Second = second;
-            }
-
-            /// <summary>
-            /// Gets the first text run.
-            /// </summary>
-            /// <value>
-            /// The first text run.
-            /// </value>
-            public ShapedTextRun First { get; }
-
-            /// <summary>
-            /// Gets the second text run.
-            /// </summary>
-            /// <value>
-            /// The second text run.
-            /// </value>
-            public ShapedTextRun Second { get; }
-        }
-    }
-}

+ 0 - 395
src/Avalonia.Visuals/Media/TextFormatting/SimpleTextFormatter.cs

@@ -1,395 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Avalonia.Media.TextFormatting.Unicode;
-using Avalonia.Platform;
-using Avalonia.Utility;
-
-namespace Avalonia.Media.TextFormatting
-{
-    internal class SimpleTextFormatter : TextFormatter
-    {
-        private static readonly ReadOnlySlice<char> s_ellipsis = new ReadOnlySlice<char>(new[] { '\u2026' });
-
-        /// <inheritdoc cref="TextFormatter.FormatLine"/>
-        public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
-            TextParagraphProperties paragraphProperties)
-        {
-            var textTrimming = paragraphProperties.TextTrimming;
-            var textWrapping = paragraphProperties.TextWrapping;
-            TextLine textLine;
-
-            var textRuns = FormatTextRuns(textSource, firstTextSourceIndex, out var textPointer);
-
-            if (textTrimming != TextTrimming.None)
-            {
-                textLine = PerformTextTrimming(textPointer, textRuns, paragraphWidth, paragraphProperties);
-            }
-            else
-            {
-                if (textWrapping == TextWrapping.Wrap)
-                {
-                    textLine = PerformTextWrapping(textPointer, textRuns, paragraphWidth, paragraphProperties);
-                }
-                else
-                {
-                    var textLineMetrics =
-                        TextLineMetrics.Create(textRuns, paragraphWidth, paragraphProperties.TextAlignment);
-
-                    textLine = new SimpleTextLine(textPointer, textRuns, textLineMetrics);
-                }
-            }
-
-            return textLine;
-        }
-
-        /// <summary>
-        /// Formats text runs with optional text style overrides.
-        /// </summary>
-        /// <param name="textSource">The text source.</param>
-        /// <param name="firstTextSourceIndex">The first text source index.</param>
-        /// <param name="textPointer">The text pointer that covers the formatted text runs.</param>
-        /// <returns>
-        /// The formatted text runs.
-        /// </returns>
-        private List<ShapedTextRun> FormatTextRuns(ITextSource textSource, int firstTextSourceIndex, out TextPointer textPointer)
-        {
-            var start = -1;
-            var length = 0;
-
-            var textRuns = new List<ShapedTextRun>();
-
-            while (true)
-            {
-                var textRun = textSource.GetTextRun(firstTextSourceIndex + length);
-
-                if (start == -1)
-                {
-                    start = textRun.Text.Start;
-                }
-
-                if (textRun is TextEndOfLine)
-                {
-                    break;
-                }
-
-                switch (textRun)
-                {
-                    case TextCharacters textCharacters:
-
-                        var runText = textCharacters.Text;
-
-                        while (!runText.IsEmpty)
-                        {
-                            var shapableTextStyleRun = CreateShapableTextStyleRun(runText, textRun.Style);
-
-                            var shapedRun = new ShapedTextRun(runText.Take(shapableTextStyleRun.TextPointer.Length),
-                                shapableTextStyleRun.Style);
-
-                            textRuns.Add(shapedRun);
-
-                            runText = runText.Skip(shapedRun.Text.Length);
-                        }
-
-                        break;
-                    default:
-                        throw new NotSupportedException("Run type not supported by the formatter.");
-                }
-
-                length += textRun.Text.Length;
-            }
-
-            textPointer = new TextPointer(start, length);
-
-            return textRuns;
-        }
-
-        /// <summary>
-        /// Performs text trimming and returns a trimmed line.
-        /// </summary>
-        /// <param name="paragraphWidth">A <see cref="double"/> value that specifies the width of the paragraph that the line fills.</param>
-        /// <param name="paragraphProperties">A <see cref="TextParagraphProperties"/> value that represents paragraph properties,
-        /// such as TextWrapping, TextAlignment, or TextStyle.</param>
-        /// <param name="textRuns">The text runs to perform the trimming on.</param>
-        /// <param name="text">The text that was used to construct the text runs.</param>
-        /// <returns></returns>
-        private static TextLine PerformTextTrimming(TextPointer text, IReadOnlyList<ShapedTextRun> textRuns,
-            double paragraphWidth, TextParagraphProperties paragraphProperties)
-        {
-            var textTrimming = paragraphProperties.TextTrimming;
-            var availableWidth = paragraphWidth;
-            var currentWidth = 0.0;
-            var runIndex = 0;
-
-            while (runIndex < textRuns.Count)
-            {
-                var currentRun = textRuns[runIndex];
-
-                currentWidth += currentRun.GlyphRun.Bounds.Width;
-
-                if (currentWidth > availableWidth)
-                {
-                    var ellipsisRun = CreateEllipsisRun(currentRun.Style);
-
-                    var measuredLength = MeasureText(currentRun, availableWidth - ellipsisRun.GlyphRun.Bounds.Width);
-
-                    if (textTrimming == TextTrimming.WordEllipsis)
-                    {
-                        if (measuredLength < text.End)
-                        {
-                            var currentBreakPosition = 0;
-
-                            var lineBreaker = new LineBreakEnumerator(currentRun.Text);
-
-                            while (currentBreakPosition < measuredLength && lineBreaker.MoveNext())
-                            {
-                                var nextBreakPosition = lineBreaker.Current.PositionWrap;
-
-                                if (nextBreakPosition == 0)
-                                {
-                                    break;
-                                }
-
-                                if (nextBreakPosition > measuredLength)
-                                {
-                                    break;
-                                }
-
-                                currentBreakPosition = nextBreakPosition;
-                            }
-
-                            measuredLength = currentBreakPosition;
-                        }
-                    }
-
-                    var splitResult = SplitTextRuns(textRuns, measuredLength);
-
-                    var trimmedRuns = new List<ShapedTextRun>(splitResult.First.Count + 1);
-
-                    trimmedRuns.AddRange(splitResult.First);
-
-                    trimmedRuns.Add(ellipsisRun);
-
-                    var textLineMetrics =
-                        TextLineMetrics.Create(trimmedRuns, paragraphWidth, paragraphProperties.TextAlignment);
-
-                    return new SimpleTextLine(text.Take(measuredLength), trimmedRuns, textLineMetrics);
-                }
-
-                availableWidth -= currentRun.GlyphRun.Bounds.Width;
-
-                runIndex++;
-            }
-
-            return new SimpleTextLine(text, textRuns,
-                TextLineMetrics.Create(textRuns, paragraphWidth, paragraphProperties.TextAlignment));
-        }
-
-        /// <summary>
-        /// Performs text wrapping returns a list of text lines.
-        /// </summary>
-        /// <param name="paragraphProperties">The text paragraph properties.</param>
-        /// <param name="textRuns">The text run'S.</param>
-        /// <param name="text">The text to analyze for break opportunities.</param>
-        /// <param name="paragraphWidth"></param>
-        /// <returns></returns>
-        private static TextLine PerformTextWrapping(TextPointer text, IReadOnlyList<ShapedTextRun> textRuns,
-            double paragraphWidth, TextParagraphProperties paragraphProperties)
-        {
-            var availableWidth = paragraphWidth;
-            var currentWidth = 0.0;
-            var runIndex = 0;
-            var length = 0;
-
-            while (runIndex < textRuns.Count)
-            {
-                var currentRun = textRuns[runIndex];
-
-                if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
-                {
-                    var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth);
-
-                    if (measuredLength < currentRun.Text.Length)
-                    {
-                        var currentBreakPosition = -1;
-
-                        var lineBreaker = new LineBreakEnumerator(currentRun.Text);
-
-                        while (currentBreakPosition < measuredLength && lineBreaker.MoveNext())
-                        {
-                            var nextBreakPosition = lineBreaker.Current.PositionWrap;
-
-                            if (nextBreakPosition == 0)
-                            {
-                                break;
-                            }
-
-                            if (nextBreakPosition > measuredLength)
-                            {
-                                break;
-                            }
-
-                            currentBreakPosition = nextBreakPosition;
-                        }
-
-                        if (currentBreakPosition != -1)
-                        {
-                            measuredLength = currentBreakPosition;
-                        }
-                    }
-
-                    length += measuredLength;
-
-                    var splitResult = SplitTextRuns(textRuns, length);
-
-                    var textLineMetrics =
-                        TextLineMetrics.Create(splitResult.First, paragraphWidth, paragraphProperties.TextAlignment);
-
-                    return new SimpleTextLine(text.Take(length), splitResult.First, textLineMetrics);
-                }
-
-                currentWidth += currentRun.GlyphRun.Bounds.Width;
-
-                length += currentRun.GlyphRun.Characters.Length;
-
-                runIndex++;
-            }
-
-            return new SimpleTextLine(text, textRuns,
-                TextLineMetrics.Create(textRuns, paragraphWidth, paragraphProperties.TextAlignment));
-        }
-
-        /// <summary>
-        /// Measures the number of characters that fits into available width.
-        /// </summary>
-        /// <param name="textRun">The text run.</param>
-        /// <param name="availableWidth">The available width.</param>
-        /// <returns></returns>
-        private static int MeasureText(ShapedTextRun textRun, double availableWidth)
-        {
-            var glyphRun = textRun.GlyphRun;
-
-            var characterHit = glyphRun.GetCharacterHitFromDistance(availableWidth, out _);
-
-            return characterHit.FirstCharacterIndex + characterHit.TrailingLength - textRun.Text.Start;
-        }
-
-        /// <summary>
-        /// Creates an ellipsis.
-        /// </summary>
-        /// <param name="textStyle">The text style.</param>
-        /// <returns></returns>
-        private static ShapedTextRun CreateEllipsisRun(TextStyle textStyle)
-        {
-            var formatterImpl = AvaloniaLocator.Current.GetService<ITextShaperImpl>();
-
-            var glyphRun = formatterImpl.ShapeText(s_ellipsis, textStyle.TextFormat);
-
-            return new ShapedTextRun(glyphRun, textStyle);
-        }
-
-        private readonly struct SplitTextRunsResult
-        {
-            public SplitTextRunsResult(IReadOnlyList<ShapedTextRun> first, IReadOnlyList<ShapedTextRun> second)
-            {
-                First = first;
-
-                Second = second;
-            }
-
-            /// <summary>
-            /// Gets the first text runs.
-            /// </summary>
-            /// <value>
-            /// The first text runs.
-            /// </value>
-            public IReadOnlyList<ShapedTextRun> First { get; }
-
-            /// <summary>
-            /// Gets the second text runs.
-            /// </summary>
-            /// <value>
-            /// The second text runs.
-            /// </value>
-            public IReadOnlyList<ShapedTextRun> Second { get; }
-        }
-
-        /// <summary>
-        /// Split a sequence of runs into two segments at specified length.
-        /// </summary>
-        /// <param name="textRuns">The text run's.</param>
-        /// <param name="length">The length to split at.</param>
-        /// <returns></returns>
-        private static SplitTextRunsResult SplitTextRuns(IReadOnlyList<ShapedTextRun> textRuns, int length)
-        {
-            var currentLength = 0;
-
-            for (var i = 0; i < textRuns.Count; i++)
-            {
-                var currentRun = textRuns[i];
-
-                if (currentLength + currentRun.GlyphRun.Characters.Length < length)
-                {
-                    currentLength += currentRun.GlyphRun.Characters.Length;
-                    continue;
-                }
-
-                var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i;
-
-                var first = new ShapedTextRun[firstCount];
-
-                if (firstCount > 1)
-                {
-                    for (var j = 0; j < i; j++)
-                    {
-                        first[j] = textRuns[j];
-                    }
-                }
-
-                var secondCount = textRuns.Count - firstCount;
-
-                if (currentLength + currentRun.GlyphRun.Characters.Length == length)
-                {
-                    var second = new ShapedTextRun[secondCount];
-
-                    var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0;
-
-                    if (secondCount > 0)
-                    {
-                        for (var j = 0; j < secondCount; j++)
-                        {
-                            second[j] = textRuns[i + j + offset];
-                        }
-                    }
-
-                    first[i] = currentRun;
-
-                    return new SplitTextRunsResult(first, second);
-                }
-                else
-                {
-                    secondCount++;
-
-                    var second = new ShapedTextRun[secondCount];
-
-                    if (secondCount > 0)
-                    {
-                        for (var j = 1; j < secondCount; j++)
-                        {
-                            second[j] = textRuns[i + j];
-                        }
-                    }
-
-                    var split = currentRun.Split(length - currentLength);
-
-                    first[i] = split.First;
-
-                    second[0] = split.Second;
-
-                    return new SplitTextRunsResult(first, second);
-                }
-            }
-
-            return new SplitTextRunsResult(textRuns, null);
-        }
-    }
-}

+ 0 - 259
src/Avalonia.Visuals/Media/TextFormatting/SimpleTextLine.cs

@@ -1,259 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Avalonia.Platform;
-
-namespace Avalonia.Media.TextFormatting
-{
-    internal class SimpleTextLine : TextLine
-    {
-        private readonly IReadOnlyList<ShapedTextRun> _textRuns;
-
-        public SimpleTextLine(TextPointer textPointer, IReadOnlyList<ShapedTextRun> textRuns, TextLineMetrics lineMetrics)
-        {
-            Text = textPointer;
-            _textRuns = textRuns;
-            LineMetrics = lineMetrics;
-        }
-
-        /// <inheritdoc/>
-        public override TextPointer Text { get; }
-
-        /// <inheritdoc/>
-        public override IReadOnlyList<TextRun> TextRuns => _textRuns;
-
-        /// <inheritdoc/>
-        public override TextLineMetrics LineMetrics { get; }
-
-        /// <inheritdoc/>
-        public override void Draw(IDrawingContextImpl drawingContext, Point origin)
-        {
-            var currentX = origin.X;
-
-            foreach (var textRun in _textRuns)
-            {
-                var baselineOrigin = new Point(currentX + LineMetrics.BaselineOrigin.X,
-                    origin.Y + LineMetrics.BaselineOrigin.Y);
-
-                textRun.Draw(drawingContext, baselineOrigin);
-
-                currentX += textRun.Bounds.Width;
-            }
-        }
-
-        /// <inheritdoc/>
-        public override CharacterHit GetCharacterHitFromDistance(double distance)
-        {
-            if (distance < 0)
-            {
-                // hit happens before the line, return the first position
-                return new CharacterHit(Text.Start);
-            }
-
-            // process hit that happens within the line
-            var characterHit = new CharacterHit();
-
-            foreach (var run in _textRuns)
-            {
-                characterHit = run.GlyphRun.GetCharacterHitFromDistance(distance, out _);
-
-                if (distance <= run.Bounds.Width)
-                {
-                    break;
-                }
-
-                distance -= run.Bounds.Width;
-            }
-
-            return characterHit;
-        }
-
-        /// <inheritdoc/>
-        public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
-        {
-            return DistanceFromCodepointIndex(characterHit.FirstCharacterIndex + (characterHit.TrailingLength != 0 ? 1 : 0));
-        }
-
-        /// <inheritdoc/>
-        public override CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit)
-        {
-            int nextVisibleCp;
-            bool navigableCpFound;
-
-            if (characterHit.TrailingLength == 0)
-            {
-                navigableCpFound = FindNextCodepointIndex(characterHit.FirstCharacterIndex, out nextVisibleCp);
-
-                if (navigableCpFound)
-                {
-                    // Move from leading to trailing edge
-                    return new CharacterHit(nextVisibleCp, 1);
-                }
-            }
-
-            navigableCpFound = FindNextCodepointIndex(characterHit.FirstCharacterIndex + 1, out nextVisibleCp);
-
-            if (navigableCpFound)
-            {
-                // Move from trailing edge of current character to trailing edge of next
-                return new CharacterHit(nextVisibleCp, 1);
-            }
-
-            // Can't move, we're after the last character
-            return characterHit;
-        }
-
-        /// <inheritdoc/>
-        public override CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit)
-        {
-            int previousCodepointIndex;
-            bool codepointIndexFound;
-
-            var cpHit = characterHit.FirstCharacterIndex;
-            var trailingHit = characterHit.TrailingLength != 0;
-
-            // Input can be right after the end of the current line. Snap it to be at the end of the line.
-            if (cpHit >= Text.Start + Text.Length)
-            {
-                cpHit = Text.Start + Text.Length - 1;
-
-                trailingHit = true;
-            }
-
-            if (trailingHit)
-            {
-                codepointIndexFound = FindPreviousCodepointIndex(cpHit, out previousCodepointIndex);
-
-                if (codepointIndexFound)
-                {
-                    // Move from trailing to leading edge
-                    return new CharacterHit(previousCodepointIndex, 0);
-                }
-            }
-
-            codepointIndexFound = FindPreviousCodepointIndex(cpHit - 1, out previousCodepointIndex);
-
-            if (codepointIndexFound)
-            {
-                // Move from leading edge of current character to leading edge of previous
-                return new CharacterHit(previousCodepointIndex, 0);
-            }
-
-            // Can't move, we're before the first character
-            return characterHit;
-        }
-
-        /// <inheritdoc/>
-        public override CharacterHit GetBackspaceCaretCharacterHit(CharacterHit characterHit)
-        {
-            // same operation as move-to-previous
-            return GetPreviousCaretCharacterHit(characterHit);
-        }
-
-        /// <summary>
-        /// Get distance from line start to the specified codepoint index
-        /// </summary>
-        private double DistanceFromCodepointIndex(int codepointIndex)
-        {
-            var currentDistance = 0.0;
-
-            foreach (var textRun in _textRuns)
-            {
-                if (codepointIndex > textRun.Text.End)
-                {
-                    currentDistance += textRun.Bounds.Width;
-
-                    continue;
-                }
-
-                return currentDistance + textRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(codepointIndex));
-            }
-
-            return currentDistance;
-        }
-
-        /// <summary>
-        /// Search forward from the given codepoint index (inclusive) to find the next navigable codepoint index.
-        /// Return true if one such codepoint index is found, false otherwise.
-        /// </summary>
-        private bool FindNextCodepointIndex(int codepointIndex, out int nextCodepointIndex)
-        {
-            nextCodepointIndex = codepointIndex;
-
-            if (codepointIndex >= Text.Start + Text.Length)
-            {
-                return false; // Cannot go forward anymore
-            }
-
-            GetRunIndexAtCodepointIndex(codepointIndex, out var runIndex, out var cpRunStart);
-
-            while (runIndex < TextRuns.Count)
-            {
-                // When navigating forward, only the trailing edge of visible content is
-                // navigable.
-                if (runIndex < TextRuns.Count)
-                {
-                    nextCodepointIndex = Math.Max(cpRunStart, codepointIndex);
-                    return true;
-                }
-
-                cpRunStart += TextRuns[runIndex++].Text.Length;
-            }
-
-            return false;
-        }
-
-        /// <summary>
-        /// Search backward from the given codepoint index (inclusive) to find the previous navigable codepoint index.
-        /// Return true if one such codepoint is found, false otherwise.
-        /// </summary>
-        private bool FindPreviousCodepointIndex(int codepointIndex, out int previousCodepointIndex)
-        {
-            previousCodepointIndex = codepointIndex;
-
-            if (codepointIndex < Text.Start)
-            {
-                return false; // Cannot go backward anymore.
-            }
-
-            // Position the cpRunEnd at the end of the span that contains the given cp
-            GetRunIndexAtCodepointIndex(codepointIndex, out var runIndex, out var codepointIndexAtRunEnd);
-
-            codepointIndexAtRunEnd += TextRuns[runIndex].Text.End;
-
-            while (runIndex >= 0)
-            {
-                // Visible content has caret stops at its leading edge.
-                if (runIndex + 1 < TextRuns.Count)
-                {
-                    previousCodepointIndex = Math.Min(codepointIndexAtRunEnd, codepointIndex);
-                    return true;
-                }
-
-                // Newline sequence has caret stops at its leading edge.
-                if (runIndex == TextRuns.Count)
-                {
-                    // Get the cp index at the beginning of the newline sequence.
-                    previousCodepointIndex = codepointIndexAtRunEnd - TextRuns[runIndex].Text.Length + 1;
-                    return true;
-                }
-
-                codepointIndexAtRunEnd -= TextRuns[runIndex--].Text.Length;
-            }
-
-            return false;
-        }
-
-        private void GetRunIndexAtCodepointIndex(int codepointIndex, out int runIndex, out int codepointIndexAtRunStart)
-        {
-            codepointIndexAtRunStart = Text.Start;
-            runIndex = 0;
-
-            // Find the span that contains the given cp
-            while (runIndex < TextRuns.Count &&
-                   codepointIndexAtRunStart + TextRuns[runIndex].Text.Length <= codepointIndex)
-            {
-                codepointIndexAtRunStart += TextRuns[runIndex++].Text.Length;
-            }
-        }
-    }
-}

+ 175 - 6
src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs

@@ -1,4 +1,6 @@
-using Avalonia.Utility;
+using System.Collections.Generic;
+using Avalonia.Media.TextFormatting.Unicode;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -7,15 +9,182 @@ namespace Avalonia.Media.TextFormatting
     /// </summary>
     public class TextCharacters : TextRun
     {
-        protected TextCharacters()
+        public TextCharacters(ReadOnlySlice<char> text, TextRunProperties properties)
         {
-            
+            TextSourceLength = text.Length;
+            Text = text;
+            Properties = properties;
         }
 
-        public TextCharacters(ReadOnlySlice<char> text, TextStyle style)
+        /// <inheritdoc />
+        public override int TextSourceLength { get; }
+
+        /// <inheritdoc />
+        public override ReadOnlySlice<char> Text { get; }
+
+        /// <inheritdoc />
+        public override TextRunProperties Properties { get; }
+
+        /// <summary>
+        /// Gets a list of <see cref="ShapeableTextCharacters"/>.
+        /// </summary>
+        /// <returns>The shapeable text characters.</returns>
+        internal IList<ShapeableTextCharacters> GetShapeableCharacters()
         {
-            Text = text;
-            Style = style;
+            var shapeableCharacters = new List<ShapeableTextCharacters>(2);
+
+            var runText = Text;
+
+            while (!runText.IsEmpty)
+            {
+                var shapeableRun = CreateShapeableRun(runText, Properties);
+
+                shapeableCharacters.Add(shapeableRun);
+
+                runText = runText.Skip(shapeableRun.Text.Length);
+            }
+
+            return shapeableCharacters;
+        }
+
+        /// <summary>
+        /// Creates a shapeable text run with unique properties.
+        /// </summary>
+        /// <param name="text">The text to create text runs from.</param>
+        /// <param name="defaultProperties">The default text run properties.</param>
+        /// <returns>A list of shapeable text runs.</returns>
+        private ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice<char> text, TextRunProperties defaultProperties)
+        {
+            var defaultTypeface = defaultProperties.Typeface;
+
+            var currentTypeface = defaultTypeface;
+
+            if (TryGetRunProperties(text, currentTypeface, defaultTypeface, out var count))
+            {
+                return new ShapeableTextCharacters(text.Take(count),
+                    new GenericTextRunProperties(currentTypeface, defaultProperties.FontRenderingEmSize,
+                        defaultProperties.TextDecorations, defaultProperties.ForegroundBrush));
+
+            }
+
+            var codepoint = Codepoint.ReadAt(text, count, out _);
+
+            //ToDo: Fix FontFamily fallback
+            currentTypeface =
+                FontManager.Current.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style, defaultTypeface.FontFamily);
+
+            if (currentTypeface != null && TryGetRunProperties(text, currentTypeface, defaultTypeface, out count))
+            {
+                //Fallback found
+                return new ShapeableTextCharacters(text.Take(count),
+                    new GenericTextRunProperties(currentTypeface, defaultProperties.FontRenderingEmSize,
+                    defaultProperties.TextDecorations, defaultProperties.ForegroundBrush));
+            }
+
+            // no fallback found
+            currentTypeface = defaultTypeface;
+
+            var glyphTypeface = currentTypeface.GlyphTypeface;
+
+            var enumerator = new GraphemeEnumerator(text);
+
+            while (enumerator.MoveNext())
+            {
+                var grapheme = enumerator.Current;
+
+                if (!grapheme.FirstCodepoint.IsWhiteSpace && glyphTypeface.TryGetGlyph(grapheme.FirstCodepoint, out _))
+                {
+                    break;
+                }
+
+                count += grapheme.Text.Length;
+            }
+
+            return new ShapeableTextCharacters(text.Take(count),
+                new GenericTextRunProperties(currentTypeface, defaultProperties.FontRenderingEmSize,
+                    defaultProperties.TextDecorations, defaultProperties.ForegroundBrush));
+        }
+
+        /// <summary>
+        /// Tries to get run properties.
+        /// </summary>
+        /// <param name="defaultTypeface"></param>
+        /// <param name="text"></param>
+        /// <param name="typeface">The typeface that is used to find matching characters.</param>
+        /// <param name="count"></param>
+        /// <returns></returns>
+        protected bool TryGetRunProperties(ReadOnlySlice<char> text, Typeface typeface, Typeface defaultTypeface,
+            out int count)
+        {
+            if (text.Length == 0)
+            {
+                count = 0;
+                return false;
+            }
+
+            var isFallback = typeface != defaultTypeface;
+
+            count = 0;
+            var script = Script.Common;
+            //var direction = BiDiClass.LeftToRight;
+
+            var font = typeface.GlyphTypeface;
+            var defaultFont = defaultTypeface.GlyphTypeface;
+
+            var enumerator = new GraphemeEnumerator(text);
+
+            while (enumerator.MoveNext())
+            {
+                var grapheme = enumerator.Current;
+
+                var currentScript = grapheme.FirstCodepoint.Script;
+
+                //var currentDirection = grapheme.FirstCodepoint.BiDiClass;
+
+                //// ToDo: Implement BiDi algorithm
+                //if (currentScript.HorizontalDirection != direction)
+                //{
+                //    if (!UnicodeUtility.IsWhiteSpace(grapheme.FirstCodepoint))
+                //    {
+                //        break;
+                //    }
+                //}
+
+                if (currentScript != script)
+                {
+                    if (currentScript != Script.Inherited && currentScript != Script.Common)
+                    {
+                        if (script == Script.Inherited || script == Script.Common)
+                        {
+                            script = currentScript;
+                        }
+                        else
+                        {
+                            break;
+                        }
+                    }
+                }
+
+                if (isFallback)
+                {
+                    if (defaultFont.TryGetGlyph(grapheme.FirstCodepoint, out _))
+                    {
+                        break;
+                    }
+                }
+
+                if (!font.TryGetGlyph(grapheme.FirstCodepoint, out _))
+                {
+                    if (!grapheme.FirstCodepoint.IsWhiteSpace)
+                    {
+                        break;
+                    }
+                }
+
+                count += grapheme.Text.Length;
+            }
+
+            return count > 0;
         }
     }
 }

+ 0 - 71
src/Avalonia.Visuals/Media/TextFormatting/TextFormat.cs

@@ -1,71 +0,0 @@
-using System;
-
-namespace Avalonia.Media.TextFormatting
-{
-    /// <summary>
-    /// Unique text formatting properties that are used by the <see cref="TextFormatter"/>.
-    /// </summary>
-    public readonly struct TextFormat : IEquatable<TextFormat>
-    {
-        public TextFormat(Typeface typeface, double fontRenderingEmSize)
-        {
-            Typeface = typeface;
-            FontRenderingEmSize = fontRenderingEmSize;
-            FontMetrics = new FontMetrics(typeface, fontRenderingEmSize);
-        }
-
-        /// <summary>
-        /// Gets the typeface.
-        /// </summary>
-        /// <value>
-        /// The typeface.
-        /// </value>
-        public Typeface Typeface { get; }
-
-        /// <summary>
-        /// Gets the font rendering em size.
-        /// </summary>
-        /// <value>
-        /// The em rendering size of the font.
-        /// </value>
-        public double FontRenderingEmSize { get; }
-
-        /// <summary>
-        /// Gets the font metrics.
-        /// </summary>
-        /// <value>
-        /// The metrics of the font.
-        /// </value> 
-        public FontMetrics FontMetrics { get; }
-
-        public static bool operator ==(TextFormat self, TextFormat other)
-        {
-            return self.Equals(other);
-        }
-
-        public static bool operator !=(TextFormat self, TextFormat other)
-        {
-            return !(self == other);
-        }
-
-        public bool Equals(TextFormat other)
-        {
-            return Typeface.Equals(other.Typeface) && FontRenderingEmSize.Equals(other.FontRenderingEmSize);
-        }
-
-        public override bool Equals(object obj)
-        {
-            return obj is TextFormat other && Equals(other);
-        }
-
-        public override int GetHashCode()
-        {
-            unchecked
-            {
-                var hashCode = (Typeface != null ? Typeface.GetHashCode() : 0);
-                hashCode = (hashCode * 397) ^ FontRenderingEmSize.GetHashCode();
-                return hashCode;
-            }
-        }
-    }
-}

+ 4 - 144
src/Avalonia.Visuals/Media/TextFormatting/TextFormatter.cs

@@ -1,5 +1,4 @@
 using Avalonia.Media.TextFormatting.Unicode;
-using Avalonia.Utility;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -22,7 +21,7 @@ namespace Avalonia.Media.TextFormatting
                     return current;
                 }
 
-                current = new SimpleTextFormatter();
+                current = new TextFormatterImpl();
 
                 AvaloniaLocator.CurrentMutable.Bind<TextFormatter>().ToConstant(current);
 
@@ -38,149 +37,10 @@ namespace Avalonia.Media.TextFormatting
         /// <param name="paragraphWidth">A <see cref="double"/> value that specifies the width of the paragraph that the line fills.</param>
         /// <param name="paragraphProperties">A <see cref="TextParagraphProperties"/> value that represents paragraph properties,
         /// such as TextWrapping, TextAlignment, or TextStyle.</param>
+        /// <param name="previousLineBreak">A <see cref="TextLineBreak"/> value that specifies the text formatter state,
+        /// in terms of where the previous line in the paragraph was broken by the text formatting process.</param>
         /// <returns>The formatted line.</returns>
         public abstract TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
-            TextParagraphProperties paragraphProperties);
-
-        /// <summary>
-        /// Creates a text style run with unique properties.
-        /// </summary>
-        /// <param name="text">The text to create text runs from.</param>
-        /// <param name="defaultStyle"></param>
-        /// <returns>A list of text runs.</returns>
-        protected TextStyleRun CreateShapableTextStyleRun(ReadOnlySlice<char> text, TextStyle defaultStyle)
-        {
-            var defaultTypeface = defaultStyle.TextFormat.Typeface;
-
-            var currentTypeface = defaultTypeface;
-
-            if (TryGetRunProperties(text, currentTypeface, defaultTypeface, out var count))
-            {
-                return new TextStyleRun(new TextPointer(text.Start, count), new TextStyle(currentTypeface,
-                    defaultStyle.TextFormat.FontRenderingEmSize,
-                    defaultStyle.Foreground, defaultStyle.TextDecorations));
-
-            }
-
-            var codepoint = Codepoint.ReadAt(text, count, out _);
-
-            //ToDo: Fix FontFamily fallback
-            currentTypeface =
-                FontManager.Current.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style, defaultStyle.TextFormat.Typeface.FontFamily);
-
-            if (currentTypeface != null && TryGetRunProperties(text, currentTypeface, defaultTypeface, out count))
-            {
-                //Fallback found
-                return new TextStyleRun(new TextPointer(text.Start, count), new TextStyle(currentTypeface,
-                    defaultStyle.TextFormat.FontRenderingEmSize,
-                    defaultStyle.Foreground, defaultStyle.TextDecorations));
-
-            }
-
-            // no fallback found
-            currentTypeface = defaultTypeface;
-
-            var glyphTypeface = currentTypeface.GlyphTypeface;
-
-            var enumerator = new GraphemeEnumerator(text);
-
-            while (enumerator.MoveNext())
-            {
-                var grapheme = enumerator.Current;
-
-                if (!grapheme.FirstCodepoint.IsWhiteSpace && glyphTypeface.TryGetGlyph(grapheme.FirstCodepoint, out _))
-                {
-                    break;
-                }
-
-                count += grapheme.Text.Length;
-            }
-
-            return new TextStyleRun(new TextPointer(text.Start, count),
-                new TextStyle(currentTypeface, defaultStyle.TextFormat.FontRenderingEmSize,
-                    defaultStyle.Foreground, defaultStyle.TextDecorations));
-        }
-
-        /// <summary>
-        /// Tries to get run properties.
-        /// </summary>
-        /// <param name="defaultTypeface"></param>
-        /// <param name="text"></param>
-        /// <param name="typeface">The typeface that is used to find matching characters.</param>
-        /// <param name="count"></param>
-        /// <returns></returns>
-        protected bool TryGetRunProperties(ReadOnlySlice<char> text, Typeface typeface, Typeface defaultTypeface,
-            out int count)
-        {
-            if (text.Length == 0)
-            {
-                count = 0;
-                return false;
-            }
-
-            var isFallback = typeface != defaultTypeface;
-
-            count = 0;
-            var script = Script.Common;
-            //var direction = BiDiClass.LeftToRight;
-
-            var font = typeface.GlyphTypeface;
-            var defaultFont = defaultTypeface.GlyphTypeface;
-
-            var enumerator = new GraphemeEnumerator(text);
-
-            while (enumerator.MoveNext())
-            {
-                var grapheme = enumerator.Current;
-
-                var currentScript = grapheme.FirstCodepoint.Script;
-
-                //var currentDirection = grapheme.FirstCodepoint.BiDiClass;
-
-                //// ToDo: Implement BiDi algorithm
-                //if (currentScript.HorizontalDirection != direction)
-                //{
-                //    if (!UnicodeUtility.IsWhiteSpace(grapheme.FirstCodepoint))
-                //    {
-                //        break;
-                //    }
-                //}
-
-                if (currentScript != script)
-                {
-                    if (currentScript != Script.Inherited && currentScript != Script.Common)
-                    {
-                        if (script == Script.Inherited || script == Script.Common)
-                        {
-                            script = currentScript;
-                        }
-                        else
-                        {
-                            break;
-                        }
-                    }
-                }
-
-                if (isFallback)
-                {
-                    if (defaultFont.TryGetGlyph(grapheme.FirstCodepoint, out _))
-                    {
-                        break;
-                    }
-                }
-
-                if (!font.TryGetGlyph(grapheme.FirstCodepoint, out _))
-                {
-                    if (!grapheme.FirstCodepoint.IsWhiteSpace)
-                    {
-                        break;
-                    }
-                }
-
-                count += grapheme.Text.Length;
-            }
-
-            return count > 0;
-        }
+            TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null);
     }
 }

+ 544 - 0
src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs

@@ -0,0 +1,544 @@
+using System.Collections.Generic;
+using Avalonia.Media.TextFormatting.Unicode;
+using Avalonia.Platform;
+using Avalonia.Utilities;
+
+namespace Avalonia.Media.TextFormatting
+{
+    internal class TextFormatterImpl : TextFormatter
+    {
+        private static readonly ReadOnlySlice<char> s_ellipsis = new ReadOnlySlice<char>(new[] { '\u2026' });
+
+        /// <inheritdoc cref="TextFormatter.FormatLine"/>
+        public override TextLine FormatLine(ITextSource textSource, int firstTextSourceIndex, double paragraphWidth,
+            TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak = null)
+        {
+            var textTrimming = paragraphProperties.TextTrimming;
+            var textWrapping = paragraphProperties.TextWrapping;
+            TextLine textLine = null;
+
+            var textRuns = FetchTextRuns(textSource, firstTextSourceIndex, previousLineBreak, out var nextLineBreak);
+
+            var textRange = GetTextRange(textRuns);
+
+            if (textTrimming != TextTrimming.None)
+            {
+                textLine = PerformTextTrimming(textRuns, textRange, paragraphWidth, paragraphProperties);
+            }
+            else
+            {
+                switch (textWrapping)
+                {
+                    case TextWrapping.NoWrap:
+                        {
+                            var textLineMetrics =
+                                TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties);
+
+                            textLine = new TextLineImpl(textRuns, textLineMetrics, nextLineBreak);
+                            break;
+                        }
+                    case TextWrapping.WrapWithOverflow:
+                    case TextWrapping.Wrap:
+                        {
+                            textLine = PerformTextWrapping(textRuns, textRange, paragraphWidth, paragraphProperties);
+                            break;
+                        }
+                }
+            }
+
+            return textLine;
+        }
+
+        /// <summary>
+        /// Fetches text runs.
+        /// </summary>
+        /// <param name="textSource">The text source.</param>
+        /// <param name="firstTextSourceIndex">The first text source index.</param>
+        /// <param name="previousLineBreak">Previous line break. Can be null.</param>
+        /// <param name="nextLineBreak">Next line break. Can be null.</param>
+        /// <returns>
+        /// The formatted text runs.
+        /// </returns>
+        private static IReadOnlyList<ShapedTextCharacters> FetchTextRuns(ITextSource textSource,
+            int firstTextSourceIndex, TextLineBreak previousLineBreak, out TextLineBreak nextLineBreak)
+        {
+            nextLineBreak = default;
+
+            var currentLength = 0;
+
+            var textRuns = new List<ShapedTextCharacters>();
+
+            if (previousLineBreak != null)
+            {
+                foreach (var shapedCharacters in previousLineBreak.RemainingCharacters)
+                {
+                    textRuns.Add(shapedCharacters);
+
+                    if (TryGetLineBreak(shapedCharacters, out var runLineBreak))
+                    {
+                        var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap);
+
+                        nextLineBreak = new TextLineBreak(splitResult.Second);
+
+                        return splitResult.First;
+                    }
+
+                    currentLength += shapedCharacters.Text.Length;
+                }
+            }
+
+            firstTextSourceIndex += currentLength;
+
+            var textRunEnumerator = new TextRunEnumerator(textSource, firstTextSourceIndex);
+
+            while (textRunEnumerator.MoveNext())
+            {
+                var textRun = textRunEnumerator.Current;
+
+                switch (textRun)
+                {
+                    case TextCharacters textCharacters:
+                        {
+                            var shapeableRuns = textCharacters.GetShapeableCharacters();
+
+                            foreach (var run in shapeableRuns)
+                            {
+                                var glyphRun = TextShaper.Current.ShapeText(run.Text, run.Properties.Typeface,
+                                    run.Properties.FontRenderingEmSize, run.Properties.CultureInfo);
+
+                                var shapedCharacters = new ShapedTextCharacters(glyphRun, textRun.Properties);
+
+                                textRuns.Add(shapedCharacters);
+                            }
+
+                            break;
+                        }
+                }
+
+                if (TryGetLineBreak(textRun, out var runLineBreak))
+                {
+                    var splitResult = SplitTextRuns(textRuns, currentLength + runLineBreak.PositionWrap);
+
+                    nextLineBreak = new TextLineBreak(splitResult.Second);
+
+                    return splitResult.First;
+                }
+
+                currentLength += textRun.Text.Length;
+            }
+
+            return textRuns;
+        }
+
+        private static bool TryGetLineBreak(TextRun textRun, out LineBreak lineBreak)
+        {
+            lineBreak = default;
+
+            if (textRun.Text.IsEmpty)
+            {
+                return false;
+            }
+
+            var lineBreakEnumerator = new LineBreakEnumerator(textRun.Text);
+
+            while (lineBreakEnumerator.MoveNext())
+            {
+                if (!lineBreakEnumerator.Current.Required)
+                {
+                    continue;
+                }
+
+                lineBreak = lineBreakEnumerator.Current;
+
+                if (lineBreak.PositionWrap >= textRun.Text.Length)
+                {
+                    return true;
+                }
+
+                //The line breaker isn't treating \n\r as a pair so we have to fix that here.
+                if (textRun.Text[lineBreak.PositionMeasure] == '\n'
+                    && textRun.Text[lineBreak.PositionWrap] == '\r')
+                {
+                    lineBreak = new LineBreak(lineBreak.PositionMeasure, lineBreak.PositionWrap + 1,
+                        lineBreak.Required);
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Performs text trimming and returns a trimmed line.
+        /// </summary>
+        /// <param name="textRuns">The text runs to perform the trimming on.</param>
+        /// <param name="textRange">The text range that is covered by the text runs.</param>
+        /// <param name="paragraphWidth">A <see cref="double"/> value that specifies the width of the paragraph that the line fills.</param>
+        /// <param name="paragraphProperties">A <see cref="TextParagraphProperties"/> value that represents paragraph properties,
+        /// such as TextWrapping, TextAlignment, or TextStyle.</param>
+        /// <returns></returns>
+        private static TextLine PerformTextTrimming(IReadOnlyList<ShapedTextCharacters> textRuns, TextRange textRange,
+            double paragraphWidth, TextParagraphProperties paragraphProperties)
+        {
+            var textTrimming = paragraphProperties.TextTrimming;
+            var availableWidth = paragraphWidth;
+            var currentWidth = 0.0;
+            var runIndex = 0;
+
+            while (runIndex < textRuns.Count)
+            {
+                var currentRun = textRuns[runIndex];
+
+                currentWidth += currentRun.GlyphRun.Bounds.Width;
+
+                if (currentWidth > availableWidth)
+                {
+                    var ellipsisRun = CreateEllipsisRun(currentRun.Properties);
+
+                    var measuredLength = MeasureText(currentRun, availableWidth - ellipsisRun.GlyphRun.Bounds.Width);
+
+                    if (textTrimming == TextTrimming.WordEllipsis)
+                    {
+                        if (measuredLength < textRange.End)
+                        {
+                            var currentBreakPosition = 0;
+
+                            var lineBreaker = new LineBreakEnumerator(currentRun.Text);
+
+                            while (currentBreakPosition < measuredLength && lineBreaker.MoveNext())
+                            {
+                                var nextBreakPosition = lineBreaker.Current.PositionWrap;
+
+                                if (nextBreakPosition == 0)
+                                {
+                                    break;
+                                }
+
+                                if (nextBreakPosition > measuredLength)
+                                {
+                                    break;
+                                }
+
+                                currentBreakPosition = nextBreakPosition;
+                            }
+
+                            measuredLength = currentBreakPosition;
+                        }
+                    }
+
+                    var splitResult = SplitTextRuns(textRuns, measuredLength);
+
+                    var trimmedRuns = new List<ShapedTextCharacters>(splitResult.First.Count + 1);
+
+                    trimmedRuns.AddRange(splitResult.First);
+
+                    trimmedRuns.Add(ellipsisRun);
+
+                    var textLineMetrics =
+                        TextLineMetrics.Create(trimmedRuns, textRange, paragraphWidth, paragraphProperties);
+
+                    return new TextLineImpl(trimmedRuns, textLineMetrics);
+                }
+
+                availableWidth -= currentRun.GlyphRun.Bounds.Width;
+
+                runIndex++;
+            }
+
+            return new TextLineImpl(textRuns,
+                TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties));
+        }
+
+        /// <summary>
+        /// Performs text wrapping returns a list of text lines.
+        /// </summary>
+        /// <param name="textRuns">The text run's.</param>
+        /// <param name="textRange">The text range that is covered by the text runs.</param>
+        /// <param name="paragraphWidth">The paragraph width.</param>
+        /// <param name="paragraphProperties">The text paragraph properties.</param>
+        /// <returns>The wrapped text line.</returns>
+        private static TextLine PerformTextWrapping(IReadOnlyList<ShapedTextCharacters> textRuns, TextRange textRange,
+            double paragraphWidth, TextParagraphProperties paragraphProperties)
+        {
+            var availableWidth = paragraphWidth;
+            var currentWidth = 0.0;
+            var runIndex = 0;
+            var length = 0;
+
+            while (runIndex < textRuns.Count)
+            {
+                var currentRun = textRuns[runIndex];
+
+                if (currentWidth + currentRun.GlyphRun.Bounds.Width > availableWidth)
+                {
+                    var measuredLength = MeasureText(currentRun, paragraphWidth - currentWidth);
+
+                    if (measuredLength < currentRun.Text.Length)
+                    {
+                        if (paragraphProperties.TextWrapping == TextWrapping.WrapWithOverflow)
+                        {
+                            var lineBreaker = new LineBreakEnumerator(currentRun.Text.Skip(measuredLength));
+
+                            if (lineBreaker.MoveNext())
+                            {
+                                measuredLength += lineBreaker.Current.PositionWrap;
+                            }
+                            else
+                            {
+                                measuredLength = currentRun.Text.Length;
+                            }
+                        }
+                        else
+                        {
+                            var currentBreakPosition = -1;
+
+                            var lineBreaker = new LineBreakEnumerator(currentRun.Text);
+
+                            while (currentBreakPosition < measuredLength && lineBreaker.MoveNext())
+                            {
+                                var nextBreakPosition = lineBreaker.Current.PositionWrap;
+
+                                if (nextBreakPosition == 0)
+                                {
+                                    break;
+                                }
+
+                                if (nextBreakPosition > measuredLength)
+                                {
+                                    break;
+                                }
+
+                                currentBreakPosition = nextBreakPosition;
+                            }
+
+                            if (currentBreakPosition != -1)
+                            {
+                                measuredLength = currentBreakPosition;
+                            }
+
+                        }
+                    }
+
+                    length += measuredLength;
+
+                    var splitResult = SplitTextRuns(textRuns, length);
+
+                    var textLineMetrics = TextLineMetrics.Create(splitResult.First,
+                        new TextRange(textRange.Start, length), paragraphWidth, paragraphProperties);
+
+                    var lineBreak = splitResult.Second != null && splitResult.Second.Count > 0 ?
+                        new TextLineBreak(splitResult.Second) :
+                        null;
+
+                    return new TextLineImpl(splitResult.First, textLineMetrics, lineBreak);
+                }
+
+                currentWidth += currentRun.GlyphRun.Bounds.Width;
+
+                length += currentRun.GlyphRun.Characters.Length;
+
+                runIndex++;
+            }
+
+            return new TextLineImpl(textRuns,
+                TextLineMetrics.Create(textRuns, textRange, paragraphWidth, paragraphProperties));
+        }
+
+        /// <summary>
+        /// Measures the number of characters that fits into available width.
+        /// </summary>
+        /// <param name="textCharacters">The text run.</param>
+        /// <param name="availableWidth">The available width.</param>
+        /// <returns></returns>
+        private static int MeasureText(ShapedTextCharacters textCharacters, double availableWidth)
+        {
+            var glyphRun = textCharacters.GlyphRun;
+
+            var characterHit = glyphRun.GetCharacterHitFromDistance(availableWidth, out _);
+
+            return characterHit.FirstCharacterIndex + characterHit.TrailingLength - textCharacters.Text.Start;
+        }
+
+        /// <summary>
+        /// Creates an ellipsis.
+        /// </summary>
+        /// <param name="properties">The text run properties.</param>
+        /// <returns></returns>
+        private static ShapedTextCharacters CreateEllipsisRun(TextRunProperties properties)
+        {
+            var formatterImpl = AvaloniaLocator.Current.GetService<ITextShaperImpl>();
+
+            var glyphRun = formatterImpl.ShapeText(s_ellipsis, properties.Typeface, properties.FontRenderingEmSize,
+                properties.CultureInfo);
+
+            return new ShapedTextCharacters(glyphRun, properties);
+        }
+
+        /// <summary>
+        /// Gets the text range that is covered by the text runs.
+        /// </summary>
+        /// <param name="textRuns">The text runs.</param>
+        /// <returns>The text range that is covered by the text runs.</returns>
+        private static TextRange GetTextRange(IReadOnlyList<TextRun> textRuns)
+        {
+            if (textRuns is null || textRuns.Count == 0)
+            {
+                return new TextRange();
+            }
+
+            var firstTextRun = textRuns[0];
+
+            if (textRuns.Count == 1)
+            {
+                return new TextRange(firstTextRun.Text.Start, firstTextRun.Text.Length);
+            }
+
+            var start = firstTextRun.Text.Start;
+
+            var end = textRuns[textRuns.Count - 1].Text.End + 1;
+
+            return new TextRange(start, end - start);
+        }
+
+        /// <summary>
+        /// Split a sequence of runs into two segments at specified length.
+        /// </summary>
+        /// <param name="textRuns">The text run's.</param>
+        /// <param name="length">The length to split at.</param>
+        /// <returns>The split text runs.</returns>
+        private static SplitTextRunsResult SplitTextRuns(IReadOnlyList<ShapedTextCharacters> textRuns, int length)
+        {
+            var currentLength = 0;
+
+            for (var i = 0; i < textRuns.Count; i++)
+            {
+                var currentRun = textRuns[i];
+
+                if (currentLength + currentRun.GlyphRun.Characters.Length < length)
+                {
+                    currentLength += currentRun.GlyphRun.Characters.Length;
+                    continue;
+                }
+
+                var firstCount = currentRun.GlyphRun.Characters.Length >= 1 ? i + 1 : i;
+
+                var first = new ShapedTextCharacters[firstCount];
+
+                if (firstCount > 1)
+                {
+                    for (var j = 0; j < i; j++)
+                    {
+                        first[j] = textRuns[j];
+                    }
+                }
+
+                var secondCount = textRuns.Count - firstCount;
+
+                if (currentLength + currentRun.GlyphRun.Characters.Length == length)
+                {
+                    var second = new ShapedTextCharacters[secondCount];
+
+                    var offset = currentRun.GlyphRun.Characters.Length > 1 ? 1 : 0;
+
+                    if (secondCount > 0)
+                    {
+                        for (var j = 0; j < secondCount; j++)
+                        {
+                            second[j] = textRuns[i + j + offset];
+                        }
+                    }
+
+                    first[i] = currentRun;
+
+                    return new SplitTextRunsResult(first, second);
+                }
+                else
+                {
+                    secondCount++;
+
+                    var second = new ShapedTextCharacters[secondCount];
+
+                    if (secondCount > 0)
+                    {
+                        for (var j = 1; j < secondCount; j++)
+                        {
+                            second[j] = textRuns[i + j];
+                        }
+                    }
+
+                    var split = currentRun.Split(length - currentLength);
+
+                    first[i] = split.First;
+
+                    second[0] = split.Second;
+
+                    return new SplitTextRunsResult(first, second);
+                }
+            }
+
+            return new SplitTextRunsResult(textRuns, null);
+        }
+
+        private readonly struct SplitTextRunsResult
+        {
+            public SplitTextRunsResult(IReadOnlyList<ShapedTextCharacters> first, IReadOnlyList<ShapedTextCharacters> second)
+            {
+                First = first;
+
+                Second = second;
+            }
+
+            /// <summary>
+            /// Gets the first text runs.
+            /// </summary>
+            /// <value>
+            /// The first text runs.
+            /// </value>
+            public IReadOnlyList<ShapedTextCharacters> First { get; }
+
+            /// <summary>
+            /// Gets the second text runs.
+            /// </summary>
+            /// <value>
+            /// The second text runs.
+            /// </value>
+            public IReadOnlyList<ShapedTextCharacters> Second { get; }
+        }
+
+        private struct TextRunEnumerator
+        {
+            private readonly ITextSource _textSource;
+            private int _pos;
+
+            public TextRunEnumerator(ITextSource textSource, int firstTextSourceIndex)
+            {
+                _textSource = textSource;
+                _pos = firstTextSourceIndex;
+                Current = null;
+            }
+
+            // ReSharper disable once MemberHidesStaticFromOuterClass
+            public TextRun Current { get; private set; }
+
+            public bool MoveNext()
+            {
+                Current = _textSource.GetTextRun(_pos);
+
+                if (Current is null)
+                {
+                    return false;
+                }
+
+                if (Current.TextSourceLength == 0)
+                {
+                    return false;
+                }
+
+                _pos += Current.TextSourceLength;
+
+                return !(Current is TextEndOfLine);
+            }
+        }
+    }
+}

+ 84 - 108
src/Avalonia.Visuals/Media/TextFormatting/TextLayout.cs

@@ -1,11 +1,9 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using Avalonia.Media.Immutable;
 using Avalonia.Media.TextFormatting.Unicode;
-using Avalonia.Platform;
 using Avalonia.Utilities;
-using Avalonia.Utility;
+using Avalonia.Platform;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -14,11 +12,11 @@ namespace Avalonia.Media.TextFormatting
     /// </summary>
     public class TextLayout
     {
-        private static readonly ReadOnlySlice<char> s_empty = new ReadOnlySlice<char>(new[] { '\u200B' });
+        private static readonly char[] s_empty = { '\u200B' };
 
         private readonly ReadOnlySlice<char> _text;
         private readonly TextParagraphProperties _paragraphProperties;
-        private readonly IReadOnlyList<TextStyleRun> _textStyleOverrides;
+        private readonly IReadOnlyList<ValueSpan<TextRunProperties>> _textStyleOverrides;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="TextLayout" /> class.
@@ -33,6 +31,7 @@ namespace Avalonia.Media.TextFormatting
         /// <param name="textDecorations">The text decorations.</param>
         /// <param name="maxWidth">The maximum width.</param>
         /// <param name="maxHeight">The maximum height.</param>
+        /// <param name="lineHeight">The height of each line of text.</param>
         /// <param name="maxLines">The maximum number of text lines.</param>
         /// <param name="textStyleOverrides">The text style overrides.</param>
         public TextLayout(
@@ -46,18 +45,22 @@ namespace Avalonia.Media.TextFormatting
             TextDecorationCollection textDecorations = null,
             double maxWidth = double.PositiveInfinity,
             double maxHeight = double.PositiveInfinity,
+            double lineHeight = double.NaN,
             int maxLines = 0,
-            IReadOnlyList<TextStyleRun> textStyleOverrides = null)
+            IReadOnlyList<ValueSpan<TextRunProperties>> textStyleOverrides = null)
         {
             _text = string.IsNullOrEmpty(text) ?
                 new ReadOnlySlice<char>() :
                 new ReadOnlySlice<char>(text.AsMemory());
 
             _paragraphProperties =
-                CreateTextParagraphProperties(typeface, fontSize, foreground, textAlignment, textWrapping, textTrimming, textDecorations?.ToImmutable());
+                CreateTextParagraphProperties(typeface, fontSize, foreground, textAlignment, textWrapping, textTrimming,
+                    textDecorations, lineHeight);
 
             _textStyleOverrides = textStyleOverrides;
 
+            LineHeight = lineHeight;
+
             MaxWidth = maxWidth;
 
             MaxHeight = maxHeight;
@@ -67,22 +70,29 @@ namespace Avalonia.Media.TextFormatting
             UpdateLayout();
         }
 
+        /// <summary>
+        /// Gets or sets the height of each line of text.
+        /// </summary>
+        /// <remarks>
+        /// A value of NaN (equivalent to an attribute value of "Auto") indicates that the line height
+        /// is determined automatically from the current font characteristics. The default is NaN.
+        /// </remarks>
+        public double LineHeight { get; }
+
         /// <summary>
         /// Gets the maximum width.
         /// </summary>
         public double MaxWidth { get; }
 
-
         /// <summary>
         /// Gets the maximum height.
         /// </summary>
         public double MaxHeight { get; }
 
-
         /// <summary>
         /// Gets the maximum number of text lines.
         /// </summary>
-        public double MaxLines { get; }
+        public int MaxLines { get; }
 
         /// <summary>
         /// Gets the text lines.
@@ -105,7 +115,7 @@ namespace Avalonia.Media.TextFormatting
         /// </summary>
         /// <param name="context">The drawing context.</param>
         /// <param name="origin">The origin.</param>
-        public void Draw(IDrawingContextImpl context, Point origin)
+        public void Draw(DrawingContext context, Point origin)
         {
             if (!TextLines.Any())
             {
@@ -132,14 +142,16 @@ namespace Avalonia.Media.TextFormatting
         /// <param name="textWrapping">The text wrapping.</param>
         /// <param name="textTrimming">The text trimming.</param>
         /// <param name="textDecorations">The text decorations.</param>
+        /// <param name="lineHeight">The height of each line of text.</param>
         /// <returns></returns>
         private static TextParagraphProperties CreateTextParagraphProperties(Typeface typeface, double fontSize,
             IBrush foreground, TextAlignment textAlignment, TextWrapping textWrapping, TextTrimming textTrimming,
-            ImmutableTextDecoration[] textDecorations)
+            TextDecorationCollection textDecorations, double lineHeight)
         {
-            var textRunStyle = new TextStyle(typeface, fontSize, foreground, textDecorations);
+            var textRunStyle = new GenericTextRunProperties(typeface, fontSize, textDecorations, foreground);
 
-            return new TextParagraphProperties(textRunStyle, textAlignment, textWrapping, textTrimming);
+            return new GenericTextParagraphProperties(textRunStyle, textAlignment, textWrapping, textTrimming,
+                lineHeight);
         }
 
         /// <summary>
@@ -170,14 +182,15 @@ namespace Avalonia.Media.TextFormatting
         /// <returns>The empty text line.</returns>
         private TextLine CreateEmptyTextLine(int startingIndex)
         {
-            var textFormat = _paragraphProperties.DefaultTextStyle.TextFormat;
+            var properties = _paragraphProperties.DefaultTextRunProperties;
 
-            var glyphRun = TextShaper.Current.ShapeText(s_empty, textFormat);
+            var glyphRun = TextShaper.Current.ShapeText(new ReadOnlySlice<char>(s_empty, startingIndex, 1),
+                properties.Typeface, properties.FontRenderingEmSize, properties.CultureInfo);
 
-            var textRuns = new[] { new ShapedTextRun(glyphRun, _paragraphProperties.DefaultTextStyle) };
+            var textRuns = new[] { new ShapedTextCharacters(glyphRun, _paragraphProperties.DefaultTextRunProperties) };
 
-            return new SimpleTextLine(new TextPointer(startingIndex, 0), textRuns,
-                TextLineMetrics.Create(textRuns, MaxWidth, _paragraphProperties.TextAlignment));
+            return new TextLineImpl(textRuns,
+                TextLineMetrics.Create(textRuns, new TextRange(startingIndex, 1), MaxWidth, _paragraphProperties));
         }
 
         /// <summary>
@@ -199,77 +212,38 @@ namespace Avalonia.Media.TextFormatting
 
                 double left = 0.0, right = 0.0, bottom = 0.0;
 
-                var lineBreaker = new LineBreakEnumerator(_text);
-
                 var currentPosition = 0;
 
+                var textSource = new FormattedTextSource(_text,
+                    _paragraphProperties.DefaultTextRunProperties, _textStyleOverrides);
+
+                TextLineBreak previousLineBreak = null;
+
                 while (currentPosition < _text.Length && (MaxLines == 0 || textLines.Count < MaxLines))
                 {
-                    int length;
+                    var textLine = TextFormatter.Current.FormatLine(textSource, currentPosition, MaxWidth,
+                        _paragraphProperties, previousLineBreak);
 
-                    if (lineBreaker.MoveNext())
-                    {
-                        if (!lineBreaker.Current.Required)
-                        {
-                            continue;
-                        }
+                    previousLineBreak = textLine.LineBreak;
 
-                        length = lineBreaker.Current.PositionWrap - currentPosition;
+                    textLines.Add(textLine);
 
-                        if (currentPosition + length < _text.Length)
-                        {
-                            //The line breaker isn't treating \n\r as a pair so we have to fix that here.
-                            if (_text[lineBreaker.Current.PositionMeasure] == '\n'
-                             && _text[lineBreaker.Current.PositionWrap] == '\r')
-                            {
-                                length++;
-                            }
-                        }
-                    }
-                    else
+                    UpdateBounds(textLine, ref left, ref right, ref bottom);
+
+                    if (!double.IsPositiveInfinity(MaxHeight) && bottom > MaxHeight)
                     {
-                        length = _text.Length - currentPosition;
+                        break;
                     }
 
-                    var remainingLength = length;
+                    currentPosition += textLine.TextRange.Length;
 
-                    while (remainingLength > 0 && (MaxLines == 0 || textLines.Count < MaxLines))
+                    if (currentPosition != _text.Length || textLine.LineBreak == null)
                     {
-                        var textSlice = _text.AsSlice(currentPosition, remainingLength);
-
-                        var textSource = new FormattedTextSource(textSlice, _paragraphProperties.DefaultTextStyle, _textStyleOverrides);
-
-                        var textLine = TextFormatter.Current.FormatLine(textSource, 0, MaxWidth, _paragraphProperties);
-
-                        UpdateBounds(textLine, ref left, ref right, ref bottom);
-
-                        textLines.Add(textLine);
-
-                        if (!double.IsPositiveInfinity(MaxHeight) && bottom + textLine.LineMetrics.Size.Height > MaxHeight)
-                        {
-                            currentPosition = _text.Length;
-                            break;
-                        }
-
-                        if (_paragraphProperties.TextTrimming != TextTrimming.None)
-                        {
-                            currentPosition += remainingLength;
-
-                            break;
-                        }
-
-                        remainingLength -= textLine.Text.Length;
-
-                        currentPosition += textLine.Text.Length;
+                        continue;
                     }
-                }
 
-                if (lineBreaker.Current.Required && currentPosition == _text.Length)
-                {
                     var emptyTextLine = CreateEmptyTextLine(currentPosition);
 
-                    UpdateBounds(emptyTextLine, ref left, ref right, ref bottom);
-
                     textLines.Add(emptyTextLine);
                 }
 
@@ -279,22 +253,27 @@ namespace Avalonia.Media.TextFormatting
             }
         }
 
-        private struct FormattedTextSource : ITextSource
+        private readonly struct FormattedTextSource : ITextSource
         {
             private readonly ReadOnlySlice<char> _text;
-            private readonly TextStyle _defaultStyle;
-            private readonly IReadOnlyList<TextStyleRun> _textStyleOverrides;
+            private readonly TextRunProperties _defaultProperties;
+            private readonly IReadOnlyList<ValueSpan<TextRunProperties>> _textModifier;
 
-            public FormattedTextSource(ReadOnlySlice<char> text, TextStyle defaultStyle,
-                IReadOnlyList<TextStyleRun> textStyleOverrides)
+            public FormattedTextSource(ReadOnlySlice<char> text, TextRunProperties defaultProperties,
+                IReadOnlyList<ValueSpan<TextRunProperties>> textModifier)
             {
                 _text = text;
-                _defaultStyle = defaultStyle;
-                _textStyleOverrides = textStyleOverrides;
+                _defaultProperties = defaultProperties;
+                _textModifier = textModifier;
             }
 
             public TextRun GetTextRun(int textSourceIndex)
             {
+                if (textSourceIndex > _text.End)
+                {
+                    return new TextEndOfLine();
+                }
+
                 var runText = _text.Skip(textSourceIndex);
 
                 if (runText.IsEmpty)
@@ -302,30 +281,29 @@ namespace Avalonia.Media.TextFormatting
                     return new TextEndOfLine();
                 }
 
-                var textStyleRun = CreateTextStyleRunWithOverride(runText, _defaultStyle, _textStyleOverrides);
+                var textStyleRun = CreateTextStyleRun(runText, _defaultProperties, _textModifier);
 
-                return new TextCharacters(runText.Take(textStyleRun.TextPointer.Length), textStyleRun.Style);
+                return new TextCharacters(runText.Take(textStyleRun.Length), textStyleRun.Value);
             }
 
             /// <summary>
-            /// Creates a text style run that has overrides applied. Only overrides with equal TextStyle.
-            /// If optimizeForShaping is <c>true</c> Foreground is ignored.
+            /// Creates a span of text run properties that has modifier applied.
             /// </summary>
-            /// <param name="text">The text to create the run for.</param>
-            /// <param name="defaultTextStyle">The default text style for segments that don't have an override.</param>
-            /// <param name="textStyleOverrides">The text style overrides.</param>
+            /// <param name="text">The text to create the properties for.</param>
+            /// <param name="defaultProperties">The default text properties.</param>
+            /// <param name="textModifier">The text properties modifier.</param>
             /// <returns>
             /// The created text style run.
             /// </returns>
-            private static TextStyleRun CreateTextStyleRunWithOverride(ReadOnlySlice<char> text,
-                TextStyle defaultTextStyle, IReadOnlyList<TextStyleRun> textStyleOverrides)
+            private static ValueSpan<TextRunProperties> CreateTextStyleRun(ReadOnlySlice<char> text,
+                TextRunProperties defaultProperties, IReadOnlyList<ValueSpan<TextRunProperties>> textModifier)
             {
-                if(textStyleOverrides == null || textStyleOverrides.Count == 0)
+                if (textModifier == null || textModifier.Count == 0)
                 {
-                    return new TextStyleRun(new TextPointer(text.Start, text.Length), defaultTextStyle);
+                    return new ValueSpan<TextRunProperties>(text.Start, text.Length, defaultProperties);
                 }
 
-                var currentTextStyle = defaultTextStyle;
+                var currentProperties = defaultProperties;
 
                 var hasOverride = false;
 
@@ -333,35 +311,34 @@ namespace Avalonia.Media.TextFormatting
 
                 var length = 0;
 
-                for (; i < textStyleOverrides.Count; i++)
+                for (; i < textModifier.Count; i++)
                 {
-                    var styleOverride = textStyleOverrides[i];
+                    var propertiesOverride = textModifier[i];
 
-                    var textPointer = styleOverride.TextPointer;
+                    var textRange = new TextRange(propertiesOverride.Start, propertiesOverride.Length);
 
-                    if (textPointer.End < text.Start)
+                    if (textRange.End < text.Start)
                     {
                         continue;
                     }
 
-                    if (textPointer.Start > text.End)
+                    if (textRange.Start > text.End)
                     {
                         length = text.Length;
                         break;
                     }
 
-                    if (textPointer.Start > text.Start)
+                    if (textRange.Start > text.Start)
                     {
-                        if (styleOverride.Style.TextFormat != currentTextStyle.TextFormat ||
-                            !currentTextStyle.Foreground.Equals(styleOverride.Style.Foreground))
+                        if (propertiesOverride.Value != currentProperties)
                         {
-                            length = Math.Min(Math.Abs(textPointer.Start - text.Start), text.Length);
+                            length = Math.Min(Math.Abs(textRange.Start - text.Start), text.Length);
 
                             break;
                         }
                     }
 
-                    length += Math.Min(text.Length - length, textPointer.Length);
+                    length += Math.Min(text.Length - length, textRange.Length);
 
                     if (hasOverride)
                     {
@@ -370,13 +347,12 @@ namespace Avalonia.Media.TextFormatting
 
                     hasOverride = true;
 
-                    currentTextStyle = styleOverride.Style;
+                    currentProperties = propertiesOverride.Value;
                 }
 
-                if (length < text.Length && i == textStyleOverrides.Count)
+                if (length < text.Length && i == textModifier.Count)
                 {
-                    if (currentTextStyle.Foreground.Equals(defaultTextStyle.Foreground) &&
-                        currentTextStyle.TextFormat == defaultTextStyle.TextFormat)
+                    if (currentProperties == defaultProperties)
                     {
                         length = text.Length;
                     }
@@ -387,7 +363,7 @@ namespace Avalonia.Media.TextFormatting
                     text = text.Take(length);
                 }
 
-                return new TextStyleRun(new TextPointer(text.Start, length), currentTextStyle);
+                return new ValueSpan<TextRunProperties>(text.Start, length, currentProperties);
             }
         }
     }

+ 12 - 5
src/Avalonia.Visuals/Media/TextFormatting/TextLine.cs

@@ -1,5 +1,4 @@
 using System.Collections.Generic;
-using Avalonia.Platform;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -9,12 +8,12 @@ namespace Avalonia.Media.TextFormatting
     public abstract class TextLine
     {
         /// <summary>
-        /// Gets the text.
+        /// Gets the text range that is covered by the line.
         /// </summary>
         /// <value>
-        /// The text pointer.
+        /// The text range that is covered by the line.
         /// </value>
-        public abstract TextPointer Text { get; }
+        public abstract TextRange TextRange { get; }
 
         /// <summary>
         /// Gets the text runs.
@@ -32,12 +31,20 @@ namespace Avalonia.Media.TextFormatting
         /// </value>
         public abstract TextLineMetrics LineMetrics { get; }
 
+        /// <summary>
+        /// Gets the state of the line when broken by line breaking process.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="LineBreak"/> value that represents the line break.
+        /// </returns>
+        public abstract TextLineBreak LineBreak { get; }
+
         /// <summary>
         /// Draws the <see cref="TextLine"/> at the given origin.
         /// </summary>
         /// <param name="drawingContext">The drawing context.</param>
         /// <param name="origin">The origin.</param>
-        public abstract void Draw(IDrawingContextImpl drawingContext, Point origin);
+        public abstract void Draw(DrawingContext drawingContext, Point origin);
 
         /// <summary>
         /// Client to get the character hit corresponding to the specified 

+ 17 - 0
src/Avalonia.Visuals/Media/TextFormatting/TextLineBreak.cs

@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Media.TextFormatting
+{
+    public class TextLineBreak
+    {
+        public TextLineBreak(IReadOnlyList<ShapedTextCharacters> remainingCharacters)
+        {
+            RemainingCharacters = remainingCharacters;
+        }
+
+        /// <summary>
+        /// Get the remaining shaped characters that were split up by the <see cref="TextFormatter"/> during the formatting process.
+        /// </summary>
+        public IReadOnlyList<ShapedTextCharacters> RemainingCharacters { get; }
+    }
+}

+ 235 - 0
src/Avalonia.Visuals/Media/TextFormatting/TextLineImpl.cs

@@ -0,0 +1,235 @@
+using System.Collections.Generic;
+
+namespace Avalonia.Media.TextFormatting
+{
+    internal class TextLineImpl : TextLine
+    {
+        private readonly IReadOnlyList<ShapedTextCharacters> _textRuns;
+
+        public TextLineImpl(IReadOnlyList<ShapedTextCharacters> textRuns, TextLineMetrics lineMetrics,
+            TextLineBreak lineBreak = null)
+        {
+            _textRuns = textRuns;
+            LineMetrics = lineMetrics;
+            LineBreak = lineBreak;
+        }
+
+        /// <inheritdoc/>
+        public override TextRange TextRange => LineMetrics.TextRange;
+
+        /// <inheritdoc/>
+        public override IReadOnlyList<TextRun> TextRuns => _textRuns;
+
+        /// <inheritdoc/>
+        public override TextLineMetrics LineMetrics { get; }
+
+        /// <inheritdoc/>
+        public override TextLineBreak LineBreak { get; }
+
+        /// <inheritdoc/>
+        public override void Draw(DrawingContext drawingContext, Point origin)
+        {
+            var currentX = origin.X;
+
+            foreach (var textRun in _textRuns)
+            {
+                var baselineOrigin = new Point(currentX + LineMetrics.BaselineOrigin.X,
+                    origin.Y + LineMetrics.BaselineOrigin.Y);
+
+                textRun.Draw(drawingContext, baselineOrigin);
+
+                currentX += textRun.Bounds.Width;
+            }
+        }
+
+        /// <inheritdoc/>
+        public override CharacterHit GetCharacterHitFromDistance(double distance)
+        {
+            if (distance < 0)
+            {
+                // hit happens before the line, return the first position
+                return new CharacterHit(TextRange.Start);
+            }
+
+            // process hit that happens within the line
+            var characterHit = new CharacterHit();
+
+            foreach (var run in _textRuns)
+            {
+                characterHit = run.GlyphRun.GetCharacterHitFromDistance(distance, out _);
+
+                if (distance <= run.Bounds.Width)
+                {
+                    break;
+                }
+
+                distance -= run.Bounds.Width;
+            }
+
+            return characterHit;
+        }
+
+        /// <inheritdoc/>
+        public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
+        {
+            return DistanceFromCodepointIndex(characterHit.FirstCharacterIndex + (characterHit.TrailingLength != 0 ? 1 : 0));
+        }
+
+        /// <inheritdoc/>
+        public override CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit)
+        {
+            if (TryFindNextCharacterHit(characterHit, out var nextCharacterHit))
+            {
+                return nextCharacterHit;
+            }
+
+            return new CharacterHit(TextRange.End); // Can't move, we're after the last character
+        }
+
+        /// <inheritdoc/>
+        public override CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit)
+        {
+            if (TryFindPreviousCharacterHit(characterHit, out var previousCharacterHit))
+            {
+                return previousCharacterHit;
+            }
+
+            return new CharacterHit(TextRange.Start); // Can't move, we're before the first character
+        }
+
+        /// <inheritdoc/>
+        public override CharacterHit GetBackspaceCaretCharacterHit(CharacterHit characterHit)
+        {
+            // same operation as move-to-previous
+            return GetPreviousCaretCharacterHit(characterHit);
+        }
+
+        /// <summary>
+        /// Get distance from line start to the specified codepoint index.
+        /// </summary>
+        private double DistanceFromCodepointIndex(int codepointIndex)
+        {
+            var currentDistance = 0.0;
+
+            foreach (var textRun in _textRuns)
+            {
+                if (codepointIndex > textRun.Text.End)
+                {
+                    currentDistance += textRun.Bounds.Width;
+
+                    continue;
+                }
+
+                return currentDistance + textRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(codepointIndex));
+            }
+
+            return currentDistance;
+        }
+
+        /// <summary>
+        /// Tries to find the next character hit.
+        /// </summary>
+        /// <param name="characterHit">The current character hit.</param>
+        /// <param name="nextCharacterHit">The next character hit.</param>
+        /// <returns></returns>
+        private bool TryFindNextCharacterHit(CharacterHit characterHit, out CharacterHit nextCharacterHit)
+        {
+            nextCharacterHit = characterHit;
+
+            var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
+
+            if (codepointIndex >= TextRange.Start + TextRange.Length)
+            {
+                return false; // Cannot go forward anymore
+            }
+
+            var runIndex = GetRunIndexAtCodepointIndex(codepointIndex);
+
+            while (runIndex < TextRuns.Count)
+            {
+                var run = _textRuns[runIndex];
+
+                nextCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);
+
+                if (codepointIndex <= nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength)
+                {
+                    return true;
+                }
+
+                runIndex++;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Tries to find the previous character hit.
+        /// </summary>
+        /// <param name="characterHit">The current character hit.</param>
+        /// <param name="previousCharacterHit">The previous character hit.</param>
+        /// <returns></returns>
+        private bool TryFindPreviousCharacterHit(CharacterHit characterHit, out CharacterHit previousCharacterHit)
+        {
+            previousCharacterHit = characterHit;
+
+            var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;
+
+            if (codepointIndex < TextRange.Start)
+            {
+                return false; // Cannot go backward anymore.
+            }
+
+            var runIndex = GetRunIndexAtCodepointIndex(codepointIndex);
+
+            while (runIndex >= 0)
+            {
+                var run = _textRuns[runIndex];
+
+                previousCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);
+
+                if (previousCharacterHit.FirstCharacterIndex < codepointIndex)
+                {
+                    return true;
+                }
+
+                runIndex--;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// Gets the run index of the specified codepoint index.
+        /// </summary>
+        /// <param name="codepointIndex">The codepoint index.</param>
+        /// <returns>The text run index.</returns>
+        private int GetRunIndexAtCodepointIndex(int codepointIndex)
+        {
+            if (codepointIndex >= TextRange.End)
+            {
+                return _textRuns.Count - 1;
+            }
+
+            if (codepointIndex <= 0)
+            {
+                return 0;
+            }
+
+            var runIndex = 0;
+
+            while (runIndex < _textRuns.Count)
+            {
+                var run = _textRuns[runIndex];
+
+                if (run.Text.End > codepointIndex)
+                {
+                    return runIndex;
+                }
+
+                runIndex++;
+            }
+
+            return runIndex;
+        }
+    }
+}

+ 31 - 38
src/Avalonia.Visuals/Media/TextFormatting/TextLineMetrics.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -8,38 +9,20 @@ namespace Avalonia.Media.TextFormatting
     /// </summary>
     public readonly struct TextLineMetrics
     {
-        public TextLineMetrics(double width, double xOrigin, double ascent, double descent, double lineGap)
+        public TextLineMetrics(Size size, Point baselineOrigin, TextRange textRange)
         {
-            Ascent = ascent;
-            Descent = descent;
-            LineGap = lineGap;
-            Size = new Size(width, descent - ascent + lineGap);
-            BaselineOrigin = new Point(xOrigin, -ascent);
+            Size = size;
+            BaselineOrigin = baselineOrigin;
+            TextRange = textRange;
         }
 
         /// <summary>
-        /// Gets the overall recommended distance above the baseline.
+        /// Gets the text range that is covered by the text line.
         /// </summary>
         /// <value>
-        /// The ascent.
+        /// The text range that is covered by the text line.
         /// </value>
-        public double Ascent { get; }
-
-        /// <summary>
-        /// Gets the overall recommended distance under the baseline.
-        /// </summary>
-        /// <value>
-        /// The descent.
-        /// </value>
-        public double Descent { get; }
-
-        /// <summary>
-        /// Gets the overall recommended additional space between two lines of text.
-        /// </summary>
-        /// <value>
-        /// The leading.
-        /// </value>
-        public double LineGap { get; }
+        public TextRange TextRange { get; }
 
         /// <summary>
         /// Gets the size of the text line.
@@ -61,10 +44,12 @@ namespace Avalonia.Media.TextFormatting
         /// Creates the text line metrics.
         /// </summary>
         /// <param name="textRuns">The text runs.</param>
+        /// <param name="textRange">The text range that is covered by the text line.</param>
         /// <param name="paragraphWidth">The paragraph width.</param>
-        /// <param name="textAlignment">The text alignment.</param>
+        /// <param name="paragraphProperties">The text alignment.</param>
         /// <returns></returns>
-        public static TextLineMetrics Create(IEnumerable<TextRun> textRuns, double paragraphWidth, TextAlignment textAlignment)
+        public static TextLineMetrics Create(IEnumerable<TextRun> textRuns, TextRange textRange, double paragraphWidth,
+            TextParagraphProperties paragraphProperties)
         {
             var lineWidth = 0.0;
             var ascent = 0.0;
@@ -73,31 +58,39 @@ namespace Avalonia.Media.TextFormatting
 
             foreach (var textRun in textRuns)
             {
-                var shapedRun = (ShapedTextRun)textRun;
+                var shapedRun = (ShapedTextCharacters)textRun;
 
-                lineWidth += shapedRun.Bounds.Width;
+                var fontMetrics =
+                    new FontMetrics(shapedRun.Properties.Typeface, shapedRun.Properties.FontRenderingEmSize);
 
-                var textFormat = textRun.Style.TextFormat;
+                lineWidth += shapedRun.Bounds.Width;
 
-                if (ascent > textRun.Style.TextFormat.FontMetrics.Ascent)
+                if (ascent > fontMetrics.Ascent)
                 {
-                    ascent = textFormat.FontMetrics.Ascent;
+                    ascent = fontMetrics.Ascent;
                 }
 
-                if (descent < textFormat.FontMetrics.Descent)
+                if (descent < fontMetrics.Descent)
                 {
-                    descent = textFormat.FontMetrics.Descent;
+                    descent = fontMetrics.Descent;
                 }
 
-                if (lineGap < textFormat.FontMetrics.LineGap)
+                if (lineGap < fontMetrics.LineGap)
                 {
-                    lineGap = textFormat.FontMetrics.LineGap;
+                    lineGap = fontMetrics.LineGap;
                 }
             }
 
-            var xOrigin = TextLine.GetParagraphOffsetX(lineWidth, paragraphWidth, textAlignment);
+            var xOrigin = TextLine.GetParagraphOffsetX(lineWidth, paragraphWidth, paragraphProperties.TextAlignment);
+
+            var baselineOrigin = new Point(xOrigin, -ascent);
+
+            var size = new Size(lineWidth,
+                double.IsNaN(paragraphProperties.LineHeight) || MathUtilities.IsZero(paragraphProperties.LineHeight) ?
+                    descent - ascent + lineGap :
+                    paragraphProperties.LineHeight);
 
-            return new TextLineMetrics(lineWidth, xOrigin, ascent, descent, lineGap);
+            return new TextLineMetrics(size, baselineOrigin, textRange);
         }
     }
 }

+ 16 - 17
src/Avalonia.Visuals/Media/TextFormatting/TextParagraphProperties.cs

@@ -3,38 +3,37 @@
     /// <summary>
     /// Provides a set of properties that are used during the paragraph layout.
     /// </summary>
-    public readonly struct TextParagraphProperties
+    public abstract class TextParagraphProperties
     {
-        public TextParagraphProperties(
-            TextStyle defaultTextStyle,
-            TextAlignment textAlignment = TextAlignment.Left,
-            TextWrapping textWrapping = TextWrapping.NoWrap,
-            TextTrimming textTrimming = TextTrimming.None)
-        {
-            DefaultTextStyle = defaultTextStyle;
-            TextAlignment = textAlignment;
-            TextWrapping = textWrapping;
-            TextTrimming = textTrimming;
-        }
+        /// <summary>
+        /// Gets the text alignment.
+        /// </summary>
+        public abstract TextAlignment TextAlignment { get; }
 
         /// <summary>
         /// Gets the default text style.
         /// </summary>
-        public TextStyle DefaultTextStyle { get; }
+        public abstract TextRunProperties DefaultTextRunProperties { get; }
 
         /// <summary>
-        /// Gets the text alignment.
+        /// If not null, text decorations to apply to all runs in the line. This is in addition
+        /// to any text decorations specified by the TextRunProperties for individual text runs.
         /// </summary>
-        public TextAlignment TextAlignment { get; }
+        public virtual TextDecorationCollection TextDecorations => null;
 
         /// <summary>
         /// Gets the text wrapping.
         /// </summary>
-        public TextWrapping TextWrapping { get; }
+        public abstract TextWrapping TextWrapping { get; }
 
         /// <summary>
         /// Gets the text trimming.
         /// </summary>
-        public TextTrimming TextTrimming { get; }
+        public abstract TextTrimming TextTrimming { get; }
+
+        /// <summary>
+        /// Paragraph's line height
+        /// </summary>
+        public abstract double LineHeight { get; }
     }
 }

+ 8 - 8
src/Avalonia.Visuals/Media/TextFormatting/TextPointer.cs → src/Avalonia.Visuals/Media/TextFormatting/TextRange.cs

@@ -5,9 +5,9 @@ namespace Avalonia.Media.TextFormatting
     /// <summary>
     /// References a portion of a text buffer.
     /// </summary>
-    public readonly struct TextPointer
+    public readonly struct TextRange
     {
-        public TextPointer(int start, int length)
+        public TextRange(int start, int length)
         {
             Start = start;
             Length = length;
@@ -41,30 +41,30 @@ namespace Avalonia.Media.TextFormatting
         /// Returns a specified number of contiguous elements from the start of the slice.
         /// </summary>
         /// <param name="length">The number of elements to return.</param>
-        /// <returns>A <see cref="TextPointer"/> that contains the specified number of elements from the start of this slice.</returns>
-        public TextPointer Take(int length)
+        /// <returns>A <see cref="TextRange"/> that contains the specified number of elements from the start of this slice.</returns>
+        public TextRange Take(int length)
         {
             if (length > Length)
             {
                 throw new ArgumentOutOfRangeException(nameof(length));
             }
 
-            return new TextPointer(Start, length);
+            return new TextRange(Start, length);
         }
 
         /// <summary>
         /// Bypasses a specified number of elements in the slice and then returns the remaining elements.
         /// </summary>
         /// <param name="length">The number of elements to skip before returning the remaining elements.</param>
-        /// <returns>A <see cref="TextPointer"/> that contains the elements that occur after the specified index in this slice.</returns>
-        public TextPointer Skip(int length)
+        /// <returns>A <see cref="TextRange"/> that contains the elements that occur after the specified index in this slice.</returns>
+        public TextRange Skip(int length)
         {
             if (length > Length)
             {
                 throw new ArgumentOutOfRangeException(nameof(length));
             }
 
-            return new TextPointer(Start + length, Length - length);
+            return new TextRange(Start + length, Length - length);
         }
     }
 }

+ 12 - 5
src/Avalonia.Visuals/Media/TextFormatting/TextRun.cs

@@ -1,5 +1,5 @@
 using System.Diagnostics;
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -9,15 +9,22 @@ namespace Avalonia.Media.TextFormatting
     [DebuggerTypeProxy(typeof(TextRunDebuggerProxy))]
     public abstract class TextRun
     {
+        public static readonly int DefaultTextSourceLength = 1;
+
+        /// <summary>
+        ///  Gets the text source length.
+        /// </summary>
+        public virtual int TextSourceLength => DefaultTextSourceLength;
+
         /// <summary>
         /// Gets the text run's text.
         /// </summary>
-        public ReadOnlySlice<char> Text { get; protected set; }
+        public virtual ReadOnlySlice<char> Text => default;
 
         /// <summary>
-        /// Gets the text run's style.
+        /// A set of properties shared by every characters in the run
         /// </summary>
-        public TextStyle Style { get; protected set; }
+        public virtual TextRunProperties Properties => null;
 
         private class TextRunDebuggerProxy
         {
@@ -42,7 +49,7 @@ namespace Avalonia.Media.TextFormatting
                 }
             }
 
-            public TextStyle Style => _textRun.Style;
+            public TextRunProperties Properties => _textRun.Properties;
         }
     }
 }

+ 90 - 0
src/Avalonia.Visuals/Media/TextFormatting/TextRunProperties.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Globalization;
+
+namespace Avalonia.Media.TextFormatting
+{
+    /// <summary>
+    /// Properties that can change from one run to the next, such as typeface or foreground brush.
+    /// </summary>
+    /// <remarks>
+    /// The client provides a concrete implementation of this abstract run properties class. This
+    /// allows client to implement their run properties the way that fits with their run formatting
+    /// store.
+    /// </remarks>
+    public abstract class TextRunProperties : IEquatable<TextRunProperties>
+    {
+        /// <summary>
+        /// Run typeface
+        /// </summary>
+        public abstract Typeface Typeface { get; }
+
+        /// <summary>
+        /// Em size of font used to format and display text
+        /// </summary>
+        public abstract double FontRenderingEmSize { get; }
+
+        ///<summary>
+        /// Run TextDecorations. 
+        ///</summary>
+        public abstract TextDecorationCollection TextDecorations { get; }
+
+        /// <summary>
+        /// Brush used to fill text.
+        /// </summary>
+        public abstract IBrush ForegroundBrush { get; }
+
+        /// <summary>
+        /// Brush used to paint background of run.
+        /// </summary>
+        public abstract IBrush BackgroundBrush { get; }
+
+        /// <summary>
+        /// Run text culture.
+        /// </summary>
+        public abstract CultureInfo CultureInfo { get; }
+
+        public bool Equals(TextRunProperties other)
+        {
+            if (ReferenceEquals(null, other))
+                return false;
+            if (ReferenceEquals(this, other))
+                return true;
+
+            return Typeface.Equals(other.Typeface) &&
+                   FontRenderingEmSize.Equals(other.FontRenderingEmSize)
+                   && Equals(TextDecorations, other.TextDecorations) &&
+                   Equals(ForegroundBrush, other.ForegroundBrush) &&
+                   Equals(BackgroundBrush, other.BackgroundBrush) &&
+                   Equals(CultureInfo, other.CultureInfo);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return ReferenceEquals(this, obj) || obj is TextRunProperties other && Equals(other);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                var hashCode = (Typeface != null ? Typeface.GetHashCode() : 0);
+                hashCode = (hashCode * 397) ^ FontRenderingEmSize.GetHashCode();
+                hashCode = (hashCode * 397) ^ (TextDecorations != null ? TextDecorations.GetHashCode() : 0);
+                hashCode = (hashCode * 397) ^ (ForegroundBrush != null ? ForegroundBrush.GetHashCode() : 0);
+                hashCode = (hashCode * 397) ^ (BackgroundBrush != null ? BackgroundBrush.GetHashCode() : 0);
+                hashCode = (hashCode * 397) ^ (CultureInfo != null ? CultureInfo.GetHashCode() : 0);
+                return hashCode;
+            }
+        }
+
+        public static bool operator ==(TextRunProperties left, TextRunProperties right)
+        {
+            return Equals(left, right);
+        }
+
+        public static bool operator !=(TextRunProperties left, TextRunProperties right)
+        {
+            return !Equals(left, right);
+        }
+    }
+}

+ 5 - 3
src/Avalonia.Visuals/Media/TextFormatting/TextShaper.cs

@@ -1,6 +1,7 @@
 using System;
+using System.Globalization;
 using Avalonia.Platform;
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting
 {
@@ -44,9 +45,10 @@ namespace Avalonia.Media.TextFormatting
         }
 
         /// <inheritdoc cref="ITextShaperImpl.ShapeText"/>
-        public GlyphRun ShapeText(ReadOnlySlice<char> text, TextFormat textFormat)
+        public GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize,
+            CultureInfo culture)
         {
-            return _platformImpl.ShapeText(text, textFormat);
+            return _platformImpl.ShapeText(text, typeface, fontRenderingEmSize, culture);
         }
     }
 }

+ 0 - 39
src/Avalonia.Visuals/Media/TextFormatting/TextStyle.cs

@@ -1,39 +0,0 @@
-using Avalonia.Media.Immutable;
-
-namespace Avalonia.Media.TextFormatting
-{
-    /// <summary>
-    /// Unique text formatting properties that effect the styling of a text.
-    /// </summary>
-    public readonly struct TextStyle
-    {
-        public TextStyle(Typeface typeface, double fontRenderingEmSize = 12, IBrush foreground = null,
-            ImmutableTextDecoration[] textDecorations = null)
-            : this(new TextFormat(typeface, fontRenderingEmSize), foreground, textDecorations)
-        {
-        }
-
-        public TextStyle(TextFormat textFormat, IBrush foreground = null,
-            ImmutableTextDecoration[] textDecorations = null)
-        {
-            TextFormat = textFormat;
-            Foreground = foreground;
-            TextDecorations = textDecorations;
-        }
-
-        /// <summary>
-        /// Gets the text format.
-        /// </summary>
-        public TextFormat TextFormat { get; }
-
-        /// <summary>
-        /// Gets the foreground.
-        /// </summary>
-        public IBrush Foreground { get; }
-
-        /// <summary>
-        /// Gets the text decorations.
-        /// </summary>
-        public ImmutableTextDecoration[] TextDecorations { get; }
-    }
-}

+ 0 - 24
src/Avalonia.Visuals/Media/TextFormatting/TextStyleRun.cs

@@ -1,24 +0,0 @@
-namespace Avalonia.Media.TextFormatting
-{
-    /// <summary>
-    /// Represents a text run's style and is used during the layout process of the <see cref="TextFormatter"/>.
-    /// </summary>
-    public readonly struct TextStyleRun
-    {
-        public TextStyleRun(TextPointer textPointer, TextStyle style)
-        {
-            TextPointer = textPointer;
-            Style = style;
-        }
-
-        /// <summary>
-        /// Gets the text pointer.
-        /// </summary>
-        public TextPointer TextPointer { get; }
-
-        /// <summary>
-        /// Gets the text style.
-        /// </summary>
-        public TextStyle Style { get; }
-    }
-}

+ 1 - 1
src/Avalonia.Visuals/Media/TextFormatting/Unicode/Codepoint.cs

@@ -1,4 +1,4 @@
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting.Unicode
 {

+ 1 - 1
src/Avalonia.Visuals/Media/TextFormatting/Unicode/CodepointEnumerator.cs

@@ -1,4 +1,4 @@
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting.Unicode
 {

+ 1 - 1
src/Avalonia.Visuals/Media/TextFormatting/Unicode/Grapheme.cs

@@ -1,4 +1,4 @@
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting.Unicode
 {

+ 1 - 1
src/Avalonia.Visuals/Media/TextFormatting/Unicode/GraphemeEnumerator.cs

@@ -4,7 +4,7 @@
 // Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
 
 using System.Runtime.InteropServices;
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting.Unicode
 {

+ 1 - 1
src/Avalonia.Visuals/Media/TextFormatting/Unicode/LineBreakEnumerator.cs

@@ -16,7 +16,7 @@
 // Ported from: https://github.com/foliojs/linebreak
 // Copied from: https://github.com/toptensoftware/RichTextKit
 
-using Avalonia.Utility;
+using Avalonia.Utilities;
 
 namespace Avalonia.Media.TextFormatting.Unicode
 {

+ 8 - 1
src/Avalonia.Visuals/Media/TextWrapping.cs

@@ -5,6 +5,13 @@ namespace Avalonia.Media
     /// </summary>
     public enum TextWrapping
     {
+        /// <summary>
+        /// Line-breaking occurs if the line overflows the available block width.
+        /// However, a line may overflow the block width if the line breaking algorithm
+        /// cannot determine a break opportunity, as in the case of a very long word.
+        /// </summary>
+        WrapWithOverflow,
+
         /// <summary>
         /// Text should not wrap.
         /// </summary>
@@ -15,4 +22,4 @@ namespace Avalonia.Media
         /// </summary>
         Wrap
     }
-}
+}

+ 6 - 6
src/Avalonia.Visuals/Media/Typeface.cs

@@ -16,11 +16,11 @@ namespace Avalonia.Media
         /// Initializes a new instance of the <see cref="Typeface"/> class.
         /// </summary>
         /// <param name="fontFamily">The font family.</param>
-        /// <param name="weight">The font weight.</param>
         /// <param name="style">The font style.</param>
+        /// <param name="weight">The font weight.</param>
         public Typeface([NotNull]FontFamily fontFamily,
-            FontWeight weight = FontWeight.Normal,
-            FontStyle style = FontStyle.Normal)
+            FontStyle style = FontStyle.Normal,
+            FontWeight weight = FontWeight.Normal)
         {
             if (weight <= 0)
             {
@@ -39,9 +39,9 @@ namespace Avalonia.Media
         /// <param name="style">The font style.</param>
         /// <param name="weight">The font weight.</param>
         public Typeface(string fontFamilyName,
-            FontWeight weight = FontWeight.Normal,
-            FontStyle style = FontStyle.Normal)
-            : this(new FontFamily(fontFamilyName), weight, style)
+            FontStyle style = FontStyle.Normal,
+            FontWeight weight = FontWeight.Normal)
+            : this(new FontFamily(fontFamilyName), style, weight)
         {
         }
 

+ 7 - 5
src/Avalonia.Visuals/Platform/ITextShaperImpl.cs

@@ -1,6 +1,6 @@
-using Avalonia.Media;
-using Avalonia.Media.TextFormatting;
-using Avalonia.Utility;
+using System.Globalization;
+using Avalonia.Media;
+using Avalonia.Utilities;
 
 namespace Avalonia.Platform
 {
@@ -13,8 +13,10 @@ namespace Avalonia.Platform
         /// Shapes the specified region within the text and returns a resulting glyph run.
         /// </summary>
         /// <param name="text">The text.</param>
-        /// <param name="textFormat">The text format.</param>
+        /// <param name="typeface">The typeface.</param>
+        /// <param name="fontRenderingEmSize">The font rendering em size.</param>
+        /// <param name="culture">The culture.</param>
         /// <returns>A shaped glyph run.</returns>
-        GlyphRun ShapeText(ReadOnlySlice<char> text, TextFormat textFormat);
+        GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture);
     }
 }

+ 2 - 3
src/Avalonia.Visuals/Utility/ReadOnlySlice.cs → src/Avalonia.Visuals/Utilities/ReadOnlySlice.cs

@@ -2,9 +2,8 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
-using Avalonia.Utilities;
 
-namespace Avalonia.Utility
+namespace Avalonia.Utilities
 {
     /// <summary>
     ///     ReadOnlySlice enables the ability to work with a sequence within a region of memory and retains the position in within that region.
@@ -47,7 +46,7 @@ namespace Avalonia.Utility
         public int Length { get; }
 
         /// <summary>
-        ///     Gets a value that indicates whether this instance of <see cref="ReadOnlySpan{T}"/> is Empty.
+        ///     Gets a value that indicates whether this instance of <see cref="ReadOnlySlice{T}"/> is Empty.
         /// </summary>
         public bool IsEmpty => Length == 0;
 

+ 30 - 0
src/Avalonia.Visuals/Utilities/ValueSpan.cs

@@ -0,0 +1,30 @@
+namespace Avalonia.Utilities
+{
+    /// <summary>
+    /// Pairing of value and positions sharing that value.
+    /// </summary>
+    public readonly struct ValueSpan<T>
+    {
+        public ValueSpan(int start, int length, T value)
+        {
+            Start = start;
+            Length = length;
+            Value = value;
+        }
+
+        /// <summary>
+        /// Get's the start of the span.
+        /// </summary>
+        public int Start { get; }
+
+        /// <summary>
+        /// Get's the length of the span.
+        /// </summary>
+        public int Length { get; }
+
+        /// <summary>
+        /// Get's the value of the span.
+        /// </summary>
+        public T Value { get; }
+    }
+}

+ 3 - 3
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
-    <DefineConstants>PCL;NETSTANDARD;NETSTANDARD2_0;HAS_TYPE_CONVERTER;HAS_CUSTOM_ATTRIBUTE_PROVIDER;XAMLIL_INTERNAL</DefineConstants>
+    <DefineConstants>PCL;NETSTANDARD;NETSTANDARD2_0;HAS_TYPE_CONVERTER;HAS_CUSTOM_ATTRIBUTE_PROVIDER;XAMLX_INTERNAL</DefineConstants>
     <UseCecil>false</UseCecil>
     <DefineConstants Condition="$(UseCecil) == true">$(DefineConstants);RUNTIME_XAML_CECIL</DefineConstants>
     <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
@@ -77,8 +77,8 @@
         <Compile Include="XamlIl\Runtime\IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs" />
         <Compile Include="XamlIl\Runtime\XamlIlRuntimeHelpers.cs" />
         <Compile Include="XamlLoadException.cs" />
-        <Compile Include="XamlIl\xamlil.github\src\XamlIl\**\*.cs" />
-        <Compile Condition="$(UseCecil) == true" Include="XamlIl\xamlil.github\src\XamlIl.Cecil\**\*.cs" />
+        <Compile Include="XamlIl\xamlil.github\src\XamlX\**\*.cs" />
+        <Compile Condition="$(UseCecil) == true" Include="XamlIl\xamlil.github\src\XamlX.Il.Cecil\**\*.cs" />
         <Compile Remove="XamlIl\xamlil.github\**\obj\**\*.cs" />
         <Compile Include="..\Avalonia.Markup\Markup\Parsers\SelectorGrammar.cs" />
         <Compile Include="..\Avalonia.Markup\Markup\Parsers\BindingExpressionGrammar.cs" />

+ 21 - 13
src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs

@@ -10,12 +10,15 @@ using System.Runtime.InteropServices;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
 using Avalonia.Markup.Xaml.XamlIl.Runtime;
 using Avalonia.Platform;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+using XamlX.IL;
+using XamlX.Emit;
 #if RUNTIME_XAML_CECIL
 using TypeAttributes = Mono.Cecil.TypeAttributes;
 using Mono.Cecil;
-using XamlIl.Ast;
+using XamlX.Ast;
+using XamlX.IL.Cecil;
 #endif
 namespace Avalonia.Markup.Xaml.XamlIl
 {
@@ -24,9 +27,10 @@ namespace Avalonia.Markup.Xaml.XamlIl
 #if !RUNTIME_XAML_CECIL
         private static SreTypeSystem _sreTypeSystem;
         private static ModuleBuilder _sreBuilder;
-        private static IXamlIlType _sreContextType; 
-        private static XamlIlLanguageTypeMappings _sreMappings;
-        private static XamlIlXmlnsMappings _sreXmlns;
+        private static IXamlType _sreContextType; 
+        private static XamlLanguageTypeMappings _sreMappings;
+        private static XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> _sreEmitMappings;
+        private static XamlXmlnsMappings _sreXmlns;
         private static AssemblyBuilder _sreAsm;
         private static bool _sreCanSave;
 
@@ -82,13 +86,14 @@ namespace Avalonia.Markup.Xaml.XamlIl
             }
 
             if (_sreMappings == null)
-                _sreMappings = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
+                (_sreMappings, _sreEmitMappings) = AvaloniaXamlIlLanguage.Configure(_sreTypeSystem);
             if (_sreXmlns == null)
-                _sreXmlns = XamlIlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
+                _sreXmlns = XamlXmlnsMappings.Resolve(_sreTypeSystem, _sreMappings);
             if (_sreContextType == null)
-                _sreContextType = XamlIlContextDefinition.GenerateContextClass(
+                _sreContextType = XamlILContextDefinition.GenerateContextClass(
                     _sreTypeSystem.CreateTypeBuilder(
-                        _sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings);
+                        _sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings,
+                        _sreEmitMappings);
         }
 
 
@@ -122,10 +127,11 @@ namespace Avalonia.Markup.Xaml.XamlIl
                 _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter,
                 new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)),
                 new XamlIlPropertyInfoAccessorFactoryEmitter(_sreTypeSystem.CreateTypeBuilder(indexerClosureType))), 
+                _sreEmitMappings,
                 _sreContextType) { EnableIlVerification = true };
             
 
-            IXamlIlType overrideType = null;
+            IXamlType overrideType = null;
             if (rootInstance != null)
             {
                 overrideType = _sreTypeSystem.GetType(rootInstance.GetType());
@@ -209,6 +215,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
         private static string _cecilEmitDir;
         private static CecilTypeSystem _cecilTypeSystem;
         private static XamlIlLanguageTypeMappings _cecilMappings;
+        private static XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> _cecilEmitMappings;
         private static XamlIlXmlnsMappings _cecilXmlns;
         private static bool _cecilInitialized;
 
@@ -221,7 +228,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
             Directory.CreateDirectory(_cecilEmitDir);
             var refs = new[] {path}.Concat(File.ReadAllLines(path + ".refs"));
             _cecilTypeSystem = new CecilTypeSystem(refs);
-            _cecilMappings = AvaloniaXamlIlLanguage.Configure(_cecilTypeSystem);
+            (_cecilMappings, _cecilEmitMappings) = AvaloniaXamlIlLanguage.Configure(_cecilTypeSystem);
             _cecilXmlns = XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings);
             _cecilInitialized = true;
         }
@@ -232,7 +239,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
             if (uri == null)
                 throw new InvalidOperationException("Please, go away");
             InitializeCecil();
-                        IXamlIlType overrideType = null;
+                        IXamlType overrideType = null;
             if (rootInstance != null)
             {
                 overrideType = _cecilTypeSystem.GetType(rootInstance.GetType().FullName);
@@ -267,6 +274,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
                     localAssembly == null ? null : _cecilTypeSystem.FindAssembly(localAssembly.GetName().Name),
                     _cecilMappings, XamlIlXmlnsMappings.Resolve(_cecilTypeSystem, _cecilMappings),
                     AvaloniaXamlIlLanguage.CustomValueConverter),
+                _cecilEmitMappings,
                 _cecilTypeSystem.CreateTypeBuilder(contextDef));
             compiler.ParseAndCompile(xaml, uri.ToString(), tb, overrideType);
             var asmPath = Path.Combine(_cecilEmitDir, safeUri + ".dll");

+ 43 - 38
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@@ -1,30 +1,33 @@
 using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Parsers;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Parsers;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
-    class AvaloniaXamlIlCompiler : XamlIlCompiler
+    class AvaloniaXamlIlCompiler : XamlILCompiler
     {
-        private readonly XamlIlTransformerConfiguration _configuration;
-        private readonly IXamlIlType _contextType;
+        private readonly TransformerConfiguration _configuration;
+        private readonly IXamlType _contextType;
         private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer;
         private readonly AvaloniaBindingExtensionTransformer _bindingTransformer;
 
-        private AvaloniaXamlIlCompiler(AvaloniaXamlIlCompilerConfiguration configuration) : base(configuration, true)
+        private AvaloniaXamlIlCompiler(TransformerConfiguration configuration, XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emitMappings)
+            : base(configuration, emitMappings, true)
         {
             _configuration = configuration;
 
-            void InsertAfter<T>(params IXamlIlAstTransformer[] t) 
+            void InsertAfter<T>(params IXamlAstTransformer[] t) 
                 => Transformers.InsertRange(Transformers.FindIndex(x => x is T) + 1, t);
 
-            void InsertBefore<T>(params IXamlIlAstTransformer[] t) 
+            void InsertBefore<T>(params IXamlAstTransformer[] t) 
                 => Transformers.InsertRange(Transformers.FindIndex(x => x is T), t);
 
 
@@ -38,14 +41,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             
             // Targeted
 
-            InsertBefore<XamlIlPropertyReferenceResolver>(
+            InsertBefore<PropertyReferenceResolver>(
                 new AvaloniaXamlIlTransformInstanceAttachedProperties(),
                 new AvaloniaXamlIlTransformSyntheticCompiledBindingMembers());
-            InsertAfter<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlAvaloniaPropertyResolver());
+            InsertAfter<PropertyReferenceResolver>(new AvaloniaXamlIlAvaloniaPropertyResolver());
             
 
 
-            InsertBefore<XamlIlContentConvertTransformer>(
+            InsertBefore<ContentConvertTransformer>(
                 new AvaloniaXamlIlBindingPathParser(),
                 new AvaloniaXamlIlSelectorTransformer(),
                 new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
@@ -56,8 +59,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             );
 
             // After everything else
-
-            InsertBefore<XamlIlNewObjectTransformer>(
+            InsertBefore<NewObjectTransformer>(
                 new AddNameScopeRegistration(),
                 new AvaloniaXamlIlDataContextTypeTransformer(),
                 new AvaloniaXamlIlBindingPathTransformer(),
@@ -66,17 +68,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
             Transformers.Add(new AvaloniaXamlIlMetadataRemover());
             Transformers.Add(new AvaloniaXamlIlRootObjectScope());
-        }
 
-        public AvaloniaXamlIlCompiler(AvaloniaXamlIlCompilerConfiguration configuration,
-            IXamlIlTypeBuilder contextTypeBuilder) : this(configuration)
+            Emitters.Add(new AvaloniaNameScopeRegistrationXamlIlNodeEmitter());
+            Emitters.Add(new AvaloniaXamlIlRootObjectScope.Emitter());
+        }
+        public AvaloniaXamlIlCompiler(TransformerConfiguration configuration,
+            XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emitMappings,
+            IXamlTypeBuilder<IXamlILEmitter> contextTypeBuilder)
+            : this(configuration, emitMappings)
         {
             _contextType = CreateContextType(contextTypeBuilder);
         }
 
         
-        public AvaloniaXamlIlCompiler(AvaloniaXamlIlCompilerConfiguration configuration,
-            IXamlIlType contextType) : this(configuration)
+        public AvaloniaXamlIlCompiler(TransformerConfiguration configuration,
+            XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emitMappings,
+            IXamlType contextType) : this(configuration, emitMappings)
         {
             _contextType = contextType;
         }
@@ -96,37 +103,35 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             set => _bindingTransformer.CompileBindingsByDefault = value;
         }
 
-        public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlIlTypeBuilder tb, IXamlIlType overrideRootType)
+        public void ParseAndCompile(string xaml, string baseUri, IFileSource fileSource, IXamlTypeBuilder<IXamlILEmitter> tb, IXamlType overrideRootType)
         {
-            var parsed = XDocumentXamlIlParser.Parse(xaml, new Dictionary<string, string>
+            var parsed = XDocumentXamlParser.Parse(xaml, new Dictionary<string, string>
             {
                 {XamlNamespaces.Blend2008, XamlNamespaces.Blend2008}
             });
             
-            var rootObject = (XamlIlAstObjectNode)parsed.Root;
+            var rootObject = (XamlAstObjectNode)parsed.Root;
 
             var classDirective = rootObject.Children
-                .OfType<XamlIlAstXmlDirective>().FirstOrDefault(x =>
+                .OfType<XamlAstXmlDirective>().FirstOrDefault(x =>
                     x.Namespace == XamlNamespaces.Xaml2006
                     && x.Name == "Class");
 
             var rootType =
                 classDirective != null ?
-                    new XamlIlAstClrTypeReference(classDirective,
-                        _configuration.TypeSystem.GetType(((XamlIlAstTextNode)classDirective.Values[0]).Text),
+                    new XamlAstClrTypeReference(classDirective,
+                        _configuration.TypeSystem.GetType(((XamlAstTextNode)classDirective.Values[0]).Text),
                         false) :
-                    XamlIlTypeReferenceResolver.ResolveType(CreateTransformationContext(parsed, true),
-                        (XamlIlAstXmlTypeReference)rootObject.Type, true);
+                    TypeReferenceResolver.ResolveType(CreateTransformationContext(parsed, true),
+                        (XamlAstXmlTypeReference)rootObject.Type, true);
             
             
             if (overrideRootType != null)
             {
-                
-
                 if (!rootType.Type.IsAssignableFrom(overrideRootType))
-                    throw new XamlIlLoadException(
+                    throw new XamlX.XamlLoadException(
                         $"Unable to substitute {rootType.Type.GetFqn()} with {overrideRootType.GetFqn()}", rootObject);
-                rootType = new XamlIlAstClrTypeReference(rootObject, overrideRootType, false);
+                rootType = new XamlAstClrTypeReference(rootObject, overrideRootType, false);
             }
 
             OverrideRootType(parsed, rootType);
@@ -136,17 +141,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             
         }
 
-        public void OverrideRootType(XamlIlDocument doc, IXamlIlAstTypeReference newType)
+        public void OverrideRootType(XamlDocument doc, IXamlAstTypeReference newType)
         {
-            var root = (XamlIlAstObjectNode)doc.Root;
+            var root = (XamlAstObjectNode)doc.Root;
             var oldType = root.Type;
             if (oldType.Equals(newType))
                 return;
 
             root.Type = newType;
-            foreach (var child in root.Children.OfType<XamlIlAstXamlPropertyValueNode>())
+            foreach (var child in root.Children.OfType<XamlAstXamlPropertyValueNode>())
             {
-                if (child.Property is XamlIlAstNamePropertyReference prop)
+                if (child.Property is XamlAstNamePropertyReference prop)
                 {
                     if (prop.DeclaringType.Equals(oldType))
                         prop.DeclaringType = newType;

+ 8 - 8
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs

@@ -1,18 +1,18 @@
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
-    class AvaloniaXamlIlCompilerConfiguration : XamlIlTransformerConfiguration
+    class AvaloniaXamlIlCompilerConfiguration : TransformerConfiguration
     {
         public XamlIlClrPropertyInfoEmitter ClrPropertyEmitter { get; }
         public XamlIlPropertyInfoAccessorFactoryEmitter AccessorFactoryEmitter { get; }
 
-        public AvaloniaXamlIlCompilerConfiguration(IXamlIlTypeSystem typeSystem, 
-            IXamlIlAssembly defaultAssembly, 
-            XamlIlLanguageTypeMappings typeMappings,
-            XamlIlXmlnsMappings xmlnsMappings,
-            XamlIlValueConverter customValueConverter,
+        public AvaloniaXamlIlCompilerConfiguration(IXamlTypeSystem typeSystem, 
+            IXamlAssembly defaultAssembly, 
+            XamlLanguageTypeMappings typeMappings,
+            XamlXmlnsMappings xmlnsMappings,
+            XamlValueConverter customValueConverter,
             XamlIlClrPropertyInfoEmitter clrPropertyEmitter,
             XamlIlPropertyInfoAccessorFactoryEmitter accessorFactoryEmitter)
             : base(typeSystem, defaultAssembly, typeMappings, xmlnsMappings, customValueConverter)

+ 42 - 36
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@@ -2,10 +2,12 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
@@ -17,12 +19,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
     
     class AvaloniaXamlIlLanguage
     {
-        public static XamlIlLanguageTypeMappings Configure(IXamlIlTypeSystem typeSystem)
+        public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult> emit) Configure(IXamlTypeSystem typeSystem)
         {
             var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
             var assignBindingAttribute = typeSystem.GetType("Avalonia.Data.AssignBindingAttribute");
             var bindingType = typeSystem.GetType("Avalonia.Data.IBinding");
-            var rv = new XamlIlLanguageTypeMappings(typeSystem)
+            var rv = new XamlLanguageTypeMappings(typeSystem)
             {
                 SupportInitialize = typeSystem.GetType("System.ComponentModel.ISupportInitialize"),
                 XmlnsAttributes =
@@ -51,18 +53,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 },
                 InnerServiceProviderFactoryMethod =
                     runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"),
-                ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.EmitProvideValueTarget,
             };
             rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv);
-            rv.ContextTypeBuilderCallback = (b, c) => EmitNameScopeField(rv, typeSystem, b, c);
-            return rv;
+
+            var emit = new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>
+            {
+                ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.EmitProvideValueTarget,
+                ContextTypeBuilderCallback = (b, c) => EmitNameScopeField(rv, typeSystem, b, c)
+            };
+            return (rv, emit);
         }
 
         public const string ContextNameScopeFieldName = "AvaloniaNameScope";
 
-        private static void EmitNameScopeField(XamlIlLanguageTypeMappings mappings,
-            IXamlIlTypeSystem typeSystem,
-            IXamlIlTypeBuilder typebuilder, IXamlIlEmitter constructor)
+        private static void EmitNameScopeField(XamlLanguageTypeMappings mappings,
+            IXamlTypeSystem typeSystem,
+            IXamlTypeBuilder<IXamlILEmitter> typebuilder, IXamlILEmitter constructor)
         {
 
             var nameScopeType = typeSystem.FindType("Avalonia.Controls.INameScope");
@@ -78,23 +84,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         }
         
 
-        class AttributeResolver : IXamlIlCustomAttributeResolver
+        class AttributeResolver : IXamlCustomAttributeResolver
         {
-            private readonly IXamlIlType _typeConverterAttribute;
+            private readonly IXamlType _typeConverterAttribute;
 
-            private readonly List<KeyValuePair<IXamlIlType, IXamlIlType>> _converters =
-                new List<KeyValuePair<IXamlIlType, IXamlIlType>>();
+            private readonly List<KeyValuePair<IXamlType, IXamlType>> _converters =
+                new List<KeyValuePair<IXamlType, IXamlType>>();
 
-            private readonly IXamlIlType _avaloniaList;
-            private readonly IXamlIlType _avaloniaListConverter;
+            private readonly IXamlType _avaloniaList;
+            private readonly IXamlType _avaloniaListConverter;
 
 
-            public AttributeResolver(IXamlIlTypeSystem typeSystem, XamlIlLanguageTypeMappings mappings)
+            public AttributeResolver(IXamlTypeSystem typeSystem, XamlLanguageTypeMappings mappings)
             {
                 _typeConverterAttribute = mappings.TypeConverterAttributes.First();
 
-                void AddType(IXamlIlType type, IXamlIlType conv) 
-                    => _converters.Add(new KeyValuePair<IXamlIlType, IXamlIlType>(type, conv));
+                void AddType(IXamlType type, IXamlType conv) 
+                    => _converters.Add(new KeyValuePair<IXamlType, IXamlType>(type, conv));
 
                 void Add(string type, string conv)
                     => AddType(typeSystem.GetType(type), typeSystem.GetType(conv));
@@ -113,7 +119,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 _avaloniaListConverter = typeSystem.GetType("Avalonia.Collections.AvaloniaListConverter`1");
             }
 
-            IXamlIlType LookupConverter(IXamlIlType type)
+            IXamlType LookupConverter(IXamlType type)
             {
                 foreach(var p in _converters)
                     if (p.Key.Equals(type))
@@ -123,15 +129,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 return null;
             }
 
-            class ConstructedAttribute : IXamlIlCustomAttribute
+            class ConstructedAttribute : IXamlCustomAttribute
             {
-                public bool Equals(IXamlIlCustomAttribute other) => false;
+                public bool Equals(IXamlCustomAttribute other) => false;
                 
-                public IXamlIlType Type { get; }
+                public IXamlType Type { get; }
                 public List<object> Parameters { get; }
                 public Dictionary<string, object> Properties { get; }
 
-                public ConstructedAttribute(IXamlIlType type, List<object> parameters, Dictionary<string, object> properties)
+                public ConstructedAttribute(IXamlType type, List<object> parameters, Dictionary<string, object> properties)
                 {
                     Type = type;
                     Parameters = parameters ?? new List<object>();
@@ -139,7 +145,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 }
             }
             
-            public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlType type, IXamlIlType attributeType)
+            public IXamlCustomAttribute GetCustomAttribute(IXamlType type, IXamlType attributeType)
             {
                 if (attributeType.Equals(_typeConverterAttribute))
                 {
@@ -151,25 +157,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 return null;
             }
 
-            public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlProperty property, IXamlIlType attributeType)
+            public IXamlCustomAttribute GetCustomAttribute(IXamlProperty property, IXamlType attributeType)
             {
                 return null;
             }
         }
 
-        public static bool CustomValueConverter(XamlIlAstTransformationContext context,
-            IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode result)
+        public static bool CustomValueConverter(AstTransformationContext context,
+            IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result)
         {
             if (type.FullName == "System.TimeSpan" 
-                && node is XamlIlAstTextNode tn
+                && node is XamlAstTextNode tn
                 && !tn.Text.Contains(":"))
             {
                 var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture);
-                result = new XamlIlStaticOrTargetedReturnMethodCallNode(tn,
+                result = new XamlStaticOrTargetedReturnMethodCallNode(tn,
                     type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double),
                     new[]
                     {
-                        new XamlIlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds)
+                        new XamlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds)
                     });
                 return true;
             }
@@ -178,9 +184,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             {
                 var scope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
                 if (scope == null)
-                    throw new XamlIlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
-                if (!(node is XamlIlAstTextNode text))
-                    throw new XamlIlLoadException("Property should be a text node", node);
+                    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);
                 return true;
             }

+ 52 - 44
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs

@@ -1,35 +1,37 @@
 using System;
 using System.Linq;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+using XamlX.Emit;
+using XamlX.IL;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AddNameScopeRegistration : IXamlIlAstTransformer
+    class AddNameScopeRegistration : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlPropertyAssignmentNode pa)
+            if (node is XamlPropertyAssignmentNode pa)
             {
                 if (pa.Property.Name == "Name"
                     && pa.Property.DeclaringType.FullName == "Avalonia.StyledElement")
                 {
-                    if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg
+                    if (context.ParentNodes().FirstOrDefault() is XamlManipulationGroupNode mg
                         && mg.Children.OfType<AvaloniaNameScopeRegistrationXamlIlNode>().Any())
                         return node;
 
-                    IXamlIlAstValueNode value = null;
+                    IXamlAstValueNode value = null;
                     for (var c = 0; c < pa.Values.Count; c++)
                         if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
                         {
                             value = pa.Values[c];
-                            if (!(value is XamlIlAstTextNode))
+                            if (!(value is XamlAstTextNode))
                             {
-                                var local = new XamlIlAstCompilerLocalNode(value);
+                                var local = new XamlAstCompilerLocalNode(value);
                                 // Wrap original in local initialization
-                                pa.Values[c] = new XamlIlAstLocalInitializationNodeEmitter(value, value, local);
+                                pa.Values[c] = new XamlAstLocalInitializationNodeEmitter(value, value, local);
                                 // Use local
                                 value = local;
                             }
@@ -39,13 +41,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
                     if (value != null)
                     {
-                        var objectType = context.ParentNodes().OfType<XamlIlAstObjectNode>().FirstOrDefault()?.Type.GetClrType();
-                        return new XamlIlManipulationGroupNode(pa)
+                        var objectType = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault()?.Type.GetClrType();
+                        return new XamlManipulationGroupNode(pa)
                         {
                             Children =
                             {
                                 pa,
-                                new AvaloniaNameScopeRegistrationXamlIlNode(value, context.GetAvaloniaTypes(), objectType)
+                                new AvaloniaNameScopeRegistrationXamlIlNode(value, objectType)
                             }
                         };
                     }
@@ -61,52 +63,58 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
     }
 
-    class NestedScopeMetadataNode : XamlIlValueWithSideEffectNodeBase
+    class NestedScopeMetadataNode : XamlValueWithSideEffectNodeBase
     {
-        public NestedScopeMetadataNode(IXamlIlAstValueNode value) : base(value, value)
+        public NestedScopeMetadataNode(IXamlAstValueNode value) : base(value, value)
         {
         }
     }
 
-    class AvaloniaNameScopeRegistrationXamlIlNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode
+    class AvaloniaNameScopeRegistrationXamlIlNode : XamlAstNode, IXamlAstManipulationNode
     {
-        private readonly AvaloniaXamlIlWellKnownTypes _types;
-        public IXamlIlAstValueNode Name { get; set; }
-        public IXamlIlType TargetType { get; }
+        public IXamlAstValueNode Name { get; set; }
+        public IXamlType TargetType { get; }
 
-        public AvaloniaNameScopeRegistrationXamlIlNode(IXamlIlAstValueNode name, AvaloniaXamlIlWellKnownTypes types, IXamlIlType targetType) : base(name)
+        public AvaloniaNameScopeRegistrationXamlIlNode(IXamlAstValueNode name, IXamlType targetType) : base(name)
         {
-            _types = types;
             TargetType = targetType;
             Name = name;
         }
 
-        public override void VisitChildren(IXamlIlAstVisitor visitor)
-            => Name = (IXamlIlAstValueNode)Name.Visit(visitor);
+        public override void VisitChildren(IXamlAstVisitor visitor)
+            => Name = (IXamlAstValueNode)Name.Visit(visitor);
+    }
 
-        public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+    class AvaloniaNameScopeRegistrationXamlIlNodeEmitter : IXamlAstLocalsNodeEmitter<IXamlILEmitter, XamlILNodeEmitResult>
+    {
+        public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
-            var scopeField = context.RuntimeContext.ContextType.Fields.First(f =>
-                f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName);
-            
-            using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object))
+            if (node is AvaloniaNameScopeRegistrationXamlIlNode registration)
             {
 
-                codeGen
-                    // var target = {pop}
-                    .Stloc(targetLoc.Local)
-                    // _context.NameScope.Register(Name, target)
-                    .Ldloc(context.ContextLocal)
-                    .Ldfld(scopeField);
-                    
-                context.Emit(Name, codeGen, Name.Type.GetClrType());
-                
-                codeGen
-                    .Ldloc(targetLoc.Local)
-                    .EmitCall(_types.INameScopeRegister, true);
-            }
+                var scopeField = context.RuntimeContext.ContextType.Fields.First(f =>
+                    f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName);
+
+                using (var targetLoc = context.GetLocalOfType(context.Configuration.WellKnownTypes.Object))
+                {
 
-            return XamlIlNodeEmitResult.Void(1);
+                    codeGen
+                        // var target = {pop}
+                        .Stloc(targetLoc.Local)
+                        // _context.NameScope.Register(Name, target)
+                        .Ldloc(context.ContextLocal)
+                        .Ldfld(scopeField);
+
+                    context.Emit(registration.Name, codeGen, registration.Name.Type.GetClrType());
+
+                    codeGen
+                        .Ldloc(targetLoc.Local)
+                        .EmitCall(context.GetAvaloniaTypes().INameScopeRegister, true);
+                }
+
+                return XamlILNodeEmitResult.Void(1);
+            }
+            return default;
         }
     }
 }

+ 16 - 14
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaBindingExtensionTransformer.cs

@@ -1,35 +1,38 @@
 using System.Linq;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+
+
+using XamlParseException = XamlX.XamlParseException;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaBindingExtensionTransformer : IXamlIlAstTransformer
+    class AvaloniaBindingExtensionTransformer : IXamlAstTransformer
     {
         public bool CompileBindingsByDefault { get; set; }
 
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
             if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlCompileBindingsNode)
             {
                 return node;
             }
 
-            if (node is XamlIlAstObjectNode obj)
+            if (node is XamlAstObjectNode obj)
             {
                 foreach (var item in obj.Children)
                 {
-                    if (item is XamlIlAstXmlDirective directive)
+                    if (item is XamlAstXmlDirective directive)
                     {
                         if (directive.Namespace == XamlNamespaces.Xaml2006
                             && directive.Name == "CompileBindings"
                             && directive.Values.Count == 1)
                         {
-                            if (!(directive.Values[0] is XamlIlAstTextNode text
+                            if (!(directive.Values[0] is XamlAstTextNode text
                                 && bool.TryParse(text.Text, out var compileBindings)))
                             {
-                                throw new XamlIlParseException("The value of x:CompileBindings must be a literal boolean value.", directive.Values[0]);
+                                throw new XamlParseException("The value of x:CompileBindings must be a literal boolean value.", directive.Values[0]);
                             }
 
                             obj.Children.Remove(directive);
@@ -40,10 +43,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 }
             }
 
-            // Our code base expects XAML parser to prefer `FooExtension` to `Foo` even with `<Foo>` syntax
-            // This is the legacy of Portable.Xaml, so we emulate that behavior here
+            // Convert the <Binding> tag to either a CompiledBinding or ReflectionBinding tag.
 
-            if (node is XamlIlAstXmlTypeReference tref
+            if (node is XamlAstXmlTypeReference tref
                 && tref.Name == "Binding"
                 && tref.XmlNamespace == "https://github.com/avaloniaui")
             {
@@ -60,9 +62,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
     }
 
-    internal class AvaloniaXamlIlCompileBindingsNode : XamlIlValueWithSideEffectNodeBase
+    internal class AvaloniaXamlIlCompileBindingsNode : XamlValueWithSideEffectNodeBase
     {
-        public AvaloniaXamlIlCompileBindingsNode(IXamlIlAstValueNode value, bool compileBindings)
+        public AvaloniaXamlIlCompileBindingsNode(IXamlAstValueNode value, bool compileBindings)
             : base(value, value)
         {
             CompileBindings = compileBindings;

+ 5 - 5
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs

@@ -1,14 +1,14 @@
 using System.Linq;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlAvaloniaPropertyResolver : IXamlIlAstTransformer
+    class AvaloniaXamlIlAvaloniaPropertyResolver : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstClrProperty prop)
+            if (node is XamlAstClrProperty prop)
             {
                 var n = prop.Name + "Property";
                 var field =

+ 58 - 56
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs

@@ -4,23 +4,25 @@ using System.Linq;
 using System.Text;
 using Avalonia.Markup.Parsers;
 using Avalonia.Utilities;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
+
+using XamlParseException = XamlX.XamlParseException;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlBindingPathParser : IXamlIlAstTransformer
+    class AvaloniaXamlIlBindingPathParser : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
+            if (node is XamlAstObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
             {
                 var convertedNode = ConvertLongFormPropertiesToBindingExpressionNode(context, binding);
 
-                if (binding.Arguments.Count > 0 && binding.Arguments[0] is XamlIlAstTextNode bindingPathText)
+                if (binding.Arguments.Count > 0 && binding.Arguments[0] is XamlAstTextNode bindingPathText)
                 {
                     var reader = new CharacterReader(bindingPathText.Text.AsSpan());
                     var (nodes, _) = BindingExpressionGrammar.Parse(ref reader);
@@ -34,10 +36,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 }
                 else
                 {
-                    var bindingPathAssignment = binding.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+                    var bindingPathAssignment = binding.Children.OfType<XamlAstXamlPropertyValueNode>()
                         .FirstOrDefault(v => v.Property.GetClrProperty().Name == "Path");
 
-                    if (bindingPathAssignment != null && bindingPathAssignment.Values[0] is XamlIlAstTextNode pathValue)
+                    if (bindingPathAssignment != null && bindingPathAssignment.Values[0] is XamlAstTextNode pathValue)
                     {
                         var reader = new CharacterReader(pathValue.Text.AsSpan());
                         var (nodes, _) = BindingExpressionGrammar.Parse(ref reader);
@@ -56,12 +58,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
 
         private static BindingExpressionGrammar.INode ConvertLongFormPropertiesToBindingExpressionNode(
-            XamlIlAstTransformationContext context,
-            XamlIlAstObjectNode binding)
+            AstTransformationContext context,
+            XamlAstObjectNode binding)
         {
             BindingExpressionGrammar.INode convertedNode = null;
 
-            var syntheticCompiledBindingProperties = binding.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+            var syntheticCompiledBindingProperties = binding.Children.OfType<XamlAstXamlPropertyValueNode>()
                 .Where(v => v.Property is AvaloniaSyntheticCompiledBindingProperty)
                 .ToList();
 
@@ -80,20 +82,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     v.Property is AvaloniaSyntheticCompiledBindingProperty prop
                     && prop.Name == SyntheticCompiledBindingPropertyName.RelativeSource);
 
-            if (elementNameProperty?.Values[0] is XamlIlAstTextNode elementName)
+            if (elementNameProperty?.Values[0] is XamlAstTextNode elementName)
             {
                 convertedNode = new BindingExpressionGrammar.NameNode { Name = elementName.Text };
             }
             else if (elementNameProperty != null)
             {
-                throw new XamlIlParseException($"Invalid ElementName '{elementNameProperty.Values[0]}'.", elementNameProperty.Values[0]);
+                throw new XamlParseException($"Invalid ElementName '{elementNameProperty.Values[0]}'.", elementNameProperty.Values[0]);
             }
 
             if (sourceProperty?.Values[0] != null)
             {
                 if (convertedNode != null)
                 {
-                    throw new XamlIlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
+                    throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
                 }
 
                 convertedNode = new RawSourceBindingExpressionNode(sourceProperty?.Values[0]);
@@ -106,13 +108,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             {
                 if (convertedNode != null)
                 {
-                    throw new XamlIlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
+                    throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
                 }
 
                 var mode = relativeSourceObject.Children
-                    .OfType<XamlIlAstXamlPropertyValueNode>()
+                    .OfType<XamlAstXamlPropertyValueNode>()
                     .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Mode")
-                    ?.Values[0] is XamlIlAstTextNode modeAssignedValue ? modeAssignedValue.Text : null;
+                    ?.Values[0] is XamlAstTextNode modeAssignedValue ? modeAssignedValue.Text : null;
                 if (relativeSourceObject.Arguments.Count == 0 && mode == null)
                 {
                     mode = "FindAncestor";
@@ -121,46 +123,46 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 if (mode == "FindAncestor")
                 {
                     var ancestorLevel = relativeSourceObject.Children
-                        .OfType<XamlIlAstXamlPropertyValueNode>()
+                        .OfType<XamlAstXamlPropertyValueNode>()
                         .FirstOrDefault(x => x.Property.GetClrProperty().Name == "FindAncestor")
-                        ?.Values[0] is XamlIlAstTextNode ancestorLevelText ? int.Parse(ancestorLevelText.Text) - 1 : 0;
+                        ?.Values[0] is XamlAstTextNode ancestorLevelText ? int.Parse(ancestorLevelText.Text) - 1 : 0;
 
                     var treeType = relativeSourceObject.Children
-                        .OfType<XamlIlAstXamlPropertyValueNode>()
+                        .OfType<XamlAstXamlPropertyValueNode>()
                         .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Tree")
-                        ?.Values[0] is XamlIlAstTextNode treeTypeValue ? treeTypeValue.Text : "Visual";
+                        ?.Values[0] is XamlAstTextNode treeTypeValue ? treeTypeValue.Text : "Visual";
 
                     var ancestorTypeName = relativeSourceObject.Children
-                        .OfType<XamlIlAstXamlPropertyValueNode>()
+                        .OfType<XamlAstXamlPropertyValueNode>()
                         .FirstOrDefault(x => x.Property.GetClrProperty().Name == "AncestorType")
-                        ?.Values[0] as XamlIlAstTextNode;
+                        ?.Values[0] as XamlAstTextNode;
 
-                    IXamlIlType ancestorType = null;
+                    IXamlType ancestorType = null;
                     if (ancestorTypeName is null)
                     {
                         if (treeType == "Visual")
                         {
-                            throw new XamlIlParseException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree.", relativeSourceObject);
+                            throw new XamlParseException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree.", relativeSourceObject);
                         }
                         else if (treeType == "Logical")
                         {
                             var styledElementType = context.GetAvaloniaTypes().StyledElement;
                             ancestorType = context
                                 .ParentNodes()
-                                .OfType<XamlIlAstObjectNode>()
+                                .OfType<XamlAstObjectNode>()
                                 .Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
                                 .ElementAtOrDefault(ancestorLevel)
                                 ?.Type.GetClrType();
 
                             if (ancestorType is null)
                             {
-                                throw new XamlIlParseException("Unable to resolve implicit ancestor type based on XAML tree.", relativeSourceObject);
+                                throw new XamlX.XamlParseException("Unable to resolve implicit ancestor type based on XAML tree.", relativeSourceObject);
                             }
                         }
                     }
                     else
                     {
-                        ancestorType = XamlIlTypeReferenceResolver.ResolveType(
+                        ancestorType = TypeReferenceResolver.ResolveType(
                                             context,
                                             ancestorTypeName.Text,
                                             false,
@@ -186,7 +188,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     }
                     else
                     {
-                        throw new XamlIlParseException($"Unknown tree type '{treeType}'.", binding);
+                        throw new XamlParseException($"Unknown tree type '{treeType}'.", binding);
                     }
                 }
                 else if (mode == "DataContext")
@@ -206,14 +208,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
                     if (parentType is null)
                     {
-                        throw new XamlIlParseException("A binding with a TemplatedParent RelativeSource has to be in a ControlTemplate.", binding);
+                        throw new XamlParseException("A binding with a TemplatedParent RelativeSource has to be in a ControlTemplate.", binding);
                     }
 
                     convertedNode = new TemplatedParentBindingExpressionNode { Type = parentType };
                 }
                 else
                 {
-                    throw new XamlIlParseException($"Unknown RelativeSource mode '{mode}'.", binding);
+                    throw new XamlParseException($"Unknown RelativeSource mode '{mode}'.", binding);
                 }
             }
 
@@ -234,9 +236,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
 
         private static bool GetRelativeSourceObjectFromAssignment(
-            XamlIlAstTransformationContext context,
-            XamlIlAstXamlPropertyValueNode relativeSourceProperty,
-            out XamlIlAstObjectNode relativeSourceObject)
+            AstTransformationContext context,
+            XamlAstXamlPropertyValueNode relativeSourceProperty,
+            out XamlAstObjectNode relativeSourceObject)
         {
             relativeSourceObject = null;
             if (relativeSourceProperty is null)
@@ -244,22 +246,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 return false;
             }
 
-            if (relativeSourceProperty.Values[0] is XamlIlMarkupExtensionNode me)
+            if (relativeSourceProperty.Values[0] is XamlMarkupExtensionNode me)
             {
                 if (me.Type.GetClrType() != context.GetAvaloniaTypes().RelativeSource)
                 {
-                    throw new XamlIlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{me.Type.GetClrType().GetFqn()}'", me);
+                    throw new XamlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{me.Type.GetClrType().GetFqn()}'", me);
                 }
 
-                relativeSourceObject = (XamlIlAstObjectNode)me.Value;
+                relativeSourceObject = (XamlAstObjectNode)me.Value;
                 return true;
             }
 
-            if (relativeSourceProperty.Values[0] is XamlIlAstObjectNode on)
+            if (relativeSourceProperty.Values[0] is XamlAstObjectNode on)
             {
                 if (on.Type.GetClrType() != context.GetAvaloniaTypes().RelativeSource)
                 {
-                    throw new XamlIlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{on.Type.GetClrType().GetFqn()}'", on);
+                    throw new XamlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{on.Type.GetClrType().GetFqn()}'", on);
                 }
 
                 relativeSourceObject = on;
@@ -270,24 +272,24 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
     }
 
-    class ParsedBindingPathNode : XamlIlAstNode, IXamlIlAstValueNode
+    class ParsedBindingPathNode : XamlAstNode, IXamlAstValueNode
     {
-        public ParsedBindingPathNode(IXamlIlLineInfo lineInfo, IXamlIlType compiledBindingType, IList<BindingExpressionGrammar.INode> path)
+        public ParsedBindingPathNode(IXamlLineInfo lineInfo, IXamlType compiledBindingType, IList<BindingExpressionGrammar.INode> path)
             : base(lineInfo)
         {
-            Type = new XamlIlAstClrTypeReference(lineInfo, compiledBindingType, false);
+            Type = new XamlAstClrTypeReference(lineInfo, compiledBindingType, false);
             Path = path;
         }
 
-        public IXamlIlAstTypeReference Type { get; }
+        public IXamlAstTypeReference Type { get; }
 
         public IList<BindingExpressionGrammar.INode> Path { get; }
 
-        public override void VisitChildren(IXamlIlAstVisitor visitor)
+        public override void VisitChildren(IXamlAstVisitor visitor)
         {
             for (int i = 0; i < Path.Count; i++)
             {
-                if (Path[i] is IXamlIlAstNode ast)
+                if (Path[i] is IXamlAstNode ast)
                 {
                     Path[i] = (BindingExpressionGrammar.INode)ast.Visit(visitor);
                 }
@@ -297,34 +299,34 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
     class VisualAncestorBindingExpressionNode : BindingExpressionGrammar.INode
     {
-        public IXamlIlType Type { get; set; }
+        public IXamlType Type { get; set; }
         public int Level { get; set; }
     }
 
     class LogicalAncestorBindingExpressionNode : BindingExpressionGrammar.INode
     {
-        public IXamlIlType Type { get; set; }
+        public IXamlType Type { get; set; }
         public int Level { get; set; }
     }
 
     class TemplatedParentBindingExpressionNode : BindingExpressionGrammar.INode
     {
-        public IXamlIlType Type { get; set; }
+        public IXamlType Type { get; set; }
     }
 
-    class RawSourceBindingExpressionNode : XamlIlAstNode, BindingExpressionGrammar.INode
+    class RawSourceBindingExpressionNode : XamlAstNode, BindingExpressionGrammar.INode
     {
-        public RawSourceBindingExpressionNode(IXamlIlAstValueNode rawSource)
+        public RawSourceBindingExpressionNode(IXamlAstValueNode rawSource)
             : base(rawSource)
         {
             RawSource = rawSource;
         }
 
-        public IXamlIlAstValueNode RawSource { get; private set; }
+        public IXamlAstValueNode RawSource { get; private set; }
 
-        public override void VisitChildren(IXamlIlAstVisitor visitor)
+        public override void VisitChildren(IXamlAstVisitor visitor)
         {
-            RawSource = (IXamlIlAstValueNode)RawSource.Visit(visitor);
+            RawSource = (IXamlAstValueNode)RawSource.Visit(visitor);
         }
     }
 }

+ 9 - 9
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs

@@ -2,24 +2,24 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlBindingPathTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlBindingPathTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
+            if (node is XamlAstConstructableObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
             {
-                IXamlIlType startType;
+                IXamlType startType;
                 var parentDataContextNode = context.ParentNodes().OfType<AvaloniaXamlIlDataContextTypeMetadataNode>().FirstOrDefault();
                 if (parentDataContextNode is null)
                 {
-                    throw new XamlIlParseException("Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.", binding);
+                    throw new XamlX.XamlParseException("Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.", binding);
                 }
 
                 startType = parentDataContextNode.DataContextType;

+ 4 - 4
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlCompiledBindingsMetadataRemover.cs

@@ -1,12 +1,12 @@
 using System.Linq;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlCompiledBindingsMetadataRemover : IXamlIlAstTransformer
+    class AvaloniaXamlIlCompiledBindingsMetadataRemover : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
             while (true)
             {

+ 15 - 13
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlConstructorServiceProviderTransformer.cs

@@ -1,15 +1,17 @@
 using System.Linq;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlConstructorServiceProviderTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlConstructorServiceProviderTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode on && on.Arguments.Count == 0)
+            if (node is XamlAstObjectNode on && on.Arguments.Count == 0)
             {
                 var ctors = on.Type.GetClrType().Constructors;
                 if (!ctors.Any(c => c.IsPublic && !c.IsStatic && c.Parameters.Count == 0))
@@ -27,20 +29,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             return node;
         }
 
-        class InjectServiceProviderNode : XamlIlAstNode, IXamlIlAstValueNode,IXamlIlAstNodeNeedsParentStack,
-            IXamlIlAstEmitableNode
+        class InjectServiceProviderNode : XamlAstNode, IXamlAstValueNode,IXamlAstNodeNeedsParentStack,
+            IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
         {
-            public InjectServiceProviderNode(IXamlIlType type, IXamlIlLineInfo lineInfo) : base(lineInfo)
+            public InjectServiceProviderNode(IXamlType type, IXamlLineInfo lineInfo) : base(lineInfo)
             {
-                Type = new XamlIlAstClrTypeReference(lineInfo, type, false);
+                Type = new XamlAstClrTypeReference(lineInfo, type, false);
             }
 
-            public IXamlIlAstTypeReference Type { get; }
+            public IXamlAstTypeReference Type { get; }
             public bool NeedsParentStack => true;
-            public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
             {
                 codeGen.Ldloc(context.ContextLocal);
-                return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
+                return XamlILNodeEmitResult.Type(0, Type.GetClrType());
             }
         }
     }

+ 14 - 14
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs

@@ -1,29 +1,29 @@
 using System.Linq;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (!(node is XamlIlAstObjectNode on
+            if (!(node is XamlAstObjectNode on
                   && on.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.Templates.ControlTemplate"))
                 return node;
-            var tt = on.Children.OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(ch =>
+            var tt = on.Children.OfType<XamlAstXamlPropertyValueNode>().FirstOrDefault(ch =>
                                               ch.Property.GetClrProperty().Name == "TargetType");
 
             if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlTargetTypeMetadataNode)
                 // Deja vu. I've just been in this place before
                 return node;
 
-            IXamlIlAstTypeReference targetType;
+            IXamlAstTypeReference targetType;
 
             var templatableBaseType = context.Configuration.TypeSystem.GetType("Avalonia.Controls.Control");
             
-            if ((tt?.Values.FirstOrDefault() is XamlIlTypeExtensionNode tn))
+            if ((tt?.Values.FirstOrDefault() is XamlTypeExtensionNode tn))
             {
                 targetType = tn.Value;
             }
@@ -33,11 +33,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     .FirstOrDefault();
                 if (parentScope?.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style)
                     targetType = parentScope.TargetType;
-                else if (context.ParentNodes().Skip(1).FirstOrDefault() is XamlIlAstObjectNode directParentNode
+                else if (context.ParentNodes().Skip(1).FirstOrDefault() is XamlAstObjectNode directParentNode
                          && templatableBaseType.IsAssignableFrom(directParentNode.Type.GetClrType()))
                     targetType = directParentNode.Type;
                 else
-                    targetType = new XamlIlAstClrTypeReference(node,
+                    targetType = new XamlAstClrTypeReference(node,
                         templatableBaseType, false);
             }
                 
@@ -48,9 +48,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
     }
 
-    class AvaloniaXamlIlTargetTypeMetadataNode : XamlIlValueWithSideEffectNodeBase
+    class AvaloniaXamlIlTargetTypeMetadataNode : XamlValueWithSideEffectNodeBase
     {
-        public IXamlIlAstTypeReference TargetType { get; set; }
+        public IXamlAstTypeReference TargetType { get; set; }
         public ScopeTypes ScopeType { get; }
 
         public enum ScopeTypes
@@ -60,7 +60,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             Transitions
         }
         
-        public AvaloniaXamlIlTargetTypeMetadataNode(IXamlIlAstValueNode value, IXamlIlAstTypeReference targetType,
+        public AvaloniaXamlIlTargetTypeMetadataNode(IXamlAstValueNode value, IXamlAstTypeReference targetType,
             ScopeTypes type)
             : base(value, value)
         {

+ 29 - 29
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs

@@ -6,18 +6,18 @@ using System.Text;
 using Avalonia.Markup.Parsers;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
 using Avalonia.Utilities;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlDataContextTypeTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlDataContextTypeTransformer : IXamlAstTransformer
     {
         private const string AvaloniaNs = "https://github.com/avaloniaui";
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
             if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlDataContextTypeMetadataNode)
             {
@@ -25,7 +25,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 return node;
             }
 
-            if (node is XamlIlAstObjectNode on)
+            if (node is XamlAstConstructableObjectNode on)
             {
                 AvaloniaXamlIlDataContextTypeMetadataNode inferredDataContextTypeNode = null;
                 AvaloniaXamlIlDataContextTypeMetadataNode directiveDataContextTypeNode = null;
@@ -34,7 +34,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 for (int i = 0; i < on.Children.Count; ++i)
                 {
                     var child = on.Children[i];
-                    if (child is XamlIlAstXmlDirective directive)
+                    if (child is XamlAstXmlDirective directive)
                     {
                         if (directive.Namespace == XamlNamespaces.Xaml2006
                             && directive.Name == "DataType"
@@ -42,29 +42,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                         {
                             on.Children.RemoveAt(i);
                             i--;
-                            if (directive.Values[0] is XamlIlAstTextNode text)
+                            if (directive.Values[0] is XamlAstTextNode text)
                             {
                                 directiveDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on,
-                                    XamlIlTypeReferenceResolver.ResolveType(context, text.Text, isMarkupExtension: false, text, strict: true).Type);
+                                    TypeReferenceResolver.ResolveType(context, text.Text, isMarkupExtension: false, text, strict: true).Type);
                             }
                             else
                             {
-                                throw new XamlIlParseException("x:DataType should be set to a type name.", directive.Values[0]);
+                                throw new XamlX.XamlParseException("x:DataType should be set to a type name.", directive.Values[0]);
                             }
                         }
                     }
-                    else if (child is XamlIlPropertyAssignmentNode pa)
+                    else if (child is XamlPropertyAssignmentNode pa)
                     {
                         if (pa.Property.Name == "DataContext"
                             && pa.Property.DeclaringType.Equals(context.GetAvaloniaTypes().StyledElement)
-                            && pa.Values[0] is XamlIlMarkupExtensionNode ext
-                            && ext.Value is XamlIlAstObjectNode obj)
+                            && pa.Values[0] is XamlMarkupExtensionNode ext
+                            && ext.Value is XamlAstConstructableObjectNode obj)
                         {
                             inferredDataContextTypeNode = ParseDataContext(context, on, obj);
                         }
                         else if(isDataTemplate
                             && pa.Property.Name == "DataType"
-                            && pa.Values[0] is XamlIlTypeExtensionNode dataTypeNode)
+                            && pa.Values[0] is XamlTypeExtensionNode dataTypeNode)
                         {
                             inferredDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, dataTypeNode.Value.GetClrType());
                         }
@@ -78,7 +78,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     if (isDataTemplate && inferredDataContextTypeNode is null)
                     {
                         // Infer data type from collection binding on a control that displays items.
-                        var parentObject = context.ParentNodes().OfType<XamlIlAstObjectNode>().FirstOrDefault();
+                        var parentObject = context.ParentNodes().OfType<XamlAstConstructableObjectNode>().FirstOrDefault();
                         if (parentObject != null && context.GetAvaloniaTypes().IItemsPresenterHost.IsDirectlyAssignableFrom(parentObject.Type.GetClrType()))
                         {
                             inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject);
@@ -96,10 +96,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             return node;
         }
 
-        private static AvaloniaXamlIlDataContextTypeMetadataNode InferDataContextOfPresentedItem(XamlIlAstTransformationContext context, XamlIlAstObjectNode on, XamlIlAstObjectNode parentObject)
+        private static AvaloniaXamlIlDataContextTypeMetadataNode InferDataContextOfPresentedItem(AstTransformationContext context, XamlAstConstructableObjectNode on, XamlAstConstructableObjectNode parentObject)
         {
             var parentItemsValue = parentObject
-                                            .Children.OfType<XamlIlPropertyAssignmentNode>()
+                                            .Children.OfType<XamlPropertyAssignmentNode>()
                                             .FirstOrDefault(pa => pa.Property.Name == "Items")
                                             ?.Values[0];
             if (parentItemsValue is null)
@@ -109,11 +109,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 return new AvaloniaXamlIlUninferrableDataContextMetadataNode(on);
             }
 
-            IXamlIlType itemsCollectionType = null;
+            IXamlType itemsCollectionType = null;
             if (context.GetAvaloniaTypes().IBinding.IsAssignableFrom(parentItemsValue.Type.GetClrType()))
             {
                 if (parentItemsValue.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension)
-                    && parentItemsValue is XamlIlMarkupExtensionNode ext && ext.Value is XamlIlAstObjectNode parentItemsBinding)
+                    && parentItemsValue is XamlMarkupExtensionNode ext && ext.Value is XamlAstConstructableObjectNode parentItemsBinding)
                 {
                     var parentItemsDataContext = context.ParentNodes().SkipWhile(n => n != parentObject).OfType<AvaloniaXamlIlDataContextTypeMetadataNode>().FirstOrDefault();
                     if (parentItemsDataContext != null)
@@ -141,7 +141,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             return new AvaloniaXamlIlUninferrableDataContextMetadataNode(on);
         }
 
-        private static AvaloniaXamlIlDataContextTypeMetadataNode ParseDataContext(XamlIlAstTransformationContext context, XamlIlAstObjectNode on, XamlIlAstObjectNode obj)
+        private static AvaloniaXamlIlDataContextTypeMetadataNode ParseDataContext(AstTransformationContext context, XamlAstConstructableObjectNode on, XamlAstConstructableObjectNode obj)
         {
             var bindingType = context.GetAvaloniaTypes().IBinding;
             if (!bindingType.IsAssignableFrom(obj.Type.GetClrType()) && !obj.Type.GetClrType().Equals(context.GetAvaloniaTypes().ReflectionBindingExtension))
@@ -150,11 +150,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             }
             else if (obj.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
             {
-                IXamlIlType startType;
+                IXamlType startType;
                 var parentDataContextNode = context.ParentNodes().OfType<AvaloniaXamlIlDataContextTypeMetadataNode>().FirstOrDefault();
                 if (parentDataContextNode is null)
                 {
-                    throw new XamlIlParseException("Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.", obj);
+                    throw new XamlX.XamlParseException("Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.", obj);
                 }
 
                 startType = parentDataContextNode.DataContextType;
@@ -168,11 +168,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
     }
 
     [DebuggerDisplay("DataType = {DataContextType}")]
-    class AvaloniaXamlIlDataContextTypeMetadataNode : XamlIlValueWithSideEffectNodeBase
+    class AvaloniaXamlIlDataContextTypeMetadataNode : XamlValueWithSideEffectNodeBase
     {
-        public virtual IXamlIlType DataContextType { get; }
+        public virtual IXamlType DataContextType { get; }
 
-        public AvaloniaXamlIlDataContextTypeMetadataNode(IXamlIlAstValueNode value, IXamlIlType targetType)
+        public AvaloniaXamlIlDataContextTypeMetadataNode(IXamlAstValueNode value, IXamlType targetType)
             : base(value, value)
         {
             DataContextType = targetType;
@@ -182,11 +182,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
     [DebuggerDisplay("DataType = Unknown")]
     class AvaloniaXamlIlUninferrableDataContextMetadataNode : AvaloniaXamlIlDataContextTypeMetadataNode
     {
-        public AvaloniaXamlIlUninferrableDataContextMetadataNode(IXamlIlAstValueNode value)
+        public AvaloniaXamlIlUninferrableDataContextMetadataNode(IXamlAstValueNode value)
             : base(value, null)
         {
         }
 
-        public override IXamlIlType DataContextType => throw new XamlIlTransformException("Unable to infer DataContext type for compiled bindings nested within this element.", Value);
+        public override IXamlType DataContextType => throw new XamlTransformException("Unable to infer DataContext type for compiled bindings nested within this element.", Value);
     }
 }

+ 13 - 13
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDesignPropertiesTransformer.cs

@@ -1,12 +1,12 @@
 using System.Collections.Generic;
 using System.Linq;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlDesignPropertiesTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlDesignPropertiesTransformer : IXamlAstTransformer
     {
         public bool IsDesignMode { get; set; }
 
@@ -17,14 +17,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         };
 
         private const string AvaloniaNs = "https://github.com/avaloniaui";
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode on)
+            if (node is XamlAstObjectNode on)
             {
                 for (var c=0; c<on.Children.Count;)
                 {
                     var ch = on.Children[c];
-                    if (ch is XamlIlAstXmlDirective directive
+                    if (ch is XamlAstXmlDirective directive
                         && directive.Namespace == XamlNamespaces.Blend2008
                         && DesignDirectives.TryGetValue(directive.Name, out var mapTo))
                     {
@@ -34,9 +34,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                         else
                         {
                             // Map to an actual property in `Design` class
-                            on.Children[c] = new XamlIlAstXamlPropertyValueNode(ch,
-                                new XamlIlAstNamePropertyReference(ch,
-                                    new XamlIlAstXmlTypeReference(ch, AvaloniaNs, "Design"),
+                            on.Children[c] = new XamlAstXamlPropertyValueNode(ch,
+                                new XamlAstNamePropertyReference(ch,
+                                    new XamlAstXmlTypeReference(ch, AvaloniaNs, "Design"),
                                     mapTo, on.Type), directive.Values);
                             c++;
                         }
@@ -44,9 +44,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     // Remove all "Design" attached properties in non-design mode
                     else if (
                         !IsDesignMode
-                        && ch is XamlIlAstXamlPropertyValueNode pv
-                        && pv.Property is XamlIlAstNamePropertyReference pref
-                        && pref.DeclaringType is XamlIlAstXmlTypeReference dref
+                        && ch is XamlAstXamlPropertyValueNode pv
+                        && pv.Property is XamlAstNamePropertyReference pref
+                        && pref.DeclaringType is XamlAstXmlTypeReference dref
                         && dref.XmlNamespace == AvaloniaNs && dref.Name == "Design"
                     )
                     {

+ 4 - 4
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs

@@ -1,12 +1,12 @@
 using System.Linq;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlMetadataRemover : IXamlIlAstTransformer
+    class AvaloniaXamlIlMetadataRemover : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
             if (node is AvaloniaXamlIlTargetTypeMetadataNode targetType)
                 return targetType.Value;

+ 49 - 47
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlPropertyPathTransformer.cs

@@ -2,21 +2,23 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Markup.Parsers;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
+using XamlX.Emit;
+using XamlX.IL;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlPropertyPathTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlPropertyPathTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstXamlPropertyValueNode pv
+            if (node is XamlAstXamlPropertyValueNode pv
                 && pv.Values.Count == 1
-                && pv.Values[0] is XamlIlAstTextNode text
+                && pv.Values[0] is XamlAstTextNode text
                 && pv.Property.GetClrProperty().Getter?.ReturnType
                     .Equals(context.GetAvaloniaTypes().PropertyPath) == true
             )
@@ -24,9 +26,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 var parentScope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
                     .FirstOrDefault();
                 if(parentScope == null)
-                    throw new XamlIlParseException("No target type scope found for property path", text);
+                    throw new XamlX.XamlParseException("No target type scope found for property path", text);
                 if (parentScope.ScopeType != AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style)
-                    throw new XamlIlParseException("PropertyPath is currently only valid for styles", pv);
+                    throw new XamlX.XamlParseException("PropertyPath is currently only valid for styles", pv);
 
 
                 IEnumerable<PropertyPathGrammar.ISyntax> parsed;
@@ -36,11 +38,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 }
                 catch (Exception e)
                 {
-                    throw new XamlIlParseException("Unable to parse PropertyPath: " + e.Message, text);
+                    throw new XamlX.XamlParseException("Unable to parse PropertyPath: " + e.Message, text);
                 }
 
                 var elements = new List<IXamlIlPropertyPathElementNode>();
-                IXamlIlType currentType = parentScope.TargetType.GetClrType();
+                IXamlType currentType = parentScope.TargetType.GetClrType();
                 
                 
                 var expectProperty = true;
@@ -48,16 +50,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 var expectTraversal = false;
                 var types = context.GetAvaloniaTypes();
                 
-                IXamlIlType GetType(string ns, string name)
+                IXamlType GetType(string ns, string name)
                 {
-                    return XamlIlTypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
+                    return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
                         text, true).GetClrType();
                 }
 
                 void HandleProperty(string name, string typeNamespace, string typeName)
                 {
                     if(!expectProperty || currentType == null)
-                        throw new XamlIlParseException("Unexpected property node", text);
+                        throw new XamlX.XamlParseException("Unexpected property node", text);
 
                     var propertySearchType =
                         typeName != null ? GetType(typeNamespace, typeName) : currentType;
@@ -78,7 +80,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     }
 
                     if (prop == null)
-                        throw new XamlIlParseException(
+                        throw new XamlX.XamlParseException(
                             $"Unable to resolve property {name} on type {propertySearchType.GetFqn()}",
                             text);
                     
@@ -93,7 +95,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     if (ge is PropertyPathGrammar.ChildTraversalSyntax)
                     {
                         if (!expectTraversal)
-                            throw new XamlIlParseException("Unexpected child traversal .", text);
+                            throw new XamlX.XamlParseException("Unexpected child traversal .", text);
                         elements.Add(new XamlIlChildTraversalPropertyPathElementNode());
                         expectTraversal = expectCast = false;
                         expectProperty = true;
@@ -101,7 +103,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     else if (ge is PropertyPathGrammar.EnsureTypeSyntax ets)
                     {
                         if(!expectCast)
-                            throw new XamlIlParseException("Unexpected cast node", text);
+                            throw new XamlX.XamlParseException("Unexpected cast node", text);
                         currentType = GetType(ets.TypeNamespace, ets.TypeName);
                         elements.Add(new XamlIlCastPropertyPathElementNode(currentType, true));
                         expectProperty = false;
@@ -110,7 +112,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     else if (ge is PropertyPathGrammar.CastTypeSyntax cts)
                     {
                         if(!expectCast)
-                            throw new XamlIlParseException("Unexpected cast node", text);
+                            throw new XamlX.XamlParseException("Unexpected cast node", text);
                         //TODO: Check if cast can be done
                         currentType = GetType(cts.TypeNamespace, cts.TypeName);
                         elements.Add(new XamlIlCastPropertyPathElementNode(currentType, false));
@@ -126,12 +128,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                         HandleProperty(tqps.Name, tqps.TypeNamespace, tqps.TypeName);
                     }
                     else
-                        throw new XamlIlParseException("Unexpected node " + ge, text);
+                        throw new XamlX.XamlParseException("Unexpected node " + ge, text);
                     
                 }
                 var propertyPathNode = new XamlIlPropertyPathNode(text, elements, types);
                 if (propertyPathNode.Type == null)
-                    throw new XamlIlParseException("Unexpected end of the property path", text);
+                    throw new XamlX.XamlParseException("Unexpected end of the property path", text);
                 pv.Values[0] = propertyPathNode;
             }
 
@@ -140,49 +142,49 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
         interface IXamlIlPropertyPathElementNode
         {
-            void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen);
-            IXamlIlType Type { get; }
+            void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen);
+            IXamlType Type { get; }
         }
 
         class XamlIlChildTraversalPropertyPathElementNode : IXamlIlPropertyPathElementNode
         {
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
                 => codeGen.EmitCall(
                     context.GetAvaloniaTypes()
                         .PropertyPathBuilder.FindMethod(m => m.Name == "ChildTraversal"));
 
-            public IXamlIlType Type => null;
+            public IXamlType Type => null;
         }
         
         class XamlIlAvaloniaPropertyPropertyPathElementNode : IXamlIlPropertyPathElementNode
         {
-            private readonly IXamlIlField _field;
+            private readonly IXamlField _field;
 
-            public XamlIlAvaloniaPropertyPropertyPathElementNode(IXamlIlField field, IXamlIlType propertyType)
+            public XamlIlAvaloniaPropertyPropertyPathElementNode(IXamlField field, IXamlType propertyType)
             {
                 _field = field;
                 Type = propertyType;
             }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
                 => codeGen
                     .Ldsfld(_field)
                     .EmitCall(context.GetAvaloniaTypes()
                         .PropertyPathBuilder.FindMethod(m => m.Name == "Property"));
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
         }
         
         class XamlIClrPropertyPathElementNode : IXamlIlPropertyPathElementNode
         {
-            private readonly IXamlIlProperty _property;
+            private readonly IXamlProperty _property;
 
-            public XamlIClrPropertyPathElementNode(IXamlIlProperty property)
+            public XamlIClrPropertyPathElementNode(IXamlProperty property)
             {
                 _property = property;
             }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
             {
                 context.Configuration.GetExtra<XamlIlClrPropertyInfoEmitter>()
                     .Emit(context, codeGen, _property);
@@ -191,21 +193,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     .PropertyPathBuilder.FindMethod(m => m.Name == "Property"));
             }
 
-            public IXamlIlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0];
+            public IXamlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0];
         }
 
         class XamlIlCastPropertyPathElementNode : IXamlIlPropertyPathElementNode
         {
-            private readonly IXamlIlType _type;
+            private readonly IXamlType _type;
             private readonly bool _ensureType;
 
-            public XamlIlCastPropertyPathElementNode(IXamlIlType type, bool ensureType)
+            public XamlIlCastPropertyPathElementNode(IXamlType type, bool ensureType)
             {
                 _type = type;
                 _ensureType = ensureType;
             }
             
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
             {
                 codeGen
                     .Ldtype(_type)
@@ -213,39 +215,39 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                         .PropertyPathBuilder.FindMethod(m => m.Name == (_ensureType ? "EnsureType" : "Cast")));
             }
 
-            public IXamlIlType Type => _type;
+            public IXamlType Type => _type;
         }
 
-        class XamlIlPropertyPathNode : XamlIlAstNode, IXamlIlPropertyPathNode, IXamlIlAstEmitableNode
+        class XamlIlPropertyPathNode : XamlAstNode, IXamlIlPropertyPathNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
         {
             private readonly List<IXamlIlPropertyPathElementNode> _elements;
             private readonly AvaloniaXamlIlWellKnownTypes _types;
 
-            public XamlIlPropertyPathNode(IXamlIlLineInfo lineInfo,
+            public XamlIlPropertyPathNode(IXamlLineInfo lineInfo,
                 List<IXamlIlPropertyPathElementNode> elements,
                 AvaloniaXamlIlWellKnownTypes types) : base(lineInfo)
             {
                 _elements = elements;
                 _types = types;
-                Type = new XamlIlAstClrTypeReference(this, types.PropertyPath, false);
+                Type = new XamlAstClrTypeReference(this, types.PropertyPath, false);
             }
 
-            public IXamlIlAstTypeReference Type { get; }
-            public IXamlIlType PropertyType => _elements.LastOrDefault()?.Type;
-            public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public IXamlAstTypeReference Type { get; }
+            public IXamlType PropertyType => _elements.LastOrDefault()?.Type;
+            public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
             {
                 codeGen
                     .Newobj(_types.PropertyPathBuilder.FindConstructor());
                 foreach(var e in _elements)
                     e.Emit(context, codeGen);
                 codeGen.EmitCall(_types.PropertyPathBuilder.FindMethod(m => m.Name == "Build"));
-                return XamlIlNodeEmitResult.Type(0, _types.PropertyPath);
+                return XamlILNodeEmitResult.Type(0, _types.PropertyPath);
             }
         }
     }
 
-    interface IXamlIlPropertyPathNode : IXamlIlAstValueNode
+    interface IXamlIlPropertyPathNode : IXamlAstValueNode
     {
-        IXamlIlType PropertyType { get; }
+        IXamlType PropertyType { get; }
     }
 }

+ 27 - 18
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlRootObjectScopeTransformer.cs

@@ -1,20 +1,22 @@
 using System;
 using System.Linq;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+using XamlX.IL;
+using XamlX.Emit;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlRootObjectScope : IXamlIlAstTransformer
+    class AvaloniaXamlIlRootObjectScope : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
             if (!context.ParentNodes().Any()
-                && node is XamlIlValueWithManipulationNode mnode)
+                && node is XamlValueWithManipulationNode mnode)
             {
-                mnode.Manipulation = new XamlIlManipulationGroupNode(mnode,
+                mnode.Manipulation = new XamlManipulationGroupNode(mnode,
                     new[]
                     {
                         mnode.Manipulation,
@@ -23,41 +25,48 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             }
             return node;
         }
-        class HandleRootObjectScopeNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode
+        class HandleRootObjectScopeNode : XamlAstNode, IXamlAstManipulationNode
         {
             private readonly AvaloniaXamlIlWellKnownTypes _types;
 
-            public HandleRootObjectScopeNode(IXamlIlLineInfo lineInfo,
+            public HandleRootObjectScopeNode(IXamlLineInfo lineInfo,
                 AvaloniaXamlIlWellKnownTypes types) : base(lineInfo)
             {
                 _types = types;
             }
-
-            public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        }
+        internal class Emitter : IXamlILAstNodeEmitter
+        {
+            public XamlILNodeEmitResult Emit(IXamlAstNode node, XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
             {
+                if (!(node is HandleRootObjectScopeNode))
+                {
+                    return null;
+                }
+                var types = context.GetAvaloniaTypes();
+                
                 var next = codeGen.DefineLabel();
                 var scopeField = context.RuntimeContext.ContextType.Fields.First(f =>
                     f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName);
-                using (var local = codeGen.LocalsPool.GetLocal(_types.StyledElement))
+                using (var local = codeGen.LocalsPool.GetLocal(types.StyledElement))
                 {
                     codeGen
-                        .Isinst(_types.StyledElement)
+                        .Isinst(types.StyledElement)
                         .Dup()
                         .Stloc(local.Local)
                         .Brfalse(next)
                         .Ldloc(local.Local)
                         .Ldloc(context.ContextLocal)
                         .Ldfld(scopeField)
-                        .EmitCall(_types.NameScopeSetNameScope, true)
+                        .EmitCall(types.NameScopeSetNameScope, true)
                         .MarkLabel(next)
                         .Ldloc(context.ContextLocal)
                         .Ldfld(scopeField)
-                        .EmitCall(_types.INameScopeComplete, true);
+                        .EmitCall(types.INameScopeComplete, true);
                 }
 
-                return XamlIlNodeEmitResult.Void(1);
+                return XamlILNodeEmitResult.Void(1);
             }
         }
-
     }
 }

+ 61 - 57
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@@ -3,41 +3,45 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using Avalonia.Markup.Parsers;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlSelectorTransformer : IXamlIlAstTransformer
+    using XamlParseException = XamlX.XamlParseException;
+    using XamlLoadException = XamlX.XamlLoadException;
+    class AvaloniaXamlIlSelectorTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (!(node is XamlIlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Style"))
+            if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Style"))
                 return node;
 
-            var pn = on.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+            var pn = on.Children.OfType<XamlAstXamlPropertyValueNode>()
                 .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");
 
             if (pn == null)
                 return node;
 
             if (pn.Values.Count != 1)
-                throw new XamlIlParseException("Selector property should should have exactly one value", node);
+                throw new XamlParseException("Selector property should should have exactly one value", node);
             
             if (pn.Values[0] is XamlIlSelectorNode)
                 //Deja vu. I've just been in this place before
                 return node;
             
-            if (!(pn.Values[0] is XamlIlAstTextNode tn))
-                throw new XamlIlParseException("Selector property should be a text node", node);
+            if (!(pn.Values[0] is XamlAstTextNode tn))
+                throw new XamlParseException("Selector property should be a text node", node);
 
             var selectorType = pn.Property.GetClrProperty().Getter.ReturnType;
             var initialNode = new XamlIlSelectorInitialNode(node, selectorType);
             XamlIlSelectorNode Create(IEnumerable<SelectorGrammar.ISyntax> syntax,
-                Func<string, string, XamlIlAstClrTypeReference> typeResolver)
+                Func<string, string, XamlAstClrTypeReference> typeResolver)
             {
                 XamlIlSelectorNode result = initialNode;
                 XamlIlOrSelectorNode results = null;
@@ -63,18 +67,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                             var type = result?.TargetType;
 
                             if (type == null)
-                                throw new XamlIlParseException("Property selectors must be applied to a type.", node);
+                                throw new XamlParseException("Property selectors must be applied to a type.", node);
 
                             var targetProperty =
                                 type.GetAllProperties().FirstOrDefault(p => p.Name == property.Property);
 
                             if (targetProperty == null)
-                                throw new XamlIlParseException($"Cannot find '{property.Property}' on '{type}", node);
+                                throw new XamlParseException($"Cannot find '{property.Property}' on '{type}", node);
 
-                            if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context,
-                                new XamlIlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String),
+                            if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context,
+                                new XamlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String),
                                 targetProperty.PropertyType, out var typedValue))
-                                throw new XamlIlParseException(
+                                throw new XamlParseException(
                                     $"Cannot convert '{property.Value}' to '{targetProperty.PropertyType.GetFqn()}",
                                     node);
 
@@ -100,7 +104,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                             result = initialNode;
                             break;
                         default:
-                            throw new XamlIlParseException($"Unsupported selector grammar '{i.GetType()}'.", node);
+                            throw new XamlParseException($"Unsupported selector grammar '{i.GetType()}'.", node);
                     }
                 }
 
@@ -119,15 +123,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             }
             catch (Exception e)
             {
-                throw new XamlIlParseException("Unable to parse selector: " + e.Message, node);
+                throw new XamlParseException("Unable to parse selector: " + e.Message, node);
             }
 
             var selector = Create(parsed, (p, n) 
-                => XamlIlTypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true));
+                => TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true));
             pn.Values[0] = selector;
 
             return new AvaloniaXamlIlTargetTypeMetadataNode(on,
-                new XamlIlAstClrTypeReference(selector, selector.TargetType, false),
+                new XamlAstClrTypeReference(selector, selector.TargetType, false),
                 AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
         }
 
@@ -135,32 +139,32 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
 
     
-    abstract class XamlIlSelectorNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode
+    abstract class XamlIlSelectorNode : XamlAstNode, IXamlAstValueNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
     {
         protected XamlIlSelectorNode Previous { get; }
-        public abstract IXamlIlType TargetType { get; }
+        public abstract IXamlType TargetType { get; }
 
         public XamlIlSelectorNode(XamlIlSelectorNode previous,
-            IXamlIlLineInfo info = null,
-            IXamlIlType selectorType = null) : base(info ?? previous)
+            IXamlLineInfo info = null,
+            IXamlType selectorType = null) : base(info ?? previous)
         {
             Previous = previous;
-            Type = selectorType == null ? previous.Type : new XamlIlAstClrTypeReference(this, selectorType, false);
+            Type = selectorType == null ? previous.Type : new XamlAstClrTypeReference(this, selectorType, false);
         }
 
-        public IXamlIlAstTypeReference Type { get; }
+        public IXamlAstTypeReference Type { get; }
 
-        public virtual XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public virtual XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             if (Previous != null)
                 context.Emit(Previous, codeGen, Type.GetClrType());
             DoEmit(context, codeGen);
-            return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
+            return XamlILNodeEmitResult.Type(0, Type.GetClrType());
         }
         
-        protected abstract void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen);
+        protected abstract void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen);
 
-        protected void EmitCall(XamlIlEmitContext context, IXamlIlEmitter codeGen, Func<IXamlIlMethod, bool> method)
+        protected void EmitCall(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, Func<IXamlMethod, bool> method)
         {
             var selectors = context.Configuration.TypeSystem.GetType("Avalonia.Styling.Selectors");
             var found = selectors.FindMethod(m => m.IsStatic && m.Parameters.Count > 0 && method(m));
@@ -170,27 +174,27 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
     
     class XamlIlSelectorInitialNode : XamlIlSelectorNode
     {
-        public XamlIlSelectorInitialNode(IXamlIlLineInfo info,
-            IXamlIlType selectorType) : base(null, info, selectorType)
+        public XamlIlSelectorInitialNode(IXamlLineInfo info,
+            IXamlType selectorType) : base(null, info, selectorType)
         {
         }
 
-        public override IXamlIlType TargetType => null;
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) => codeGen.Ldnull();
+        public override IXamlType TargetType => null;
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) => codeGen.Ldnull();
     }
 
     class XamlIlTypeSelector : XamlIlSelectorNode
     {
         public bool Concrete { get; }
 
-        public XamlIlTypeSelector(XamlIlSelectorNode previous, IXamlIlType type, bool concrete) : base(previous)
+        public XamlIlTypeSelector(XamlIlSelectorNode previous, IXamlType type, bool concrete) : base(previous)
         {
             TargetType = type;
             Concrete = concrete;
         }
 
-        public override IXamlIlType TargetType { get; }
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public override IXamlType TargetType { get; }
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             var name = Concrete ? "OfType" : "Is";
             codeGen.Ldtype(TargetType);
@@ -217,8 +221,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         }
 
 
-        public override IXamlIlType TargetType => Previous?.TargetType;
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public override IXamlType TargetType => Previous?.TargetType;
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             codeGen.Ldstr(String);
             var name = _type.ToString();
@@ -242,8 +246,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             _type = type;
         }
 
-        public override IXamlIlType TargetType => null;
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public override IXamlType TargetType => null;
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             var name = _type.ToString();
             EmitCall(context, codeGen,
@@ -260,8 +264,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             Argument = argument;
         }
 
-        public override IXamlIlType TargetType => Previous?.TargetType;
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public override IXamlType TargetType => Previous?.TargetType;
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             context.Emit(Argument, codeGen, Type.GetClrType());
             EmitCall(context, codeGen,
@@ -272,22 +276,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
     class XamlIlPropertyEqualsSelector : XamlIlSelectorNode
     {
         public XamlIlPropertyEqualsSelector(XamlIlSelectorNode previous,
-            IXamlIlProperty property,
-            IXamlIlAstValueNode value)
+            IXamlProperty property,
+            IXamlAstValueNode value)
             : base(previous)
         {
             Property = property;
             Value = value;
         }
 
-        public IXamlIlProperty Property { get; set; }
-        public IXamlIlAstValueNode Value { get; set; }
+        public IXamlProperty Property { get; set; }
+        public IXamlAstValueNode Value { get; set; }
         
-        public override IXamlIlType TargetType => Previous?.TargetType;
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public override IXamlType TargetType => Previous?.TargetType;
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property))
-                throw new XamlIlLoadException(
+                throw new XamlLoadException(
                     $"{Property.Name} of {(Property.Setter ?? Property.Getter).DeclaringType.GetFqn()} doesn't seem to be an AvaloniaProperty",
                     this);
             context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object);
@@ -302,7 +306,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
     class XamlIlOrSelectorNode : XamlIlSelectorNode
     {
         List<XamlIlSelectorNode> _selectors = new List<XamlIlSelectorNode>();
-        public XamlIlOrSelectorNode(IXamlIlLineInfo info, IXamlIlType selectorType) : base(null, info, selectorType)
+        public XamlIlOrSelectorNode(IXamlLineInfo info, IXamlType selectorType) : base(null, info, selectorType)
         {
         }
 
@@ -311,11 +315,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             _selectors.Add(node);
         }
         
-        public override IXamlIlType TargetType
+        public override IXamlType TargetType
         {
             get
             {
-                IXamlIlType result = null;
+                IXamlType result = null;
 
                 foreach (var selector in _selectors)
                 {
@@ -340,10 +344,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             }
         }
 
-        protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
         {
             if (_selectors.Count == 0)
-                throw new XamlIlLoadException("Invalid selector count", this);
+                throw new XamlLoadException("Invalid selector count", this);
             if (_selectors.Count == 1)
             {
                 _selectors[0].Emit(context, codeGen);

+ 39 - 35
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@@ -2,74 +2,78 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Data.Core;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlSetterTransformer : IXamlIlAstTransformer
+    using XamlParseException = XamlX.XamlParseException;
+    using XamlLoadException = XamlX.XamlLoadException;
+    class AvaloniaXamlIlSetterTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (!(node is XamlIlAstObjectNode on
+            if (!(node is XamlAstObjectNode on
                   && on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
                 return node;
 
-            var parent = context.ParentNodes().OfType<XamlIlAstObjectNode>()
+            var parent = context.ParentNodes().OfType<XamlAstObjectNode>()
                 .FirstOrDefault(p => p.Type.GetClrType().FullName == "Avalonia.Styling.Style");
             
             if (parent == null)
-                throw new XamlIlParseException(
+                throw new XamlParseException(
                     "Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node);
-            var selectorProperty = parent.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+            var selectorProperty = parent.Children.OfType<XamlAstXamlPropertyValueNode>()
                 .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");
             if (selectorProperty == null)
-                throw new XamlIlParseException(
+                throw new XamlParseException(
                     "Can not find parent Style Selector", node);
             var selector = selectorProperty.Values.FirstOrDefault() as XamlIlSelectorNode;
             if (selector?.TargetType == null)
-                throw new XamlIlParseException(
+                throw new XamlParseException(
                     "Can not resolve parent Style Selector type", node);
 
-            IXamlIlType propType = null;
-            var property = @on.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+            IXamlType propType = null;
+            var property = @on.Children.OfType<XamlAstXamlPropertyValueNode>()
                 .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property");
             if (property != null)
             {
 
-                var propertyName = property.Values.OfType<XamlIlAstTextNode>().FirstOrDefault()?.Text;
+                var propertyName = property.Values.OfType<XamlAstTextNode>().FirstOrDefault()?.Text;
                 if (propertyName == null)
-                    throw new XamlIlParseException("Setter.Property must be a string", node);
+                    throw new XamlParseException("Setter.Property must be a string", node);
 
 
                 var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName,
-                    new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]);
-                property.Values = new List<IXamlIlAstValueNode> {avaloniaPropertyNode};
+                    new XamlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]);
+                property.Values = new List<IXamlAstValueNode> {avaloniaPropertyNode};
                 propType = avaloniaPropertyNode.AvaloniaPropertyType;
             }
             else
             {
-                var propertyPath = on.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+                var propertyPath = on.Children.OfType<XamlAstXamlPropertyValueNode>()
                     .FirstOrDefault(x => x.Property.GetClrProperty().Name == "PropertyPath");
                 if (propertyPath == null)
-                    throw new XamlIlParseException("Setter without a property or property path is not valid", node);
+                    throw new XamlX.XamlParseException("Setter without a property or property path is not valid", node);
                 if (propertyPath.Values[0] is IXamlIlPropertyPathNode ppn
                     && ppn.PropertyType != null)
                     propType = ppn.PropertyType;
                 else
-                    throw new XamlIlParseException("Unable to get the property path property type", node);
+                    throw new XamlX.XamlParseException("Unable to get the property path property type", node);
             }
 
             var valueProperty = on.Children
-                .OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
-            if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode)
+                .OfType<XamlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
+            if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlAstTextNode)
             {
-                if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
+                if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
                         propType, out var converted))
-                    throw new XamlIlParseException(
+                    throw new XamlParseException(
                         $"Unable to convert property value to {propType.GetFqn()}",
                         valueProperty.Values[0]);
 
@@ -80,9 +84,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             return node;
         }
 
-        class SetterValueProperty : XamlIlAstClrProperty
+        class SetterValueProperty : XamlAstClrProperty
         {
-            public SetterValueProperty(IXamlIlLineInfo line, IXamlIlType setterType, IXamlIlType targetType,
+            public SetterValueProperty(IXamlLineInfo line, IXamlType setterType, IXamlType targetType,
                 AvaloniaXamlIlWellKnownTypes types)
                 : base(line, "Value", setterType, null)
             {
@@ -93,21 +97,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType));
             }
             
-            class XamlIlDirectCallPropertySetter : IXamlIlPropertySetter
+            class XamlIlDirectCallPropertySetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
             {
-                private readonly IXamlIlMethod _method;
-                private readonly IXamlIlType _type;
-                public IXamlIlType TargetType { get; }
+                private readonly IXamlMethod _method;
+                private readonly IXamlType _type;
+                public IXamlType TargetType { get; }
                 public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
-                public IReadOnlyList<IXamlIlType> Parameters { get; }
-                public void Emit(IXamlIlEmitter codegen)
+                public IReadOnlyList<IXamlType> Parameters { get; }
+                public void Emit(IXamlILEmitter codegen)
                 {
                     if (_type.IsValueType)
                         codegen.Box(_type);
                     codegen.EmitCall(_method, true);
                 }
 
-                public XamlIlDirectCallPropertySetter(IXamlIlMethod method, IXamlIlType type)
+                public XamlIlDirectCallPropertySetter(IXamlMethod method, IXamlType type)
                 {
                     _method = method;
                     _type = type;

+ 40 - 38
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs

@@ -1,20 +1,22 @@
 using System.Collections.Generic;
 using System.Linq;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlTransformInstanceAttachedProperties : IXamlIlAstTransformer
+    class AvaloniaXamlIlTransformInstanceAttachedProperties : IXamlAstTransformer
     {
 
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstNamePropertyReference prop 
-                && prop.TargetType is XamlIlAstClrTypeReference targetRef 
-                && prop.DeclaringType is XamlIlAstClrTypeReference declaringRef)
+            if (node is XamlAstNamePropertyReference prop 
+                && prop.TargetType is XamlAstClrTypeReference targetRef 
+                && prop.DeclaringType is XamlAstClrTypeReference declaringRef)
             {
                 // Target and declared type aren't assignable but both inherit from AvaloniaObject
                 var avaloniaObject = context.Configuration.TypeSystem.FindType("Avalonia.AvaloniaObject");
@@ -70,21 +72,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             return node;
         }
 
-        class AvaloniaAttachedInstanceProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty
+        class AvaloniaAttachedInstanceProperty : XamlAstClrProperty, IXamlIlAvaloniaProperty
         {
-            private readonly XamlIlTransformerConfiguration _config;
-            private readonly IXamlIlType _declaringType;
-            private readonly IXamlIlType _avaloniaPropertyType;
-            private readonly IXamlIlType _avaloniaObject;
-            private readonly IXamlIlField _field;
-
-            public AvaloniaAttachedInstanceProperty(XamlIlAstNamePropertyReference prop,
-                XamlIlTransformerConfiguration config,
-                IXamlIlType declaringType,
-                IXamlIlType type,
-                IXamlIlType avaloniaPropertyType,
-                IXamlIlType avaloniaObject,
-                IXamlIlField field) : base(prop, prop.Name,
+            private readonly TransformerConfiguration _config;
+            private readonly IXamlType _declaringType;
+            private readonly IXamlType _avaloniaPropertyType;
+            private readonly IXamlType _avaloniaObject;
+            private readonly IXamlField _field;
+
+            public AvaloniaAttachedInstanceProperty(XamlAstNamePropertyReference prop,
+                TransformerConfiguration config,
+                IXamlType declaringType,
+                IXamlType type,
+                IXamlType avaloniaPropertyType,
+                IXamlType avaloniaObject,
+                IXamlField field) : base(prop, prop.Name,
                 declaringType, null)
             
             
@@ -104,11 +106,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 Getter = new GetterMethod(this);
             }
 
-            public IXamlIlType PropertyType { get;  }
+            public IXamlType PropertyType { get;  }
 
-            public IXamlIlField AvaloniaProperty => _field;
+            public IXamlField AvaloniaProperty => _field;
             
-            class SetterMethod : IXamlIlPropertySetter
+            class SetterMethod : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
             {
                 private readonly AvaloniaAttachedInstanceProperty _parent;
 
@@ -118,10 +120,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     Parameters = new[] {_parent._avaloniaObject, _parent.PropertyType};
                 }
 
-                public IXamlIlType TargetType => _parent.DeclaringType;
+                public IXamlType TargetType => _parent.DeclaringType;
                 public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
-                public IReadOnlyList<IXamlIlType> Parameters { get; }
-                public void Emit(IXamlIlEmitter emitter)
+                public IReadOnlyList<IXamlType> Parameters { get; }
+                public void Emit(IXamlILEmitter emitter)
                 {
                     var so = _parent._config.WellKnownTypes.Object;
                     var method = _parent._avaloniaObject
@@ -133,7 +135,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                                          && m.Parameters[2].IsEnum
                         );
                     if (method == null)
-                        throw new XamlIlTypeSystemException(
+                        throw new XamlTypeSystemException(
                             "Unable to find SetValue(AvaloniaProperty, object, BindingPriority) on AvaloniaObject");
                     using (var loc = emitter.LocalsPool.GetLocal(_parent.PropertyType))
                         emitter
@@ -150,7 +152,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 }
             }
 
-            class GetterMethod :  IXamlIlCustomEmitMethod
+            class GetterMethod :  IXamlCustomEmitMethod<IXamlILEmitter>
             {
                 public GetterMethod(AvaloniaAttachedInstanceProperty parent) 
                 {
@@ -163,16 +165,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                 public bool IsPublic => true;
                 public bool IsStatic => true;
                 public string Name { get; protected set; }
-                public IXamlIlType DeclaringType { get; }
-                public IXamlIlMethod MakeGenericMethod(IReadOnlyList<IXamlIlType> typeArguments) 
+                public IXamlType DeclaringType { get; }
+                public IXamlMethod MakeGenericMethod(IReadOnlyList<IXamlType> typeArguments) 
                     => throw new System.NotSupportedException();
 
 
-                public bool Equals(IXamlIlMethod other) =>
+                public bool Equals(IXamlMethod other) =>
                     other is GetterMethod m && m.Name == Name && m.DeclaringType.Equals(DeclaringType);
-                public IXamlIlType ReturnType => Parent.PropertyType;
-                public IReadOnlyList<IXamlIlType> Parameters { get; }
-                public void EmitCall(IXamlIlEmitter emitter)
+                public IXamlType ReturnType => Parent.PropertyType;
+                public IReadOnlyList<IXamlType> Parameters { get; }
+                public void EmitCall(IXamlILEmitter emitter)
                 {
                     var method = Parent._avaloniaObject
                         .FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "GetValue"
@@ -180,7 +182,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                                          m.Parameters.Count == 1
                                          && m.Parameters[0].Equals(Parent._avaloniaPropertyType));
                     if (method == null)
-                        throw new XamlIlTypeSystemException(
+                        throw new XamlTypeSystemException(
                             "Unable to find T GetValue<T>(AvaloniaProperty<T>) on AvaloniaObject");
                     emitter
                         .Ldsfld(Parent._field)

+ 9 - 9
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs

@@ -1,18 +1,18 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlTransformSyntheticCompiledBindingMembers : IXamlIlAstTransformer
+    class AvaloniaXamlIlTransformSyntheticCompiledBindingMembers : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstNamePropertyReference prop
-               && prop.TargetType is XamlIlAstClrTypeReference targetRef
+            if (node is XamlAstNamePropertyReference prop
+               && prop.TargetType is XamlAstClrTypeReference targetRef
                && targetRef.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
             {
                 if (prop.Name == "ElementName")
@@ -43,12 +43,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         Source
     }
 
-    class AvaloniaSyntheticCompiledBindingProperty : XamlIlAstNode, IXamlIlAstPropertyReference
+    class AvaloniaSyntheticCompiledBindingProperty : XamlAstNode, IXamlAstPropertyReference
     {
         public SyntheticCompiledBindingPropertyName Name { get; }
 
         public AvaloniaSyntheticCompiledBindingProperty(
-            IXamlIlLineInfo lineInfo,
+            IXamlLineInfo lineInfo,
             SyntheticCompiledBindingPropertyName name)
             : base(lineInfo)
         {

+ 6 - 6
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs

@@ -1,17 +1,17 @@
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class AvaloniaXamlIlTransitionsTypeMetadataTransformer : IXamlIlAstTransformer
+    class AvaloniaXamlIlTransitionsTypeMetadataTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode on)
+            if (node is XamlAstObjectNode on)
             {
                 foreach (var ch in on.Children)
                 {
-                    if (ch is XamlIlAstXamlPropertyValueNode pn
+                    if (ch is XamlAstXamlPropertyValueNode pn
                         && pn.Property.GetClrProperty().Getter?.ReturnType.Equals(context.GetAvaloniaTypes().Transitions) == true)
                     {
                         for (var c = 0; c < pn.Values.Count; c++)

+ 41 - 39
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@@ -1,47 +1,49 @@
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Emit;
+using XamlX.IL;
+using XamlX.Transform;
+using XamlX.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
     class AvaloniaXamlIlWellKnownTypes
     {
-        public IXamlIlType AvaloniaObject { get; }
-        public IXamlIlType IAvaloniaObject { get; }
-        public IXamlIlType BindingPriority { get; }
-        public IXamlIlType AvaloniaObjectExtensions { get; }
-        public IXamlIlType AvaloniaProperty { get; }
-        public IXamlIlType AvaloniaPropertyT { get; }
-        public IXamlIlType IBinding { get; }
-        public IXamlIlMethod AvaloniaObjectBindMethod { get; }
-        public IXamlIlMethod AvaloniaObjectSetValueMethod { get; }
-        public IXamlIlType IDisposable { get; }
-        public XamlIlTypeWellKnownTypes XamlIlTypes { get; }
-        public XamlIlLanguageTypeMappings XamlIlMappings { get; }
-        public IXamlIlType Transitions { get; }
-        public IXamlIlType AssignBindingAttribute { get; }
-        public IXamlIlType UnsetValueType { get; }
-        public IXamlIlType StyledElement { get; }
-        public IXamlIlType NameScope { get; }
-        public IXamlIlMethod NameScopeSetNameScope { get; }
-        public IXamlIlType INameScope { get; }
-        public IXamlIlMethod INameScopeRegister { get; }
-        public IXamlIlMethod INameScopeComplete { get; }
-        public IXamlIlType IPropertyInfo { get; }
-        public IXamlIlType ClrPropertyInfo { get; }
-        public IXamlIlType PropertyPath { get; }
-        public IXamlIlType PropertyPathBuilder { get; }
-        public IXamlIlType IPropertyAccessor { get; }
-        public IXamlIlType PropertyInfoAccessorFactory { get; }
-        public IXamlIlType CompiledBindingPathBuilder { get; }
-        public IXamlIlType CompiledBindingPath { get; }
-        public IXamlIlType CompiledBindingExtension { get; }
-        public IXamlIlType DataTemplate { get; }
-        public IXamlIlType IItemsPresenterHost { get; }
-        public IXamlIlType ReflectionBindingExtension { get; }
+        public IXamlType AvaloniaObject { get; }
+        public IXamlType IAvaloniaObject { get; }
+        public IXamlType BindingPriority { get; }
+        public IXamlType AvaloniaObjectExtensions { get; }
+        public IXamlType AvaloniaProperty { get; }
+        public IXamlType AvaloniaPropertyT { get; }
+        public IXamlType IBinding { get; }
+        public IXamlMethod AvaloniaObjectBindMethod { get; }
+        public IXamlMethod AvaloniaObjectSetValueMethod { get; }
+        public IXamlType IDisposable { get; }
+        public XamlTypeWellKnownTypes XamlIlTypes { get; }
+        public XamlLanguageTypeMappings XamlIlMappings { get; }
+        public IXamlType Transitions { get; }
+        public IXamlType AssignBindingAttribute { get; }
+        public IXamlType UnsetValueType { get; }
+        public IXamlType StyledElement { get; }
+        public IXamlType NameScope { get; }
+        public IXamlMethod NameScopeSetNameScope { get; }
+        public IXamlType INameScope { get; }
+        public IXamlMethod INameScopeRegister { get; }
+        public IXamlMethod INameScopeComplete { get; }
+        public IXamlType IPropertyInfo { get; }
+        public IXamlType ClrPropertyInfo { get; }
+        public IXamlType PropertyPath { get; }
+        public IXamlType PropertyPathBuilder { get; }
+        public IXamlType IPropertyAccessor { get; }
+        public IXamlType PropertyInfoAccessorFactory { get; }
+        public IXamlType CompiledBindingPathBuilder { get; }
+        public IXamlType CompiledBindingPath { get; }
+        public IXamlType CompiledBindingExtension { get; }
+        public IXamlType DataTemplate { get; }
+        public IXamlType IItemsPresenterHost { get; }
+        public IXamlType ReflectionBindingExtension { get; }
 
-        public IXamlIlType RelativeSource { get; }
+        public IXamlType RelativeSource { get; }
 
-        public AvaloniaXamlIlWellKnownTypes(XamlIlTransformerConfiguration cfg)
+        public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
         {
             XamlIlTypes = cfg.WellKnownTypes;
             AvaloniaObject = cfg.TypeSystem.GetType("Avalonia.AvaloniaObject");
@@ -99,7 +101,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
     static class AvaloniaXamlIlWellKnownTypesExtensions
     {
-        public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlIlAstTransformationContext ctx)
+        public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this AstTransformationContext ctx)
         {
             if (ctx.TryGetItem<AvaloniaXamlIlWellKnownTypes>(out var rv))
                 return rv;
@@ -107,7 +109,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             return rv;
         }
         
-        public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlIlEmitContext ctx)
+        public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> ctx)
         {
             if (ctx.TryGetItem<AvaloniaXamlIlWellKnownTypes>(out var rv))
                 return rv;

+ 7 - 7
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/IgnoredDirectivesTransformer.cs

@@ -1,17 +1,17 @@
 using System.Linq;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class IgnoredDirectivesTransformer : IXamlIlAstTransformer
+    class IgnoredDirectivesTransformer : IXamlAstTransformer
     {
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode no)
+            if (node is XamlAstObjectNode no)
             {
-                foreach (var d in no.Children.OfType<XamlIlAstXmlDirective>().ToList())
+                foreach (var d in no.Children.OfType<XamlAstXmlDirective>().ToList())
                 {
                     if (d.Namespace == XamlNamespaces.Xaml2006)
                     {

+ 9 - 10
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/XNameTransformer.cs

@@ -1,30 +1,29 @@
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 {
-    class XNameTransformer : IXamlIlAstTransformer
+    class XNameTransformer : IXamlAstTransformer
     {
-        
         /// <summary>
         /// Converts x:Name directives to regular Name assignments
         /// </summary>
         /// <returns></returns>
-        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
         {
-            if (node is XamlIlAstObjectNode on)
+            if (node is XamlAstObjectNode on)
             {
                 for (var c =0; c< on.Children.Count;c++)
                 {
                     var ch = on.Children[c];
-                    if (ch is XamlIlAstXmlDirective d
+                    if (ch is XamlAstXmlDirective d
                         && d.Namespace == XamlNamespaces.Xaml2006
                         && d.Name == "Name")
 
 
-                        on.Children[c] = new XamlIlAstXamlPropertyValueNode(d,
-                            new XamlIlAstNamePropertyReference(d, on.Type, "Name", on.Type),
+                        on.Children[c] = new XamlAstXamlPropertyValueNode(d,
+                            new XamlAstNamePropertyReference(d, on.Type, "Name", on.Type),
                             d.Values);
                 }
             }

+ 58 - 53
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@@ -5,18 +5,23 @@ using System.Xml;
 using Avalonia.Markup.Xaml.Parsers;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
 using Avalonia.Utilities;
-using XamlIl;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
+using XamlX;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
+using XamlX.Emit;
+using XamlX.IL;
+
+using XamlIlEmitContext = XamlX.Emit.XamlEmitContext<XamlX.IL.IXamlILEmitter, XamlX.IL.XamlILNodeEmitResult>;
+using IXamlIlAstEmitableNode = XamlX.Emit.IXamlAstEmitableNode<XamlX.IL.IXamlILEmitter, XamlX.IL.XamlILNodeEmitResult>;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
     class XamlIlAvaloniaPropertyHelper
     {
-        public static bool EmitProvideValueTarget(XamlIlEmitContext context, IXamlIlEmitter emitter,
-            XamlIlAstClrProperty property)
+        public static bool EmitProvideValueTarget(XamlIlEmitContext context, IXamlILEmitter emitter,
+            XamlAstClrProperty property)
         {
             if (Emit(context, emitter, property))
                 return true;
@@ -29,7 +34,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return true;
         }
         
-        public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, XamlIlAstClrProperty property)
+        public static bool Emit(XamlIlEmitContext context, IXamlILEmitter emitter, XamlAstClrProperty property)
         {
             if (property is IXamlIlAvaloniaProperty ap)
             {
@@ -46,7 +51,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return true;
         }
         
-        public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, IXamlIlProperty property)
+        public static bool Emit(XamlIlEmitContext context, IXamlILEmitter emitter, IXamlProperty property)
         {
             var type = (property.Getter ?? property.Setter).DeclaringType;
             var name = property.Name + "Property";
@@ -58,16 +63,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return true;
         }
 
-        public static IXamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context,
-            string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo)
+        public static IXamlIlAvaloniaPropertyNode CreateNode(AstTransformationContext context,
+            string propertyName, IXamlAstTypeReference selectorTypeReference, IXamlLineInfo lineInfo)
         {
-            XamlIlAstNamePropertyReference forgedReference;
+            XamlAstNamePropertyReference forgedReference;
             
             var parser = new PropertyParser();
             
             var parsedPropertyName = parser.Parse(new CharacterReader(propertyName.AsSpan()));
             if(parsedPropertyName.owner == null)
-                forgedReference = new XamlIlAstNamePropertyReference(lineInfo, selectorTypeReference,
+                forgedReference = new XamlAstNamePropertyReference(lineInfo, selectorTypeReference,
                     propertyName, selectorTypeReference);
             else
             {
@@ -76,27 +81,27 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                     xmlOwner += ":";
                 xmlOwner += parsedPropertyName.owner;
                 
-                var tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);
+                var tref = TypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);
 
                 var propertyFieldName = parsedPropertyName.name + "Property";
                 var found = tref.Type.GetAllFields()
                     .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName);
                 if (found == null)
-                    throw new XamlIlParseException(
+                    throw new XamlX.XamlParseException(
                         $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo);
                 return new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found);
             }
 
             var clrProperty =
-                ((XamlIlAstClrProperty)new XamlIlPropertyReferenceResolver().Transform(context,
+                ((XamlAstClrProperty)new PropertyReferenceResolver().Transform(context,
                     forgedReference));
             return new XamlIlAvaloniaPropertyNode(lineInfo,
                 context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"),
                 clrProperty);
         }
 
-        public static IXamlIlType GetAvaloniaPropertyType(IXamlIlField field,
-            AvaloniaXamlIlWellKnownTypes types, IXamlIlLineInfo lineInfo)
+        public static IXamlType GetAvaloniaPropertyType(IXamlField field,
+            AvaloniaXamlIlWellKnownTypes types, IXamlLineInfo lineInfo)
         {
             var avaloniaPropertyType = field.FieldType;
             while (avaloniaPropertyType != null)
@@ -109,47 +114,47 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 avaloniaPropertyType = avaloniaPropertyType.BaseType;
             }
 
-            throw new XamlIlParseException(
+            throw new XamlX.XamlParseException(
                 $"{field.Name}'s type {field.FieldType} doesn't inherit from  AvaloniaProperty<T>, make sure to use typed properties",
                 lineInfo);
 
         }
     }
 
-    interface IXamlIlAvaloniaPropertyNode : IXamlIlAstValueNode
+    interface IXamlIlAvaloniaPropertyNode : IXamlAstValueNode
     {
-        IXamlIlType AvaloniaPropertyType { get; }
+        IXamlType AvaloniaPropertyType { get; }
     }
     
-    class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode
+    class XamlIlAvaloniaPropertyNode : XamlAstNode, IXamlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode
     {
-        public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, XamlIlAstClrProperty property) : base(lineInfo)
+        public XamlIlAvaloniaPropertyNode(IXamlLineInfo lineInfo, IXamlType type, XamlAstClrProperty property) : base(lineInfo)
         {
-            Type = new XamlIlAstClrTypeReference(this, type, false);
+            Type = new XamlAstClrTypeReference(this, type, false);
             Property = property;
             AvaloniaPropertyType = Property.Getter?.ReturnType
                                    ?? Property.Setters.First().Parameters[0];
         }
 
-        public XamlIlAstClrProperty Property { get; }
+        public XamlAstClrProperty Property { get; }
 
-        public IXamlIlAstTypeReference Type { get; }
-        public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public IXamlAstTypeReference Type { get; }
+        public XamlILNodeEmitResult Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
         {
             if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property))
-                throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this);
-            return XamlIlNodeEmitResult.Type(0, Type.GetClrType());
+                throw new XamlX.XamlLoadException(Property.Name + " is not an AvaloniaProperty", this);
+            return XamlILNodeEmitResult.Type(0, Type.GetClrType());
         }
 
-        public IXamlIlType AvaloniaPropertyType { get; }
+        public IXamlType AvaloniaPropertyType { get; }
     }
 
-    class XamlIlAvaloniaPropertyFieldNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode
+    class XamlIlAvaloniaPropertyFieldNode : XamlAstNode, IXamlAstValueNode, IXamlIlAstEmitableNode, IXamlIlAvaloniaPropertyNode
     {
-        private readonly IXamlIlField _field;
+        private readonly IXamlField _field;
 
         public XamlIlAvaloniaPropertyFieldNode(AvaloniaXamlIlWellKnownTypes types,
-            IXamlIlLineInfo lineInfo, IXamlIlField field) : base(lineInfo)
+            IXamlLineInfo lineInfo, IXamlField field) : base(lineInfo)
         {
             _field = field;
             AvaloniaPropertyType = XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(field,
@@ -158,25 +163,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         
         
 
-        public IXamlIlAstTypeReference Type => new XamlIlAstClrTypeReference(this, _field.FieldType, false);
-        public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public IXamlAstTypeReference Type => new XamlAstClrTypeReference(this, _field.FieldType, false);
+        public XamlILNodeEmitResult Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
         {
             codeGen.Ldsfld(_field);
-            return XamlIlNodeEmitResult.Type(0, _field.FieldType);
+            return XamlILNodeEmitResult.Type(0, _field.FieldType);
         }
 
-        public IXamlIlType AvaloniaPropertyType { get; }
+        public IXamlType AvaloniaPropertyType { get; }
     }
 
     interface IXamlIlAvaloniaProperty
     {
-        IXamlIlField AvaloniaProperty { get; }
+        IXamlField AvaloniaProperty { get; }
     }
     
-    class XamlIlAvaloniaProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty
+    class XamlIlAvaloniaProperty : XamlAstClrProperty, IXamlIlAvaloniaProperty
     {
-        public IXamlIlField AvaloniaProperty { get; }
-        public XamlIlAvaloniaProperty(XamlIlAstClrProperty original, IXamlIlField field,
+        public IXamlField AvaloniaProperty { get; }
+        public XamlIlAvaloniaProperty(XamlAstClrProperty original, IXamlField field,
             AvaloniaXamlIlWellKnownTypes types)
             :base(original, original.Name, original.DeclaringType, original.Getter, original.Setters)
         {
@@ -188,41 +193,41 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field));
         }
 
-        abstract class AvaloniaPropertyCustomSetter : IXamlIlPropertySetter
+        abstract class AvaloniaPropertyCustomSetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
         {
             protected AvaloniaXamlIlWellKnownTypes Types;
-            protected IXamlIlField AvaloniaProperty;
+            protected IXamlField AvaloniaProperty;
 
             public AvaloniaPropertyCustomSetter(AvaloniaXamlIlWellKnownTypes types,
-                IXamlIlType declaringType,
-                IXamlIlField avaloniaProperty)
+                IXamlType declaringType,
+                IXamlField avaloniaProperty)
             {
                 Types = types;
                 AvaloniaProperty = avaloniaProperty;
                 TargetType = declaringType;
             }
 
-            public IXamlIlType TargetType { get; }
+            public IXamlType TargetType { get; }
 
             public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters
             {
                 AllowXNull = false
             };
 
-            public IReadOnlyList<IXamlIlType> Parameters { get; set; }
-            public abstract void Emit(IXamlIlEmitter codegen);
+            public IReadOnlyList<IXamlType> Parameters { get; set; }
+            public abstract void Emit(IXamlILEmitter codegen);
         }
 
         class BindingSetter : AvaloniaPropertyCustomSetter
         {
             public BindingSetter(AvaloniaXamlIlWellKnownTypes types,
-                IXamlIlType declaringType,
-                IXamlIlField avaloniaProperty) : base(types, declaringType, avaloniaProperty)
+                IXamlType declaringType,
+                IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty)
             {
                 Parameters = new[] {types.IBinding};
             }
 
-            public override void Emit(IXamlIlEmitter emitter)
+            public override void Emit(IXamlILEmitter emitter)
             {
                 using (var bloc = emitter.LocalsPool.GetLocal(Types.IBinding))
                     emitter
@@ -237,13 +242,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
         class UnsetValueSetter : AvaloniaPropertyCustomSetter
         {
-            public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlIlType declaringType, IXamlIlField avaloniaProperty) 
+            public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty) 
                 : base(types, declaringType, avaloniaProperty)
             {
                 Parameters = new[] {types.UnsetValueType};
             }
 
-            public override void Emit(IXamlIlEmitter codegen)
+            public override void Emit(IXamlILEmitter codegen)
             {
                 var unsetValue = Types.AvaloniaProperty.Fields.First(f => f.Name == "UnsetValue");
                 codegen

+ 97 - 93
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs

@@ -5,20 +5,24 @@ using System.Linq;
 using System.Reflection.Emit;
 using Avalonia.Markup.Parsers;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.Transform.Transformers;
-using XamlIl.TypeSystem;
-using XamlIl;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.Transform.Transformers;
+using XamlX.TypeSystem;
+using XamlX;
+using XamlX.Emit;
+using XamlX.IL;
 using Avalonia.Utilities;
 
+using XamlIlEmitContext = XamlX.Emit.XamlEmitContext<XamlX.IL.IXamlILEmitter, XamlX.IL.XamlILNodeEmitResult>;
+
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
     static class XamlIlBindingPathHelper
     {
-        public static IXamlIlType UpdateCompiledBindingExtension(XamlIlAstTransformationContext context, XamlIlAstObjectNode binding, IXamlIlType startType)
+        public static IXamlType UpdateCompiledBindingExtension(AstTransformationContext context, XamlAstConstructableObjectNode binding, IXamlType startType)
         {
-            IXamlIlType bindingResultType = null;
+            IXamlType bindingResultType = null;
             if (binding.Arguments.Count > 0 && binding.Arguments[0] is ParsedBindingPathNode bindingPath)
             {
                 var transformed = TransformBindingPath(
@@ -32,7 +36,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             }
             else
             {
-                var bindingPathAssignment = binding.Children.OfType<XamlIlPropertyAssignmentNode>()
+                var bindingPathAssignment = binding.Children.OfType<XamlPropertyAssignmentNode>()
                     .FirstOrDefault(v => v.Property.Name == "Path");
 
                 if (bindingPathAssignment is null)
@@ -60,7 +64,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return bindingResultType;
         }
 
-        private static IXamlIlBindingPathNode TransformBindingPath(XamlIlAstTransformationContext context, IXamlIlLineInfo lineInfo, IXamlIlType startType, IEnumerable<BindingExpressionGrammar.INode> bindingExpression)
+        private static IXamlIlBindingPathNode TransformBindingPath(AstTransformationContext context, IXamlLineInfo lineInfo, IXamlType startType, IEnumerable<BindingExpressionGrammar.INode> bindingExpression)
         {
             List<IXamlIlBindingPathElementNode> transformNodes = new List<IXamlIlBindingPathElementNode>();
             List<IXamlIlBindingPathElementNode> nodes = new List<IXamlIlBindingPathElementNode>();
@@ -75,7 +79,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                         transformNodes.Add(new XamlIlNotPathElementNode(context.Configuration.WellKnownTypes.Boolean));
                         break;
                     case BindingExpressionGrammar.StreamNode _:
-                        IXamlIlType observableType;
+                        IXamlType observableType;
                         if (targetType.GenericTypeDefinition?.Equals(context.Configuration.TypeSystem.FindType("System.IObservable`1")) == true)
                         {
                             observableType = targetType;
@@ -104,7 +108,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                         {
                             break;
                         }
-                        throw new XamlIlParseException($"Compiled bindings do not support stream bindings for objects of type {targetType.FullName}.", lineInfo);
+                        throw new XamlX.XamlParseException($"Compiled bindings do not support stream bindings for objects of type {targetType.FullName}.", lineInfo);
                     case BindingExpressionGrammar.PropertyNameNode propName:
                         var avaloniaPropertyFieldNameMaybe = propName.PropertyName + "Property";
                         var avaloniaPropertyFieldMaybe = targetType.GetAllFields().FirstOrDefault(f =>
@@ -121,7 +125,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
                             if (clrProperty is null)
                             {
-                                throw new XamlIlParseException($"Unable to resolve property of name '{propName.PropertyName}' on type '{targetType}'.", lineInfo);
+                                throw new XamlX.XamlParseException($"Unable to resolve property of name '{propName.PropertyName}' on type '{targetType}'.", lineInfo);
                             }
                             nodes.Add(new XamlIlClrPropertyPathElementNode(clrProperty));
                         }
@@ -134,7 +138,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                                 break;
                             }
 
-                            IXamlIlProperty property = null;
+                            IXamlProperty property = null;
                             for (var currentType = targetType; currentType != null; currentType = currentType.BaseType)
                             {
                                 var defaultMemberAttribute = currentType.CustomAttributes.FirstOrDefault(x => x.Type.Namespace == "System.Reflection" && x.Type.Name == "DefaultMemberAttribute");
@@ -146,19 +150,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                             };
                             if (property is null)
                             {
-                                throw new XamlIlParseException($"The type '${targetType}' does not have an indexer.", lineInfo);
+                                throw new XamlX.XamlParseException($"The type '${targetType}' does not have an indexer.", lineInfo);
                             }
 
-                            IEnumerable<IXamlIlType> parameters = property.IndexerParameters;
+                            IEnumerable<IXamlType> parameters = property.IndexerParameters;
 
-                            List<IXamlIlAstValueNode> values = new List<IXamlIlAstValueNode>();
+                            List<IXamlAstValueNode> values = new List<IXamlAstValueNode>();
                             int currentParamIndex = 0;
                             foreach (var param in parameters)
                             {
-                                var textNode = new XamlIlAstTextNode(lineInfo, indexer.Arguments[currentParamIndex], type: context.Configuration.WellKnownTypes.String);
-                                if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, textNode,
+                                var textNode = new XamlAstTextNode(lineInfo, indexer.Arguments[currentParamIndex], type: context.Configuration.WellKnownTypes.String);
+                                if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, textNode,
                                         param, out var converted))
-                                    throw new XamlIlParseException(
+                                    throw new XamlX.XamlParseException(
                                         $"Unable to convert indexer parameter value of '{indexer.Arguments[currentParamIndex]}' to {param.GetFqn()}",
                                         textNode);
 
@@ -197,14 +201,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                             var styledElementType = context.GetAvaloniaTypes().StyledElement;
                             var ancestorType = context
                                 .ParentNodes()
-                                .OfType<XamlIlAstObjectNode>()
+                                .OfType<XamlAstConstructableObjectNode>()
                                 .Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
                                 .ElementAtOrDefault(ancestor.Level)
                                 ?.Type.GetClrType();
 
                             if (ancestorType is null)
                             {
-                                throw new XamlIlParseException("Unable to resolve implicit ancestor type based on XAML tree.", lineInfo);
+                                throw new XamlX.XamlParseException("Unable to resolve implicit ancestor type based on XAML tree.", lineInfo);
                             }
 
                             nodes.Add(new FindAncestorPathElementNode(ancestorType, ancestor.Level));
@@ -215,7 +219,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                         }
                         break;
                     case BindingExpressionGrammar.NameNode elementName:
-                        IXamlIlType elementType = null;
+                        IXamlType elementType = null;
                         foreach (var deferredContent in context.ParentNodes().OfType<NestedScopeMetadataNode>())
                         {
                             elementType = ScopeRegistrationFinder.GetTargetType(deferredContent, elementName.Name);
@@ -231,7 +235,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
                         if (elementType is null)
                         {
-                            throw new XamlIlParseException($"Unable to find element '{elementName.Name}' in the current namescope. Unable to use a compiled binding with a name binding if the name cannot be found at compile time.", lineInfo);
+                            throw new XamlX.XamlParseException($"Unable to find element '{elementName.Name}' in the current namescope. Unable to use a compiled binding with a name binding if the name cannot be found at compile time.", lineInfo);
                         }
                         nodes.Add(new ElementNamePathElementNode(elementName.Name, elementType));
                         break;
@@ -243,17 +247,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
             return new XamlIlBindingPathNode(lineInfo, context.GetAvaloniaTypes().CompiledBindingPath, transformNodes, nodes);
 
-            IXamlIlType GetType(string ns, string name)
+            IXamlType GetType(string ns, string name)
             {
-                return XamlIlTypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
+                return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
                     lineInfo, true).GetClrType();
             }
         }
 
-        class ScopeRegistrationFinder : IXamlIlAstVisitor
+        class ScopeRegistrationFinder : IXamlAstVisitor
         {
-            private Stack<IXamlIlAstNode> _stack = new Stack<IXamlIlAstNode>();
-            private Stack<IXamlIlAstNode> _childScopesStack = new Stack<IXamlIlAstNode>();
+            private Stack<IXamlAstNode> _stack = new Stack<IXamlAstNode>();
+            private Stack<IXamlAstNode> _childScopesStack = new Stack<IXamlAstNode>();
 
             private ScopeRegistrationFinder(string name)
             {
@@ -262,16 +266,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
             string Name { get; }
 
-            IXamlIlType TargetType { get; set; }
+            IXamlType TargetType { get; set; }
 
-            public static IXamlIlType GetTargetType(IXamlIlAstNode namescopeRoot, string name)
+            public static IXamlType GetTargetType(IXamlAstNode namescopeRoot, string name)
             {
                 var finder = new ScopeRegistrationFinder(name);
                 namescopeRoot.Visit(finder);
                 return finder.TargetType;
             }
 
-            void IXamlIlAstVisitor.Pop()
+            void IXamlAstVisitor.Pop()
             {
                 var node = _stack.Pop();
                 if (_childScopesStack.Count > 0 && node == _childScopesStack.Peek())
@@ -280,7 +284,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 }
             }
 
-            void IXamlIlAstVisitor.Push(IXamlIlAstNode node)
+            void IXamlAstVisitor.Push(IXamlAstNode node)
             {
                 _stack.Push(node);
                 if (node is NestedScopeMetadataNode)
@@ -289,11 +293,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 }
             }
 
-            IXamlIlAstNode IXamlIlAstVisitor.Visit(IXamlIlAstNode node)
+            IXamlAstNode IXamlAstVisitor.Visit(IXamlAstNode node)
             {
                 if (_childScopesStack.Count == 0 && node is AvaloniaNameScopeRegistrationXamlIlNode registration)
                 {
-                    if (registration.Name is XamlIlAstTextNode text && text.Text == Name)
+                    if (registration.Name is XamlAstTextNode text && text.Text == Name)
                     {
                         TargetType = registration.TargetType;
                     }
@@ -304,21 +308,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
         interface IXamlIlBindingPathElementNode
         {
-            IXamlIlType Type { get; }
+            IXamlType Type { get; }
 
-            void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen);
+            void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen);
         }
 
         class XamlIlNotPathElementNode : IXamlIlBindingPathElementNode
         {
-            public XamlIlNotPathElementNode(IXamlIlType boolType)
+            public XamlIlNotPathElementNode(IXamlType boolType)
             {
                 Type = boolType;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Not"));
             }
@@ -326,14 +330,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
         class XamlIlStreamObservablePathElementNode : IXamlIlBindingPathElementNode
         {
-            public XamlIlStreamObservablePathElementNode(IXamlIlType type)
+            public XamlIlStreamObservablePathElementNode(IXamlType type)
             {
                 Type = type;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "StreamObservable").MakeGenericMethod(new[] { Type }));
             }
@@ -341,14 +345,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
         class XamlIlStreamTaskPathElementNode : IXamlIlBindingPathElementNode
         {
-            public XamlIlStreamTaskPathElementNode(IXamlIlType type)
+            public XamlIlStreamTaskPathElementNode(IXamlType type)
             {
                 Type = type;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "StreamTask").MakeGenericMethod(new[] { Type }));
             }
@@ -356,14 +360,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
         class SelfPathElementNode : IXamlIlBindingPathElementNode
         {
-            public SelfPathElementNode(IXamlIlType type)
+            public SelfPathElementNode(IXamlType type)
             {
                 Type = type;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Self"));
             }
@@ -373,15 +377,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         {
             private readonly int _level;
 
-            public FindAncestorPathElementNode(IXamlIlType ancestorType, int level)
+            public FindAncestorPathElementNode(IXamlType ancestorType, int level)
             {
                 Type = ancestorType;
                 _level = level;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.Ldtype(Type)
                     .Ldc_I4(_level)
@@ -393,15 +397,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         {
             private readonly int _level;
 
-            public FindVisualAncestorPathElementNode(IXamlIlType ancestorType, int level)
+            public FindVisualAncestorPathElementNode(IXamlType ancestorType, int level)
             {
                 Type = ancestorType;
                 _level = level;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.Ldtype(Type)
                     .Ldc_I4(_level)
@@ -413,15 +417,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         {
             private readonly string _name;
 
-            public ElementNamePathElementNode(string name, IXamlIlType elementType)
+            public ElementNamePathElementNode(string name, IXamlType elementType)
             {
                 _name = name;
                 Type = elementType;
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 var scopeField = context.RuntimeContext.ContextType.Fields.First(f =>
                     f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName);
@@ -436,15 +440,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 
         class XamlIlAvaloniaPropertyPropertyPathElementNode : IXamlIlBindingPathElementNode
         {
-            private readonly IXamlIlField _field;
+            private readonly IXamlField _field;
 
-            public XamlIlAvaloniaPropertyPropertyPathElementNode(IXamlIlField field, IXamlIlType propertyType)
+            public XamlIlAvaloniaPropertyPropertyPathElementNode(IXamlField field, IXamlType propertyType)
             {
                 _field = field;
                 Type = propertyType;
             }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 codeGen.Ldsfld(_field);
                 context.Configuration.GetExtra<XamlIlPropertyInfoAccessorFactoryEmitter>()
@@ -453,19 +457,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                     .CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property"));
             }
 
-            public IXamlIlType Type { get; }
+            public IXamlType Type { get; }
         }
 
         class XamlIlClrPropertyPathElementNode : IXamlIlBindingPathElementNode
         {
-            private readonly IXamlIlProperty _property;
+            private readonly IXamlProperty _property;
 
-            public XamlIlClrPropertyPathElementNode(IXamlIlProperty property)
+            public XamlIlClrPropertyPathElementNode(IXamlProperty property)
             {
                 _property = property;
             }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 context.Configuration.GetExtra<XamlIlClrPropertyInfoEmitter>()
                     .Emit(context, codeGen, _property);
@@ -478,17 +482,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                         .CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property"));
             }
 
-            public IXamlIlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0];
+            public IXamlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0];
         }
 
         class XamlIlClrIndexerPathElementNode : IXamlIlBindingPathElementNode
         {
-            private readonly IXamlIlProperty _property;
-            private readonly List<IXamlIlAstValueNode> _values;
+            private readonly IXamlProperty _property;
+            private readonly List<IXamlAstValueNode> _values;
             private readonly string _indexerKey;
             private readonly bool _isNotifyingCollection;
 
-            public XamlIlClrIndexerPathElementNode(IXamlIlProperty property, List<IXamlIlAstValueNode> values, string indexerKey, bool isNotifyingCollection)
+            public XamlIlClrIndexerPathElementNode(IXamlProperty property, List<IXamlAstValueNode> values, string indexerKey, bool isNotifyingCollection)
             {
                 _property = property;
                 _values = values;
@@ -496,7 +500,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 _isNotifyingCollection = isNotifyingCollection;
             }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 var intType = context.Configuration.TypeSystem.GetType("System.Int32");
                 context.Configuration.GetExtra<XamlIlClrPropertyInfoEmitter>()
@@ -520,15 +524,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                     .CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property"));
             }
 
-            public IXamlIlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0];
+            public IXamlType Type => _property.Getter?.ReturnType ?? _property.Setter?.Parameters[0];
         }
 
         class XamlIlArrayIndexerPathElementNode : IXamlIlBindingPathElementNode
         {
-            private readonly IXamlIlType _arrayType;
+            private readonly IXamlType _arrayType;
             private readonly List<int> _values;
 
-            public XamlIlArrayIndexerPathElementNode(IXamlIlType arrayType, IList<string> values, IXamlIlLineInfo lineInfo)
+            public XamlIlArrayIndexerPathElementNode(IXamlType arrayType, IList<string> values, IXamlLineInfo lineInfo)
             {
                 _arrayType = arrayType;
                 _values = new List<int>(values.Count);
@@ -536,13 +540,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 {
                     if (!int.TryParse(item, out var index))
                     {
-                        throw new XamlIlParseException($"Unable to convert '{item}' to an integer.", lineInfo.Line, lineInfo.Position);
+                        throw new XamlX.XamlParseException($"Unable to convert '{item}' to an integer.", lineInfo.Line, lineInfo.Position);
                     }
                     _values.Add(index);
                 }
             }
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 var intType = context.Configuration.TypeSystem.GetType("System.Int32");
                 var indices = codeGen.DefineLocal(intType.MakeArrayType(1));
@@ -563,23 +567,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                     .CompiledBindingPathBuilder.FindMethod(m => m.Name == "ArrayElement"));
             }
 
-            public IXamlIlType Type => _arrayType.ArrayElementType;
+            public IXamlType Type => _arrayType.ArrayElementType;
         }
 
-        class RawSourcePathElementNode : XamlIlAstNode, IXamlIlBindingPathElementNode
+        class RawSourcePathElementNode : XamlAstNode, IXamlIlBindingPathElementNode
         {
-            private readonly IXamlIlAstValueNode _rawSource;
+            private readonly IXamlAstValueNode _rawSource;
 
-            public RawSourcePathElementNode(IXamlIlAstValueNode rawSource)
+            public RawSourcePathElementNode(IXamlAstValueNode rawSource)
                 :base(rawSource)
             {
                 _rawSource = rawSource;
                 
             }
 
-            public IXamlIlType Type => _rawSource.Type.GetClrType();
+            public IXamlType Type => _rawSource.Type.GetClrType();
 
-            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 context.Emit(_rawSource, codeGen, Type);
                 codeGen
@@ -588,29 +592,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             }
         }
 
-        class XamlIlBindingPathNode : XamlIlAstNode, IXamlIlBindingPathNode, IXamlIlAstEmitableNode
+        class XamlIlBindingPathNode : XamlAstNode, IXamlIlBindingPathNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
         {
             private readonly List<IXamlIlBindingPathElementNode> _transformElements;
             private readonly List<IXamlIlBindingPathElementNode> _elements;
 
-            public XamlIlBindingPathNode(IXamlIlLineInfo lineInfo,
-                IXamlIlType bindingPathType,
+            public XamlIlBindingPathNode(IXamlLineInfo lineInfo,
+                IXamlType bindingPathType,
                 List<IXamlIlBindingPathElementNode> transformElements,
                 List<IXamlIlBindingPathElementNode> elements) : base(lineInfo)
             {
-                Type = new XamlIlAstClrTypeReference(lineInfo, bindingPathType, false);
+                Type = new XamlAstClrTypeReference(lineInfo, bindingPathType, false);
                 _transformElements = transformElements;
                 _elements = elements;
             }
 
-            public IXamlIlType BindingResultType
+            public IXamlType BindingResultType
                 => _transformElements.Count > 0
                     ? _transformElements[0].Type
                     : _elements[_elements.Count - 1].Type;
 
-            public IXamlIlAstTypeReference Type { get; }
+            public IXamlAstTypeReference Type { get; }
 
-            public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            public XamlILNodeEmitResult Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
             {
                 var types = context.GetAvaloniaTypes();
                 codeGen.Newobj(types.CompiledBindingPathBuilder.FindConstructor());
@@ -626,21 +630,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 }
 
                 codeGen.EmitCall(types.CompiledBindingPathBuilder.FindMethod(m => m.Name == "Build"));
-                return XamlIlNodeEmitResult.Type(0, types.CompiledBindingPath);
+                return XamlILNodeEmitResult.Type(0, types.CompiledBindingPath);
             }
 
-            public override void VisitChildren(IXamlIlAstVisitor visitor)
+            public override void VisitChildren(IXamlAstVisitor visitor)
             {
                 for (int i = 0; i < _transformElements.Count; i++)
                 {
-                    if (_transformElements[i] is IXamlIlAstNode ast)
+                    if (_transformElements[i] is IXamlAstNode ast)
                     {
                         _transformElements[i] = (IXamlIlBindingPathElementNode)ast.Visit(visitor);
                     }
                 }
                 for (int i = 0; i < _elements.Count; i++)
                 {
-                    if (_elements[i] is IXamlIlAstNode ast)
+                    if (_elements[i] is IXamlAstNode ast)
                     {
                         _elements[i] = (IXamlIlBindingPathElementNode)ast.Visit(visitor);
                     }
@@ -649,8 +653,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
         }
     }
 
-    interface IXamlIlBindingPathNode : IXamlIlAstValueNode
+    interface IXamlIlBindingPathNode : IXamlAstValueNode
     {
-        IXamlIlType BindingResultType { get; }
+        IXamlType BindingResultType { get; }
     }
 }

+ 17 - 15
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs

@@ -2,25 +2,27 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+using XamlX.IL;
+using XamlX.Emit;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
     class XamlIlClrPropertyInfoEmitter
     {
-        private readonly IXamlIlTypeBuilder _builder;
+        private readonly IXamlTypeBuilder<IXamlILEmitter> _builder;
 
-        private Dictionary<string, List<(IXamlIlProperty prop, IXamlIlMethod get)>> _fields
-            = new Dictionary<string, List<(IXamlIlProperty prop, IXamlIlMethod get)>>();
+        private Dictionary<string, List<(IXamlProperty prop, IXamlMethod get)>> _fields
+            = new Dictionary<string, List<(IXamlProperty prop, IXamlMethod get)>>();
         
-        public XamlIlClrPropertyInfoEmitter(IXamlIlTypeBuilder builder)
+        public XamlIlClrPropertyInfoEmitter(IXamlTypeBuilder<IXamlILEmitter> builder)
         {
             _builder = builder;
         }
 
-        static string GetKey(IXamlIlProperty property, string indexerArgumentsKey)
+        static string GetKey(IXamlProperty property, string indexerArgumentsKey)
         {
             var baseKey = property.Getter.DeclaringType.GetFullName() + "." + property.Name;
 
@@ -32,15 +34,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return baseKey + $"[{indexerArgumentsKey}]";
         }
 
-        public IXamlIlType Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlProperty property, IEnumerable<IXamlIlAstValueNode> indexerArguments = null, string indexerArgumentsKey = null)
+        public IXamlType Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, IXamlProperty property, IEnumerable<IXamlAstValueNode> indexerArguments = null, string indexerArgumentsKey = null)
         {
-            indexerArguments = indexerArguments ?? Enumerable.Empty<IXamlIlAstValueNode>();
+            indexerArguments = indexerArguments ?? Enumerable.Empty<IXamlAstValueNode>();
             var types = context.GetAvaloniaTypes();
-            IXamlIlMethod Get()
+            IXamlMethod Get()
             {
                 var key = GetKey(property, indexerArgumentsKey);
                 if (!_fields.TryGetValue(key, out var lst))
-                    _fields[key] = lst = new List<(IXamlIlProperty prop, IXamlIlMethod get)>();
+                    _fields[key] = lst = new List<(IXamlProperty prop, IXamlMethod get)>();
 
                 foreach (var cached in lst)
                 {
@@ -57,7 +59,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                 
                 var field = _builder.DefineField(types.IPropertyInfo, name + "!Field", false, true);
 
-                void Load(IXamlIlMethod m, IXamlIlEmitter cg)
+                void Load(IXamlMethod m, IXamlILEmitter cg)
                 {
                     cg
                         .Ldarg_0();
@@ -105,7 +107,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                         .Ret();
                 }
 
-                var get = _builder.DefineMethod(types.IPropertyInfo, Array.Empty<IXamlIlType>(),
+                var get = _builder.DefineMethod(types.IPropertyInfo, Array.Empty<IXamlType>(),
                     name + "!Property", true, true, false);
 
 
@@ -121,7 +123,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                     .MarkLabel(cacheMiss)
                     .Ldstr(property.Name);
 
-                void EmitFunc(IXamlIlEmitter emitter, IXamlIlMethod method, IXamlIlType del)
+                void EmitFunc(IXamlILEmitter emitter, IXamlMethod method, IXamlType del)
                 {
                     if (method == null)
                         emitter.Ldnull();

+ 17 - 13
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs

@@ -3,37 +3,41 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
-using XamlIl.Ast;
-using XamlIl.Transform;
-using XamlIl.TypeSystem;
+using XamlX.Ast;
+using XamlX.Transform;
+using XamlX.TypeSystem;
+using XamlX.Emit;
+using XamlX.IL;
+
+using XamlIlEmitContext = XamlX.Emit.XamlEmitContext<XamlX.IL.IXamlILEmitter, XamlX.IL.XamlILNodeEmitResult>;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
 {
     class XamlIlPropertyInfoAccessorFactoryEmitter
     {
         private const string IndexerClosureFactoryMethodName = "CreateAccessor";
-        private readonly IXamlIlTypeBuilder _indexerClosureTypeBuilder;
-        private IXamlIlType _indexerClosureType;
-        public XamlIlPropertyInfoAccessorFactoryEmitter(IXamlIlTypeBuilder indexerClosureType)
+        private readonly IXamlTypeBuilder<IXamlILEmitter> _indexerClosureTypeBuilder;
+        private IXamlType _indexerClosureType;
+        public XamlIlPropertyInfoAccessorFactoryEmitter(IXamlTypeBuilder<IXamlILEmitter> indexerClosureType)
         {
             _indexerClosureTypeBuilder = indexerClosureType;
         }
 
-        public IXamlIlType EmitLoadInpcPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public IXamlType EmitLoadInpcPropertyAccessorFactory(XamlIlEmitContext context, IXamlILEmitter codeGen)
         {
             codeGen.Ldnull();
             EmitLoadPropertyAccessorFactory(context, codeGen, context.GetAvaloniaTypes().PropertyInfoAccessorFactory, "CreateInpcPropertyAccessor");
             return EmitCreateAccessorFactoryDelegate(context, codeGen);
         }
 
-        public IXamlIlType EmitLoadAvaloniaPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        public IXamlType EmitLoadAvaloniaPropertyAccessorFactory(XamlIlEmitContext context, IXamlILEmitter codeGen)
         {
             codeGen.Ldnull();
             EmitLoadPropertyAccessorFactory(context, codeGen, context.GetAvaloniaTypes().PropertyInfoAccessorFactory, "CreateAvaloniaPropertyAccessor");
             return EmitCreateAccessorFactoryDelegate(context, codeGen);
         }
 
-        private void EmitLoadPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlType type, string accessorFactoryName, bool isStatic = true)
+        private void EmitLoadPropertyAccessorFactory(XamlIlEmitContext context, IXamlILEmitter codeGen, IXamlType type, string accessorFactoryName, bool isStatic = true)
         {
             var types = context.GetAvaloniaTypes();
             var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference`1").MakeGenericType(context.Configuration.WellKnownTypes.Object);
@@ -44,7 +48,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             codeGen.Ldftn(type.GetMethod(accessorFactorySignature));
         }
 
-        public IXamlIlType EmitLoadIndexerAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlAstValueNode value)
+        public IXamlType EmitLoadIndexerAccessorFactory(XamlIlEmitContext context, IXamlILEmitter codeGen, IXamlAstValueNode value)
         {
             var intType = context.Configuration.TypeSystem.GetType("System.Int32");
             if (_indexerClosureType is null)
@@ -53,12 +57,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             }
 
             context.Emit(value, codeGen, intType);
-            codeGen.Newobj(_indexerClosureType.FindConstructor(new List<IXamlIlType> { intType }));
+            codeGen.Newobj(_indexerClosureType.FindConstructor(new List<IXamlType> { intType }));
             EmitLoadPropertyAccessorFactory(context, codeGen, _indexerClosureType, IndexerClosureFactoryMethodName, isStatic: false);
             return EmitCreateAccessorFactoryDelegate(context, codeGen);
         }
 
-        private IXamlIlType InitializeClosureType(XamlIlEmitContext context)
+        private IXamlType InitializeClosureType(XamlIlEmitContext context)
         {
             var types = context.GetAvaloniaTypes();
             var intType = context.Configuration.TypeSystem.GetType("System.Int32");
@@ -97,7 +101,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             return _indexerClosureTypeBuilder.CreateType();
         }
 
-        private IXamlIlType EmitCreateAccessorFactoryDelegate(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+        private IXamlType EmitCreateAccessorFactoryDelegate(XamlIlEmitContext context, IXamlILEmitter codeGen)
         {
             var types = context.GetAvaloniaTypes();
             var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference`1").MakeGenericType(context.Configuration.WellKnownTypes.Object);

+ 1 - 1
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@@ -1 +1 @@
-Subproject commit 068162245473ec39ee36da12150e928072b96403
+Subproject commit 0028377ce7c7dc21f9fe71b45f62a95991b1ab58

+ 1 - 1
src/Skia/Avalonia.Skia/FormattedTextImpl.cs

@@ -569,7 +569,7 @@ namespace Avalonia.Skia
                 
                 float constraint = -1;
 
-                if (_wrapping == TextWrapping.Wrap)
+                if (_wrapping != TextWrapping.NoWrap)
                 {
                     constraint = widthConstraint <= 0 ? MAX_LINE_WIDTH : widthConstraint;
                     if (constraint > MAX_LINE_WIDTH)

+ 8 - 6
src/Skia/Avalonia.Skia/TextShaperImpl.cs

@@ -1,9 +1,9 @@
 using System;
+using System.Globalization;
 using Avalonia.Media;
-using Avalonia.Media.TextFormatting;
 using Avalonia.Media.TextFormatting.Unicode;
 using Avalonia.Platform;
-using Avalonia.Utility;
+using Avalonia.Utilities;
 using HarfBuzzSharp;
 using Buffer = HarfBuzzSharp.Buffer;
 
@@ -11,7 +11,7 @@ namespace Avalonia.Skia
 {
     internal class TextShaperImpl : ITextShaperImpl
     {
-        public GlyphRun ShapeText(ReadOnlySlice<char> text, TextFormat textFormat)
+        public GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture)
         {
             using (var buffer = new Buffer())
             {
@@ -61,9 +61,11 @@ namespace Avalonia.Skia
                     buffer.AddUtf16(text.Buffer.Span);
                 }
 
+                buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);
+
                 buffer.GuessSegmentProperties();
 
-                var glyphTypeface = textFormat.Typeface.GlyphTypeface;
+                var glyphTypeface = typeface.GlyphTypeface;
 
                 var font = ((GlyphTypefaceImpl)glyphTypeface.PlatformImpl).Font;
 
@@ -71,7 +73,7 @@ namespace Avalonia.Skia
 
                 font.GetScale(out var scaleX, out _);
 
-                var textScale = textFormat.FontRenderingEmSize / scaleX;
+                var textScale = fontRenderingEmSize / scaleX;
 
                 var bufferLength = buffer.Length;
 
@@ -101,7 +103,7 @@ namespace Avalonia.Skia
                     SetOffset(glyphPositions, i, textScale, ref glyphOffsets);
                 }
 
-                return new GlyphRun(glyphTypeface, textFormat.FontRenderingEmSize,
+                return new GlyphRun(glyphTypeface, fontRenderingEmSize,
                     new ReadOnlySlice<ushort>(glyphIndices),
                     new ReadOnlySlice<double>(glyphAdvances),
                     new ReadOnlySlice<Vector>(glyphOffsets),

+ 9 - 6
src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs

@@ -1,8 +1,9 @@
-using Avalonia.Media;
+using System.Globalization;
+using Avalonia.Media;
 using Avalonia.Media.TextFormatting;
 using Avalonia.Media.TextFormatting.Unicode;
 using Avalonia.Platform;
-using Avalonia.Utility;
+using Avalonia.Utilities;
 using HarfBuzzSharp;
 using Buffer = HarfBuzzSharp.Buffer;
 
@@ -10,7 +11,7 @@ namespace Avalonia.Direct2D1.Media
 {
     internal class TextShaperImpl : ITextShaperImpl
     {
-        public GlyphRun ShapeText(ReadOnlySlice<char> text, TextFormat textFormat)
+        public GlyphRun ShapeText(ReadOnlySlice<char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture)
         {
             using (var buffer = new Buffer())
             {
@@ -62,15 +63,17 @@ namespace Avalonia.Direct2D1.Media
 
                 buffer.GuessSegmentProperties();
 
-                var glyphTypeface = textFormat.Typeface.GlyphTypeface;
+                var glyphTypeface = typeface.GlyphTypeface;
 
                 var font = ((GlyphTypefaceImpl)glyphTypeface.PlatformImpl).Font;
 
+                buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);
+
                 font.Shape(buffer);
 
                 font.GetScale(out var scaleX, out _);
 
-                var textScale = textFormat.FontRenderingEmSize / scaleX;
+                var textScale = fontRenderingEmSize / scaleX;
 
                 var len = buffer.Length;
 
@@ -104,7 +107,7 @@ namespace Avalonia.Direct2D1.Media
                     glyphOffsets[i] = new Vector(offsetX, offsetY);
                 }
 
-                return new GlyphRun(glyphTypeface, textFormat.FontRenderingEmSize,
+                return new GlyphRun(glyphTypeface, fontRenderingEmSize,
                     new ReadOnlySlice<ushort>(glyphIndices),
                     new ReadOnlySlice<double>(glyphAdvances),
                     new ReadOnlySlice<Vector>(glyphOffsets),

+ 2 - 2
tests/Avalonia.Direct2D1.UnitTests/Media/FontManagerImplTests.cs

@@ -41,7 +41,7 @@ namespace Avalonia.Direct2D1.UnitTests.Media
                 var fontManager = new FontManagerImpl();
 
                 var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface(
-                    new Typeface(new FontFamily("A, B, Arial"), FontWeight.Bold));
+                    new Typeface(new FontFamily("A, B, Arial"), weight: FontWeight.Bold));
 
                 var font = glyphTypeface.DWFont;
 
@@ -105,7 +105,7 @@ namespace Avalonia.Direct2D1.UnitTests.Media
                 var fontManager = new FontManagerImpl();
 
                 var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface(
-                    new Typeface(s_fontUri, FontWeight.Black, FontStyle.Italic));
+                    new Typeface(s_fontUri, FontStyle.Italic, FontWeight.Black));
 
                 var font = glyphTypeface.DWFont;
 

+ 6 - 6
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@@ -9,7 +9,7 @@ using Avalonia.Controls.Presenters;
 using Avalonia.Data.Core;
 using Avalonia.Markup.Data;
 using Avalonia.UnitTests;
-using XamlIl;
+using XamlX;
 using Xunit;
 
 namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
@@ -328,7 +328,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
     <ContentControl Name='target' Content='{CompiledBinding}' />
 </Window>";
                 var loader = new AvaloniaXamlLoader();
-                Assert.Throws<XamlIlTransformException>(() => loader.Load(xaml));
+                Assert.Throws<XamlTransformException>(() => loader.Load(xaml));
             }
         }
 
@@ -347,7 +347,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
     </ContentControl>
 </Window>";
                 var loader = new AvaloniaXamlLoader();
-                Assert.Throws<XamlIlTransformException>(() => loader.Load(xaml));
+                Assert.Throws<XamlTransformException>(() => loader.Load(xaml));
             }
         }
 
@@ -406,7 +406,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
     </ItemsControl>
 </Window>";
                 var loader = new AvaloniaXamlLoader();
-                Assert.Throws<XamlIlTransformException>(() => loader.Load(xaml));
+                Assert.Throws<XamlTransformException>(() => loader.Load(xaml));
             }
         }
 
@@ -562,7 +562,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
     <TextBlock Text='{Binding InvalidPath}' Name='textBlock' />
 </Window>";
                 var loader = new AvaloniaXamlLoader();
-                Assert.Throws<XamlIlParseException>(() => loader.Load(xaml));
+                Assert.Throws<XamlX.XamlParseException>(() => loader.Load(xaml));
             }
         }
 
@@ -579,7 +579,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
         x:CompileBindings='notabool'>
 </Window>";
                 var loader = new AvaloniaXamlLoader();
-                Assert.Throws<XamlIlParseException>(() => loader.Load(xaml));
+                Assert.Throws<XamlX.XamlParseException>(() => loader.Load(xaml));
             }
         }
     }

+ 0 - 45
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs

@@ -249,51 +249,6 @@ namespace Avalonia.Markup.Xaml.UnitTests
             Assert.Equal(6, parsed.Count);
         }
 
-        [Fact]
-        public void Should_Provide_PropertyPath_For_Setters()
-        {
-            using (UnitTestApplication.Start(TestServices.StyledWindow))
-            {
-                var parsed = AvaloniaXamlLoader.Parse<Style>(@"
-<Style Selector='Animatable' xmlns='https://github.com/avaloniaui'>
-    <Setter PropertyPath=':>Visual.Bounds.BottomRight.X' Value='0' />
-    <Setter PropertyPath=':>Visual.RenderTransform:=ScaleTransform.ScaleX' Value='0' />
-    <Setter PropertyPath='(Visual.RenderTransform):=ScaleTransform.ScaleX' Value='0' />
-</Style>");
-                var s1e = ((Setter)parsed.Setters[0]).PropertyPath.Elements;
-                var s2e = ((Setter)parsed.Setters[1]).PropertyPath.Elements;
-                var s3e = ((Setter)parsed.Setters[2]).PropertyPath.Elements;
-                
-                Assert.Equal(typeof(Visual), ((CastTypePropertyPathElement)s1e[0]).Type);
-                Assert.IsType<ChildTraversalPropertyPathElement>(s1e[1]);
-                Assert.Equal("Bounds", ((AvaloniaProperty)((PropertyPropertyPathElement)s1e[2]).Property).Name);
-                Assert.IsType<ChildTraversalPropertyPathElement>(s1e[3]);
-                var bottomRight = ((PropertyPropertyPathElement)s1e[4]).Property;
-                Assert.IsType<ChildTraversalPropertyPathElement>(s1e[5]);
-                var pointX = ((PropertyPropertyPathElement)s1e[6]).Property;
-                
-                var orect = (object)(new Rect(100, 100, 200, 200));
-                var point = bottomRight.Get(orect);
-                var x = pointX.Get(point);
-                Assert.Equal(300, (double)x);
-                
-                Assert.Equal(typeof(Visual), ((CastTypePropertyPathElement)s2e[0]).Type);
-                Assert.IsType<ChildTraversalPropertyPathElement>(s2e[1]);
-                Assert.Equal("RenderTransform", ((AvaloniaProperty)((PropertyPropertyPathElement)s2e[2]).Property).Name);
-                Assert.Equal(typeof(ScaleTransform), ((EnsureTypePropertyPathElement)s2e[3]).Type);
-                Assert.IsType<ChildTraversalPropertyPathElement>(s2e[4]);
-                Assert.Equal("ScaleX", ((AvaloniaProperty)((PropertyPropertyPathElement)s2e[5]).Property).Name);
-
-
-                var s3fqp = (AvaloniaProperty)((PropertyPropertyPathElement)s3e[0]).Property;
-                Assert.Equal("RenderTransform", s3fqp.Name);
-                Assert.Equal(typeof(Visual), s3fqp.OwnerType);
-                Assert.Equal(typeof(ScaleTransform), ((EnsureTypePropertyPathElement)s3e[1]).Type);
-                Assert.IsType<ChildTraversalPropertyPathElement>(s3e[2]);
-                Assert.Equal("ScaleX", ((AvaloniaProperty)((PropertyPropertyPathElement)s3e[3]).Property).Name);
-            }
-        }
-
         [Fact]
         public void DataContextType_Resolution()
         {

+ 1 - 1
tests/Avalonia.Skia.UnitTests/CustomFontManagerImpl.cs → tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs

@@ -6,7 +6,7 @@ using Avalonia.Media.Fonts;
 using Avalonia.Platform;
 using SkiaSharp;
 
-namespace Avalonia.Skia.UnitTests
+namespace Avalonia.Skia.UnitTests.Media
 {
     public class CustomFontManagerImpl : IFontManagerImpl
     {

+ 3 - 5
tests/Avalonia.Skia.UnitTests/FontManagerImplTests.cs → tests/Avalonia.Skia.UnitTests/Media/FontManagerImplTests.cs

@@ -1,13 +1,11 @@
 using System;
 using System.Linq;
-using System.Reflection;
 using Avalonia.Media;
-using Avalonia.Platform;
 using Avalonia.UnitTests;
 using SkiaSharp;
 using Xunit;
 
-namespace Avalonia.Skia.UnitTests
+namespace Avalonia.Skia.UnitTests.Media
 {
     public class FontManagerImplTests
     {
@@ -39,7 +37,7 @@ namespace Avalonia.Skia.UnitTests
             string fontName = fontManager.GetInstalledFontFamilyNames().First();
 
             var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface(
-                new Typeface(new FontFamily($"A, B, {fontName}"), FontWeight.Bold));
+                new Typeface(new FontFamily($"A, B, {fontName}"), weight: FontWeight.Bold));
 
             var skTypeface = glyphTypeface.Typeface;
 
@@ -88,7 +86,7 @@ namespace Avalonia.Skia.UnitTests
                 var fontManager = new FontManagerImpl();
 
                 var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface(
-                    new Typeface(s_fontUri, FontWeight.Black, FontStyle.Italic));
+                    new Typeface(s_fontUri, FontStyle.Italic, FontWeight.Black));
 
                 var skTypeface = glyphTypeface.Typeface;
 

+ 2 - 2
tests/Avalonia.Skia.UnitTests/SKTypefaceCollectionCacheTests.cs → tests/Avalonia.Skia.UnitTests/Media/SKTypefaceCollectionCacheTests.cs

@@ -2,7 +2,7 @@
 using Avalonia.UnitTests;
 using Xunit;
 
-namespace Avalonia.Skia.UnitTests
+namespace Avalonia.Skia.UnitTests.Media
 {
     public class SKTypefaceCollectionCacheTests
     {
@@ -19,7 +19,7 @@ namespace Avalonia.Skia.UnitTests
 
                 var notoMonoCollection = SKTypefaceCollectionCache.GetOrAddTypefaceCollection(notoMono);
 
-                var typeface = new Typeface("ABC", FontWeight.Bold, FontStyle.Italic);
+                var typeface = new Typeface("ABC", FontStyle.Italic, FontWeight.Bold);
 
                 Assert.Equal("Noto Mono", notoMonoCollection.Get(typeface).FamilyName);
 

+ 38 - 0
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/FormattableTextSource.cs

@@ -0,0 +1,38 @@
+using System;
+using Avalonia.Media.TextFormatting;
+using Avalonia.Utilities;
+
+namespace Avalonia.Skia.UnitTests.Media.TextFormatting
+{
+    internal class FormattableTextSource : ITextSource
+    {
+        private readonly ReadOnlySlice<char> _text;
+        private readonly TextRunProperties _defaultStyle;
+        private ReadOnlySlice<ValueSpan<TextRunProperties>> _styleSpans;
+
+        public FormattableTextSource(string text, TextRunProperties defaultStyle,
+            ReadOnlySlice<ValueSpan<TextRunProperties>> styleSpans)
+        {
+            _text = text.AsMemory();
+
+            _defaultStyle = defaultStyle;
+
+            _styleSpans = styleSpans;
+        }
+
+        public TextRun GetTextRun(int textSourceIndex)
+        {
+            if (_styleSpans.IsEmpty)
+            {
+                return new TextEndOfParagraph();
+            }
+
+            var currentSpan = _styleSpans[0];
+
+            _styleSpans = _styleSpans.Skip(1);
+
+            return new TextCharacters(_text.AsSlice(currentSpan.Start, currentSpan.Length),
+                _defaultStyle);
+        }
+    }
+}

+ 36 - 0
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/MultiBufferTextSource.cs

@@ -0,0 +1,36 @@
+using System;
+using Avalonia.Media.TextFormatting;
+using Avalonia.Utilities;
+
+namespace Avalonia.Skia.UnitTests.Media.TextFormatting
+{
+    internal class MultiBufferTextSource : ITextSource
+    {
+        private readonly string[] _runTexts;
+        private readonly GenericTextRunProperties _defaultStyle;
+
+        public MultiBufferTextSource(GenericTextRunProperties defaultStyle)
+        {
+            _defaultStyle = defaultStyle;
+
+            _runTexts = new[] { "A123456789", "B123456789", "C123456789", "D123456789", "E123456789" };
+        }
+
+        public static TextRange TextRange => new TextRange(0, 50);
+
+        public TextRun GetTextRun(int textSourceIndex)
+        {
+            if (textSourceIndex == 50)
+            {
+                return new TextEndOfParagraph();
+            }
+
+            var index = textSourceIndex / 10;
+
+            var runText = _runTexts[index];
+
+            return new TextCharacters(
+                new ReadOnlySlice<char>(runText.AsMemory(), textSourceIndex, runText.Length), _defaultStyle);
+        }
+    }
+}

Some files were not shown because too many files changed in this diff