|
@@ -72,12 +72,38 @@ namespace Avalonia.Build.Tasks
|
|
asm.MainModule.ImportReference(editorBrowsableAttribute.GetConstructors()
|
|
asm.MainModule.ImportReference(editorBrowsableAttribute.GetConstructors()
|
|
.First(c => c.Parameters.Count == 1));
|
|
.First(c => c.Parameters.Count == 1));
|
|
|
|
|
|
|
|
+
|
|
|
|
+ var loaderDispatcherDef = new TypeDefinition("CompiledAvaloniaXaml", "!XamlLoader",
|
|
|
|
+ TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ loaderDispatcherDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
|
|
|
|
+ {
|
|
|
|
+ ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)}
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ var loaderDispatcherMethod = new MethodDefinition("TryLoad",
|
|
|
|
+ MethodAttributes.Static | MethodAttributes.Public,
|
|
|
|
+ asm.MainModule.TypeSystem.Object)
|
|
|
|
+ {
|
|
|
|
+ Parameters = {new ParameterDefinition(asm.MainModule.TypeSystem.String)}
|
|
|
|
+ };
|
|
|
|
+ loaderDispatcherDef.Methods.Add(loaderDispatcherMethod);
|
|
|
|
+ asm.MainModule.Types.Add(loaderDispatcherDef);
|
|
|
|
+
|
|
|
|
+ var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First(
|
|
|
|
+ m =>
|
|
|
|
+ m.IsStatic && m.Name == "Equals" && m.Parameters.Count == 2 &&
|
|
|
|
+ m.ReturnType.FullName == "System.Boolean"
|
|
|
|
+ && m.Parameters[0].ParameterType.FullName == "System.String"
|
|
|
|
+ && m.Parameters[1].ParameterType.FullName == "System.String"));
|
|
|
|
+
|
|
bool CompileGroup(IResourceGroup group)
|
|
bool CompileGroup(IResourceGroup group)
|
|
{
|
|
{
|
|
- var typeDef = new TypeDefinition("CompiledAvaloniaXaml", group.Name,
|
|
|
|
|
|
+ var typeDef = new TypeDefinition("CompiledAvaloniaXaml", "!"+ group.Name,
|
|
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
|
|
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
|
|
|
|
|
|
-
|
|
|
|
typeDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
|
|
typeDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
|
|
{
|
|
{
|
|
ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)}
|
|
ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)}
|
|
@@ -87,6 +113,8 @@ namespace Avalonia.Build.Tasks
|
|
|
|
|
|
foreach (var res in group.Resources.Where(CheckXamlName))
|
|
foreach (var res in group.Resources.Where(CheckXamlName))
|
|
{
|
|
{
|
|
|
|
+ if(res.Name.Contains("DefaultTheme"))
|
|
|
|
+ Console.WriteLine();
|
|
try
|
|
try
|
|
{
|
|
{
|
|
// StreamReader is needed here to handle BOM
|
|
// StreamReader is needed here to handle BOM
|
|
@@ -114,15 +142,18 @@ namespace Avalonia.Build.Tasks
|
|
compiler.Compile(parsed, builder, contextClass,
|
|
compiler.Compile(parsed, builder, contextClass,
|
|
populateName, buildName,
|
|
populateName, buildName,
|
|
"NamespaceInfo:" + res.Name, res.Uri);
|
|
"NamespaceInfo:" + res.Name, res.Uri);
|
|
|
|
+
|
|
|
|
+ var classTypeDefinition =
|
|
|
|
+ classType == null ? null : typeSystem.GetTypeReference(classType).Resolve();
|
|
|
|
|
|
- if (classType != null)
|
|
|
|
|
|
+ if (classTypeDefinition != null)
|
|
{
|
|
{
|
|
var compiledPopulateMethod = typeSystem.GetTypeReference(builder).Resolve()
|
|
var compiledPopulateMethod = typeSystem.GetTypeReference(builder).Resolve()
|
|
.Methods.First(m => m.Name == populateName);
|
|
.Methods.First(m => m.Name == populateName);
|
|
- var classTypeDefinition = typeSystem.GetTypeReference(classType).Resolve();
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- var trampoline = new MethodDefinition("!XamlIlPopulateTrampoline",
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ const string TrampolineName = "!XamlIlPopulateTrampoline";
|
|
|
|
+ var trampoline = new MethodDefinition(TrampolineName,
|
|
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
|
|
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
|
|
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
|
|
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
|
|
classTypeDefinition.Methods.Add(trampoline);
|
|
classTypeDefinition.Methods.Add(trampoline);
|
|
@@ -143,6 +174,16 @@ namespace Avalonia.Build.Tasks
|
|
&& i[c].OpCode == OpCodes.Call)
|
|
&& i[c].OpCode == OpCodes.Call)
|
|
{
|
|
{
|
|
var op = i[c].Operand as MethodReference;
|
|
var op = i[c].Operand as MethodReference;
|
|
|
|
+
|
|
|
|
+ // TODO: Throw an error
|
|
|
|
+ // This usually happens when same XAML resource was added twice for some weird reason
|
|
|
|
+ // We currently support it for dual-named default theme resource
|
|
|
|
+ if (op != null
|
|
|
|
+ && op.Name == TrampolineName)
|
|
|
|
+ {
|
|
|
|
+ foundXamlLoader = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
if (op != null
|
|
if (op != null
|
|
&& op.Name == "Load"
|
|
&& op.Name == "Load"
|
|
&& op.Parameters.Count == 1
|
|
&& op.Parameters.Count == 1
|
|
@@ -158,9 +199,10 @@ namespace Avalonia.Build.Tasks
|
|
|
|
|
|
if (!foundXamlLoader)
|
|
if (!foundXamlLoader)
|
|
{
|
|
{
|
|
- var ctors = classTypeDefinition.GetConstructors().ToList();
|
|
|
|
|
|
+ var ctors = classTypeDefinition.GetConstructors()
|
|
|
|
+ .Where(c => !c.IsStatic).ToList();
|
|
// We can inject xaml loader into default constructor
|
|
// We can inject xaml loader into default constructor
|
|
- if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode!=OpCodes.Nop) == 3)
|
|
|
|
|
|
+ if (ctors.Count == 1 && ctors[0].Body.Instructions.Count(o=>o.OpCode != OpCodes.Nop) == 3)
|
|
{
|
|
{
|
|
var i = ctors[0].Body.Instructions;
|
|
var i = ctors[0].Body.Instructions;
|
|
var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret));
|
|
var retIdx = i.IndexOf(i.Last(x => x.OpCode == OpCodes.Ret));
|
|
@@ -175,6 +217,39 @@ namespace Avalonia.Build.Tasks
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (buildName != null || classTypeDefinition != null)
|
|
|
|
+ {
|
|
|
|
+ var compiledBuildMethod = buildName == null ?
|
|
|
|
+ null :
|
|
|
|
+ typeSystem.GetTypeReference(builder).Resolve()
|
|
|
|
+ .Methods.First(m => m.Name == buildName);
|
|
|
|
+ var parameterlessConstructor = compiledBuildMethod != null ?
|
|
|
|
+ null :
|
|
|
|
+ classTypeDefinition.GetConstructors().FirstOrDefault(c =>
|
|
|
|
+ c.IsPublic && !c.IsStatic && !c.HasParameters);
|
|
|
|
+
|
|
|
|
+ if (compiledBuildMethod != null || parameterlessConstructor != null)
|
|
|
|
+ {
|
|
|
|
+ var i = loaderDispatcherMethod.Body.Instructions;
|
|
|
|
+ var nop = Instruction.Create(OpCodes.Nop);
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Ldarg_0));
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Ldstr, res.Uri));
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Call, stringEquals));
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Brfalse, nop));
|
|
|
|
+ if (parameterlessConstructor != null)
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor));
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Ldnull));
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ i.Add(Instruction.Create(OpCodes.Ret));
|
|
|
|
+ i.Add(nop);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
catch (Exception e)
|
|
{
|
|
{
|
|
@@ -191,11 +266,9 @@ namespace Avalonia.Build.Tasks
|
|
}
|
|
}
|
|
res.Remove();
|
|
res.Remove();
|
|
}
|
|
}
|
|
-
|
|
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
if (emres.Resources.Count(CheckXamlName) != 0)
|
|
if (emres.Resources.Count(CheckXamlName) != 0)
|
|
if (!CompileGroup(emres))
|
|
if (!CompileGroup(emres))
|
|
return new CompileResult(false);
|
|
return new CompileResult(false);
|
|
@@ -205,7 +278,10 @@ namespace Avalonia.Build.Tasks
|
|
return new CompileResult(false);
|
|
return new CompileResult(false);
|
|
avares.Save();
|
|
avares.Save();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
|
|
|
|
+ loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
|
|
|
+
|
|
var ms = new MemoryStream();
|
|
var ms = new MemoryStream();
|
|
asm.Write(ms);
|
|
asm.Write(ms);
|
|
return new CompileResult(true, ms.ToArray());
|
|
return new CompileResult(true, ms.ToArray());
|