32 changed files with 620 additions and 74 deletions
@ -1,4 +1,5 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"> |
|||
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> |
|||
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> |
|||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
|||
</manifest> |
|||
|
|||
@ -0,0 +1 @@ |
|||
DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend |
|||
@ -0,0 +1 @@ |
|||
DOTNET_DiagnosticPorts=10.0.2.2:9001,suspend |
|||
@ -0,0 +1,24 @@ |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Media |
|||
{ |
|||
internal class PlatformGeometry : Geometry |
|||
{ |
|||
private readonly IGeometryImpl _geometryImpl; |
|||
|
|||
public PlatformGeometry(IGeometryImpl geometryImpl) |
|||
{ |
|||
_geometryImpl = geometryImpl; |
|||
} |
|||
|
|||
public override Geometry Clone() |
|||
{ |
|||
return new PlatformGeometry(_geometryImpl); |
|||
} |
|||
|
|||
protected override IGeometryImpl? CreateDefiningGeometry() |
|||
{ |
|||
return _geometryImpl; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
using Avalonia.Metadata; |
|||
|
|||
namespace Avalonia.Controls.Templates; |
|||
|
|||
public interface ITypedDataTemplate : IDataTemplate |
|||
{ |
|||
[DataType] |
|||
Type? DataType { get; } |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using XamlX; |
|||
using XamlX.Ast; |
|||
using XamlX.Transform; |
|||
using XamlX.Transform.Transformers; |
|||
using XamlX.TypeSystem; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
|||
{ |
|||
internal class XDataTypeTransformer : IXamlAstTransformer |
|||
{ |
|||
private const string DataTypePropertyName = "DataType"; |
|||
|
|||
/// <summary>
|
|||
/// Converts x:DataType directives to regular DataType assignments if property with Avalonia.Metadata.DataTypeAttribute exists.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstObjectNode on) |
|||
{ |
|||
for (var c = 0; c < on.Children.Count; c++) |
|||
{ |
|||
var ch = on.Children[c]; |
|||
if (ch is XamlAstXmlDirective { Namespace: XamlNamespaces.Xaml2006, Name: DataTypePropertyName } d) |
|||
{ |
|||
if (on.Children.OfType<XamlAstXamlPropertyValueNode>() |
|||
.Any(p => ((XamlAstNamePropertyReference)p.Property)?.Name == DataTypePropertyName)) |
|||
{ |
|||
// Break iteration if any DataType property was already set by user code.
|
|||
break; |
|||
} |
|||
|
|||
var templateDataTypeAttribute = context.GetAvaloniaTypes().DataTypeAttribute; |
|||
|
|||
var clrType = (on.Type as XamlAstClrTypeReference)?.Type; |
|||
if (clrType is null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
// Technically it's possible to map "x:DataType" to a property with [DataType] attribute regardless of its name,
|
|||
// but we go explicitly strict here and check the name as well.
|
|||
var (declaringType, dataTypeProperty) = GetAllProperties(clrType) |
|||
.FirstOrDefault(t => t.property.Name == DataTypePropertyName && t.property.CustomAttributes |
|||
.Any(a => a.Type == templateDataTypeAttribute)); |
|||
|
|||
if (dataTypeProperty is not null) |
|||
{ |
|||
on.Children[c] = new XamlAstXamlPropertyValueNode(d, |
|||
new XamlAstNamePropertyReference(d, |
|||
new XamlAstClrTypeReference(ch, declaringType, false), dataTypeProperty.Name, |
|||
on.Type), |
|||
d.Values); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
private static IEnumerable<(IXamlType declaringType, IXamlProperty property)> GetAllProperties(IXamlType t) |
|||
{ |
|||
foreach (var p in t.Properties) |
|||
yield return (t, p); |
|||
if(t.BaseType!=null) |
|||
foreach (var tuple in GetAllProperties(t.BaseType)) |
|||
yield return tuple; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Documents; |
|||
using Avalonia.Controls.Shapes; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Imaging; |
|||
using Xunit; |
|||
|
|||
#if AVALONIA_SKIA
|
|||
namespace Avalonia.Skia.RenderTests |
|||
#else
|
|||
namespace Avalonia.Direct2D1.RenderTests.Media |
|||
#endif
|
|||
{ |
|||
public class GlyphRunTests : TestBase |
|||
{ |
|||
public GlyphRunTests() |
|||
: base(@"Media\GlyphRun") |
|||
{ |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Render_GlyphRun_Geometry() |
|||
{ |
|||
Decorator target = new Decorator |
|||
{ |
|||
Padding = new Thickness(8), |
|||
Width = 200, |
|||
Height = 100, |
|||
Child = new GlyphRunGeometryControl |
|||
{ |
|||
[TextElement.ForegroundProperty] = new LinearGradientBrush |
|||
{ |
|||
StartPoint = new RelativePoint(0, 0.5, RelativeUnit.Relative), |
|||
EndPoint = new RelativePoint(1, 0.5, RelativeUnit.Relative), |
|||
GradientStops = |
|||
{ |
|||
new GradientStop { Color = Colors.Red, Offset = 0 }, |
|||
new GradientStop { Color = Colors.Blue, Offset = 1 } |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
await RenderToFile(target); |
|||
|
|||
CompareImages(); |
|||
} |
|||
|
|||
public class GlyphRunGeometryControl : Control |
|||
{ |
|||
private readonly Geometry _geometry; |
|||
|
|||
public GlyphRunGeometryControl() |
|||
{ |
|||
var glyphTypeface = new Typeface(TestFontFamily).GlyphTypeface; |
|||
|
|||
var glyphIndices = new[] { glyphTypeface.GetGlyph('A'), glyphTypeface.GetGlyph('B'), glyphTypeface.GetGlyph('C') }; |
|||
|
|||
var characters = new[] { 'A', 'B', 'C' }; |
|||
|
|||
var glyphRun = new GlyphRun(glyphTypeface, 100, characters, glyphIndices); |
|||
|
|||
_geometry = glyphRun.BuildGeometry(); |
|||
} |
|||
|
|||
protected override Size MeasureOverride(Size availableSize) |
|||
{ |
|||
return _geometry.Bounds.Size; |
|||
} |
|||
|
|||
public override void Render(DrawingContext context) |
|||
{ |
|||
var foreground = TextElement.GetForeground(this); |
|||
|
|||
context.DrawGeometry(foreground, null, _geometry); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
Loading…
Reference in new issue