Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
StephaneDelcroix committed Nov 3, 2017
1 parent 43143bd commit 1b1f6ce
Show file tree
Hide file tree
Showing 35 changed files with 1,499 additions and 59 deletions.
24 changes: 22 additions & 2 deletions .nuspec/Xamarin.Forms.targets
@@ -1,5 +1,6 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.XamlGTask" AssemblyFile="Xamarin.Forms.Build.Tasks.dll"/>
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.CssGTask" AssemblyFile="Xamarin.Forms.Build.Tasks.dll"/>
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.XamlCTask" AssemblyFile="Xamarin.Forms.Build.Tasks.dll"/>
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.GetTasksAbi" AssemblyFile="Xamarin.Forms.Build.Tasks.dll"/>

Expand Down Expand Up @@ -33,7 +34,7 @@
</GetTasksAbi >

<PropertyGroup>
<_XFTasksExpectedAbi>3</_XFTasksExpectedAbi>
<_XFTasksExpectedAbi>4</_XFTasksExpectedAbi>
</PropertyGroup>

<Error
Expand Down Expand Up @@ -92,4 +93,23 @@
DebugType = "$(DebugType)"
KeepXamlResources = "$(XFKeepXamlResources)" />
</Target>
</Project>

<!-- CssG -->
<PropertyGroup>
<CoreCompileDependsOn>
CssG;
$(CoreCompileDependsOn);
</CoreCompileDependsOn>
</PropertyGroup>

<Target Name="CssG">
<CssGTask
XamlFiles="@(EmbeddedResource)" Condition="'%(Extension)' == '.css' AND '$(DefaultLanguageSourceExtension)' == '.cs'"
Language = "$(Language)"
AssemblyName = "$(AssemblyName)"
OutputPath = "$(IntermediateOutputPath)">
<Output ItemName="FilesWrite" TaskParameter="GeneratedCodeFiles" />
<Output ItemName="Compile" TaskParameter="GeneratedCodeFiles" />
</CssGTask>
</Target>
</Project>
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Mono.Cecil;
using Mono.Cecil.Cil;
Expand All @@ -13,6 +12,7 @@

namespace Xamarin.Forms.Core.XamlC
{

class RDSourceTypeConverter : ICompiledTypeConverter
{
public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
Expand Down Expand Up @@ -60,7 +60,7 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
yield return Create(Ldloc, uriVarDef);
}

static string GetPathForType(ModuleDefinition module, TypeReference type)
internal static string GetPathForType(ModuleDefinition module, TypeReference type)
{
foreach (var ca in type.Module.GetCustomAttributes()) {
if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference(typeof(XamlResourceIdAttribute))))
Expand All @@ -72,7 +72,7 @@ static string GetPathForType(ModuleDefinition module, TypeReference type)
return null;
}

static string GetResourceIdForPath(ModuleDefinition module, string path)
internal static string GetResourceIdForPath(ModuleDefinition module, string path)
{
foreach (var ca in module.GetCustomAttributes()) {
if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference(typeof(XamlResourceIdAttribute))))
Expand Down
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Mono.Cecil.Cil;

using static Mono.Cecil.Cil.Instruction;
using static Mono.Cecil.Cil.OpCodes;

using Xamarin.Forms.Build.Tasks;
using Xamarin.Forms.Xaml;

namespace Xamarin.Forms.Core.XamlC
{
class StyleSheetConverter : ICompiledTypeConverter
{
public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
{
var module = context.Body.Method.Module;
var body = context.Body;

INode rootNode = node;
while (!(rootNode is ILRootNode))
rootNode = rootNode.Parent;

var rootTargetPath = RDSourceTypeConverter.GetPathForType(module, ((ILRootNode)rootNode).TypeReference);
var uri = new Uri(value, UriKind.Relative);

var resourceId = ResourceDictionary.RDSourceTypeConverter.GetResourceId(uri, rootTargetPath, s => RDSourceTypeConverter.GetResourceIdForPath(module, s));

//return StyleSheet.Parse(rootObjectType.GetTypeInfo().Assembly, resourceId, lineInfo);

var getTypeFromHandle = module.ImportReference(typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }));
var getAssembly = module.ImportReference(typeof(Type).GetProperty("Assembly").GetGetMethod());
yield return Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference));
yield return Create(Call, module.ImportReference(getTypeFromHandle));
yield return Create(Callvirt, module.ImportReference(getAssembly)); //assembly

yield return Create(Ldstr, resourceId); //resourceId

foreach (var instruction in node.PushXmlLineInfo(context))
yield return instruction; //lineinfo

var styleSheetParse = module.ImportReference(typeof(StyleSheets.StyleSheet).GetMethods().FirstOrDefault(mi => mi.Name == "Parse" && mi.GetParameters().Length == 3));
yield return Create(Call, module.ImportReference(styleSheetParse));
}
}
}
55 changes: 55 additions & 0 deletions Xamarin.Forms.Build.Tasks/CssGTask.cs
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Xamarin.Forms.Build.Tasks
{
public class CssGTask : Task
{
readonly List<ITaskItem> _generatedCodeFiles = new List<ITaskItem>();

[Required]
public ITaskItem[] XamlFiles { get; set; }

[Output]
public ITaskItem[] GeneratedCodeFiles => _generatedCodeFiles.ToArray();

public string Language { get; set; }
public string AssemblyName { get; set; }
public string OutputPath { get; set; }

public override bool Execute()
{
bool success = true;

if (XamlFiles == null) {
Log.LogMessage("Skipping CssG");
return true;
}

foreach (var xamlFile in XamlFiles) {
var outputFile = Path.Combine(OutputPath, $"{xamlFile.GetMetadata("TargetPath")}.g.cs");
var generator = new CssGenerator(xamlFile, Language, AssemblyName, outputFile, Log);
try {
if (generator.Execute())
_generatedCodeFiles.Add(new TaskItem(Microsoft.Build.Evaluation.ProjectCollection.Escape(outputFile)));
}
catch (XmlException xe) {
Log.LogError(null, null, null, xamlFile.ItemSpec, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);

success = false;
}
catch (Exception e) {
Log.LogError(null, null, null, xamlFile.ItemSpec, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
success = false;
}
}

return success;
}
}
}
97 changes: 97 additions & 0 deletions Xamarin.Forms.Build.Tasks/CssGenerator.cs
@@ -0,0 +1,97 @@
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.CSharp;

using Xamarin.Forms.Xaml;

namespace Xamarin.Forms.Build.Tasks
{
class CssGenerator
{
internal CssGenerator()
{
}

public CssGenerator(
ITaskItem taskItem,
string language,
string assemblyName,
string outputFile,
TaskLoggingHelper logger)
: this(
taskItem.ItemSpec,
language,
taskItem.GetMetadata("ManifestResourceName"),
taskItem.GetMetadata("TargetPath"),
assemblyName,
outputFile,
logger)
{
}

internal static CodeDomProvider Provider = new CSharpCodeProvider();

public string CssFile { get; }
public string Language { get; }
public string ResourceId { get; }
public string TargetPath { get; }
public string AssemblyName { get; }
public string OutputFile { get; }
public TaskLoggingHelper Logger { get; }

public CssGenerator(
string cssFile,
string language,
string resourceId,
string targetPath,
string assemblyName,
string outputFile,
TaskLoggingHelper logger = null)
{
CssFile = cssFile;
Language = language;
ResourceId = resourceId;
TargetPath = targetPath;
AssemblyName = assemblyName;
OutputFile = outputFile;
Logger = logger;
}

//returns true if a file is generated
public bool Execute()
{
Logger?.LogMessage("Source: {0}", CssFile);
Logger?.LogMessage(" Language: {0}", Language);
Logger?.LogMessage(" ResourceID: {0}", ResourceId);
Logger?.LogMessage(" TargetPath: {0}", TargetPath);
Logger?.LogMessage(" AssemblyName: {0}", AssemblyName);
Logger?.LogMessage(" OutputFile {0}", OutputFile);

GenerateCode();

return true;
}

void GenerateCode()
{
//Create the target directory if required
Directory.CreateDirectory(Path.GetDirectoryName(OutputFile));

var ccu = new CodeCompileUnit();
ccu.AssemblyCustomAttributes.Add(
new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(XamlResourceIdAttribute).FullName}"),
new CodeAttributeArgument(new CodePrimitiveExpression(ResourceId)),
new CodeAttributeArgument(new CodePrimitiveExpression(TargetPath)),
new CodeAttributeArgument(new CodePrimitiveExpression(null))
));

//write the result
using (var writer = new StreamWriter(OutputFile))
Provider.GenerateCodeFromCompileUnit(ccu, writer, new CodeGeneratorOptions());
}
}
}
2 changes: 1 addition & 1 deletion Xamarin.Forms.Build.Tasks/GetTasksAbi.cs
Expand Up @@ -6,7 +6,7 @@ namespace Xamarin.Forms.Build.Tasks
public class GetTasksAbi : Task
{
[Output]
public string AbiVersion { get; } = "3";
public string AbiVersion { get; } = "4";

public override bool Execute()
=> true;
Expand Down
4 changes: 4 additions & 0 deletions Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs
Expand Up @@ -21,6 +21,10 @@ static string GetAssembly(TypeReference typeRef)

public bool Equals(TypeReference x, TypeReference y)
{
if (x == null)
return y == null;
if (y == null)
return x == null;
if (x.FullName != y.FullName)
return false;
var xasm = GetAssembly(x);
Expand Down
3 changes: 3 additions & 0 deletions Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
Expand Up @@ -102,6 +102,9 @@
<Compile Include="GetTasksAbi.cs" />
<Compile Include="CompiledConverters\UriTypeConverter.cs" />
<Compile Include="CompiledConverters\RDSourceTypeConverter.cs" />
<Compile Include="CssGTask.cs" />
<Compile Include="CssGenerator.cs" />
<Compile Include="CompiledConverters\StyleSheetConverter.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
Expand Down
16 changes: 14 additions & 2 deletions Xamarin.Forms.Core.UnitTests/LabelTests.cs
Expand Up @@ -189,8 +189,7 @@ public void FontSizeCanBeSetFromStyle ()
public void ManuallySetFontSizeNotOverridenByStyle ()
{
var label = new Label ();

Assert.AreEqual (10.0, label.FontSize);
Assume.That (label.FontSize, Is.EqualTo(10.0));

label.SetValue (Label.FontSizeProperty, 2.0, false);
Assert.AreEqual (2.0, label.FontSize);
Expand All @@ -199,6 +198,19 @@ public void ManuallySetFontSizeNotOverridenByStyle ()
Assert.AreEqual (2.0, label.FontSize);
}

[Test]
public void ManuallySetFontSizeNotOverridenByFontSetInStyle()
{
var label = new Label();
Assume.That(label.FontSize, Is.EqualTo(10.0));

label.SetValue(Label.FontSizeProperty, 2.0);
Assert.AreEqual(2.0, label.FontSize);

label.SetValue(Label.FontProperty, Font.SystemFontOfSize(1.0), fromStyle: true);
Assert.AreEqual(2.0, label.FontSize);
}

[Test]
public void ChangingHorizontalTextAlignmentFiresXAlignChanged ()
{
Expand Down
51 changes: 51 additions & 0 deletions Xamarin.Forms.Core.UnitTests/StyleSheets/IStylableTest.cs
@@ -0,0 +1,51 @@
using System;

using NUnit.Framework;

using Xamarin.Forms.Core.UnitTests;

namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class IStylableTest
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Internals.Registrar.RegisterAll(new Type[0]);
}

[TestCase]
public void GetBackgroundColor()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("background-color");
Assert.AreSame(VisualElement.BackgroundColorProperty, bp);
}

[TestCase]
public void GetLabelColor()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("color");
Assert.AreSame(Label.TextColorProperty, bp);
}

[TestCase]
public void GetEntryColor()
{
var entry = new Entry();
var bp = ((IStylable)entry).GetProperty("color");
Assert.AreSame(Entry.TextColorProperty, bp);
}

[TestCase]
public void GetGridColor()
{
var grid = new Grid();
var bp = ((IStylable)grid).GetProperty("color");
Assert.Null(bp);
}
}
}

0 comments on commit 1b1f6ce

Please sign in to comment.