Browse Source

Merge branch 'master' into fixes/buttonAccessKeyAltGr

pull/11090/head
Benedikt Stebner 4 years ago
committed by GitHub
parent
commit
de90d25aa8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Directory.Build.targets
  2. 104
      native/Avalonia.Native/src/OSX/AvnView.mm
  3. 2
      nukebuild/Build.cs
  4. 24
      nukebuild/Helpers.cs
  5. 171
      nukebuild/RefAssemblyGenerator.cs
  6. 13
      nukebuild/_build.csproj
  7. 4
      src/Avalonia.Base/Input/PointerEventArgs.cs
  8. 10
      src/Avalonia.Base/Media/PolyLineSegment.cs
  9. 18
      src/Avalonia.Base/Media/PolylineGeometry.cs
  10. 9
      src/Avalonia.Base/Metadata/PrivateApiAttribute.cs
  11. 2
      src/Avalonia.Base/Platform/ICursorFactory.cs
  12. 4
      src/Avalonia.Base/Platform/IPlatformRenderInterface.cs
  13. 14
      src/Avalonia.Base/Points.cs
  14. 8
      src/Avalonia.Base/Threading/IDispatcherImpl.cs
  15. 2
      src/Avalonia.Controls/Platform/IPlatformIconLoader.cs
  16. 2
      src/Avalonia.Controls/Platform/IWindowingPlatform.cs
  17. 6
      src/Avalonia.Controls/Primitives/Thumb.cs
  18. 9
      src/Avalonia.Controls/Shapes/Polygon.cs
  19. 9
      src/Avalonia.Controls/Shapes/Polyline.cs
  20. 71
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlArrayConstantAstNode.cs
  21. 138
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  22. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  23. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  24. 4
      tests/Avalonia.RenderTests/Shapes/PolygonTests.cs
  25. 4
      tests/Avalonia.RenderTests/Shapes/PolylineTests.cs

2
Directory.Build.targets

@ -1,5 +1,5 @@
<Project> <Project>
<PropertyGroup Condition="$(NETCoreSdkVersion.StartsWith('7.0'))"> <PropertyGroup Condition="$([MSBuild]::VersionGreaterThanOrEquals($(NETCoreSdkVersion), '7.0'))">
<DefineConstants>$(DefineConstants);NET7SDK</DefineConstants> <DefineConstants>$(DefineConstants);NET7SDK</DefineConstants>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

104
native/Avalonia.Native/src/OSX/AvnView.mm

@ -12,7 +12,6 @@
{ {
ComPtr<WindowBaseImpl> _parent; ComPtr<WindowBaseImpl> _parent;
NSTrackingArea* _area; NSTrackingArea* _area;
NSMutableAttributedString* _markedText;
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed; bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed;
AvnInputModifiers _modifierState; AvnInputModifiers _modifierState;
NSEvent* _lastMouseDownEvent; NSEvent* _lastMouseDownEvent;
@ -22,8 +21,9 @@
AvnPlatformResizeReason _resizeReason; AvnPlatformResizeReason _resizeReason;
AvnAccessibilityElement* _accessibilityChild; AvnAccessibilityElement* _accessibilityChild;
NSRect _cursorRect; NSRect _cursorRect;
NSMutableString* _text; NSMutableAttributedString* _text;
NSRange _selection; NSRange _selectedRange;
NSRange _markedRange;
} }
- (void)onClosed - (void)onClosed
@ -59,6 +59,11 @@
[self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]]; [self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]];
_modifierState = AvnInputModifiersNone; _modifierState = AvnInputModifiersNone;
_text = [[NSMutableAttributedString alloc] initWithString:@""];
_markedRange = NSMakeRange(0, 0);
_selectedRange = NSMakeRange(0, 0);
return self; return self;
} }
@ -521,9 +526,13 @@
- (void)keyDown:(NSEvent *)event - (void)keyDown:(NSEvent *)event
{ {
[self keyboardEvent:event withType:KeyDown]; _lastKeyHandled = false;
_lastKeyHandled = [[self inputContext] handleEvent:event];
[super keyDown:event]; [[self inputContext] handleEvent:event];
if(!_lastKeyHandled){
[self keyboardEvent:event withType:KeyDown];
}
} }
- (void)keyUp:(NSEvent *)event - (void)keyUp:(NSEvent *)event
@ -532,6 +541,10 @@
[super keyUp:event]; [super keyUp:event];
} }
- (void) doCommandBySelector:(SEL)selector{
}
- (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod - (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod
{ {
unsigned int rv = 0; unsigned int rv = 0;
@ -561,50 +574,52 @@
- (BOOL)hasMarkedText - (BOOL)hasMarkedText
{ {
return [_markedText length] > 0; return _markedRange.length > 0;
} }
- (NSRange)markedRange - (NSRange)markedRange
{ {
if([_markedText length] > 0) return _markedRange;
return NSMakeRange(0, [_markedText length] - 1);
return NSMakeRange(NSNotFound, 0);
} }
- (NSRange)selectedRange - (NSRange)selectedRange
{ {
return _selection; return _selectedRange;
} }
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange - (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{ {
_lastKeyHandled = true;
NSString* markedText;
if([string isKindOfClass:[NSAttributedString class]]) if([string isKindOfClass:[NSAttributedString class]])
{ {
_markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string]; markedText = [string string];
} }
else else
{ {
_markedText = [[NSMutableAttributedString alloc] initWithString:string]; markedText = (NSString*) string;
} }
if(!_parent->InputMethod->IsActive()){ _markedRange = NSMakeRange(_selectedRange.location, [markedText length]);
return;
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]);
} }
_parent->InputMethod->Client->SetPreeditText((char*)[_markedText.string UTF8String]);
} }
- (void)unmarkText - (void)unmarkText
{ {
[[_markedText mutableString] setString:@""]; if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText(nullptr);
}
[[self inputContext] discardMarkedText]; _markedRange = NSMakeRange(_selectedRange.location, 0);
if(!_parent->InputMethod->IsActive()){ if([self inputContext]) {
return; [[self inputContext] discardMarkedText];
} }
_parent->InputMethod->Client->SetPreeditText(nullptr);
} }
- (NSArray<NSString *> *)validAttributesForMarkedText - (NSArray<NSString *> *)validAttributesForMarkedText
@ -614,19 +629,38 @@
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{ {
return nullptr; if(actualRange){
range = *actualRange;
}
NSAttributedString* subString = [_text attributedSubstringFromRange:range];
return subString;
} }
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{ {
[self unmarkText]; if(_parent == nullptr){
return;
if(_parent != nullptr) }
NSString* text;
if([string isKindOfClass:[NSAttributedString class]])
{ {
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]); text = [string string];
}
else
{
text = (NSString*) string;
} }
[[self inputContext] invalidateCharacterCoordinates]; [self unmarkText];
uint32_t timestamp = static_cast<uint32_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]);
} }
- (NSUInteger)characterIndexForPoint:(NSPoint)point - (NSUInteger)characterIndexForPoint:(NSPoint)point
@ -746,15 +780,11 @@
} }
- (void) setText:(NSString *)text{ - (void) setText:(NSString *)text{
[_text setString:text]; [[_text mutableString] setString:text];
[[self inputContext] discardMarkedText];
} }
- (void) setSelection:(int)start :(int)end{ - (void) setSelection:(int)start :(int)end{
_selection = NSMakeRange(start, end - start); _selectedRange = NSMakeRange(start, end - start);
[[self inputContext] invalidateCharacterCoordinates];
} }
- (void) setCursorRect:(AvnRect)rect{ - (void) setCursorRect:(AvnRect)rect{
@ -766,7 +796,9 @@
_cursorRect = windowRectOnScreen; _cursorRect = windowRectOnScreen;
[[self inputContext] invalidateCharacterCoordinates]; if([self inputContext]) {
[[self inputContext] invalidateCharacterCoordinates];
}
} }
@end @end

2
nukebuild/Build.cs

@ -273,6 +273,8 @@ partial class Build : NukeBuild
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config, if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
new NumergeNukeLogger())) new NumergeNukeLogger()))
throw new Exception("Package merge failed"); throw new Exception("Package merge failed");
RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
Parameters.Version + ".nupkg");
}); });
Target RunTests => _ => _ Target RunTests => _ => _

24
nukebuild/Helpers.cs

@ -0,0 +1,24 @@
using System;
using System.IO;
using Nuke.Common.Utilities;
class Helpers
{
public static IDisposable UseTempDir(out string dir)
{
var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(path);
dir = path;
return DelegateDisposable.CreateBracket(null, () =>
{
try
{
Directory.Delete(path, true);
}
catch
{
// ignore
}
});
}
}

171
nukebuild/RefAssemblyGenerator.cs

@ -0,0 +1,171 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using ILRepacking;
using Mono.Cecil;
using Mono.Cecil.Cil;
public class RefAssemblyGenerator
{
class Resolver : DefaultAssemblyResolver, IAssemblyResolver
{
private readonly string _dir;
Dictionary<string, AssemblyDefinition> _cache = new();
public Resolver(string dir)
{
_dir = dir;
}
public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (_cache.TryGetValue(name.Name, out var asm))
return asm;
var path = Path.Combine(_dir, name.Name + ".dll");
if (File.Exists(path))
return _cache[name.Name] = AssemblyDefinition.ReadAssembly(path, parameters);
return base.Resolve(name, parameters);
}
}
public static void PatchRefAssembly(string file)
{
var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk");
var snk = new byte[reader.Length];
reader.Read(snk, 0, snk.Length);
var def = AssemblyDefinition.ReadAssembly(file, new ReaderParameters
{
ReadWrite = true,
InMemory = true,
ReadSymbols = true,
SymbolReaderProvider = new DefaultSymbolReaderProvider(false),
AssemblyResolver = new Resolver(Path.GetDirectoryName(file))
});
var obsoleteAttribute = def.MainModule.ImportReference(new TypeReference("System", "ObsoleteAttribute", def.MainModule,
def.MainModule.TypeSystem.CoreLibrary));
var obsoleteCtor = def.MainModule.ImportReference(new MethodReference(".ctor",
def.MainModule.TypeSystem.Void, obsoleteAttribute)
{
Parameters = { new ParameterDefinition(def.MainModule.TypeSystem.String) }
});
foreach(var t in def.MainModule.Types)
ProcessType(t, obsoleteCtor);
def.Write(file, new WriterParameters()
{
StrongNameKeyBlob = snk,
WriteSymbols = def.MainModule.HasSymbols,
SymbolWriterProvider = new EmbeddedPortablePdbWriterProvider(),
DeterministicMvid = def.MainModule.HasSymbols
});
}
static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor)
{
foreach (var nested in type.NestedTypes)
ProcessType(nested, obsoleteCtor);
if (type.IsInterface)
{
var hideMethods = type.Name.EndsWith("Impl")
|| (type.HasCustomAttributes && type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.PrivateApiAttribute"));
var injectMethod = hideMethods
|| type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.NotClientImplementableAttribute");
if (hideMethods)
{
foreach (var m in type.Methods)
{
var dflags = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.FamORAssem |
MethodAttributes.FamANDAssem | MethodAttributes.Assembly;
m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
}
}
if(injectMethod)
{
type.Methods.Add(new MethodDefinition("NotClientImplementable",
MethodAttributes.Assembly
| MethodAttributes.Abstract
| MethodAttributes.NewSlot
| MethodAttributes.HideBySig, type.Module.TypeSystem.Void));
}
var forceUnstable = type.CustomAttributes.Any(a =>
a.AttributeType.FullName == "Avalonia.Metadata.UnstableAttribute");
foreach (var m in type.Methods)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
foreach (var m in type.Properties)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
foreach (var m in type.Events)
MarkAsUnstable(m, obsoleteCtor, forceUnstable);
}
}
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, bool force)
{
if (!force && (
def.HasCustomAttributes == false
|| def.CustomAttributes.All(a => a.AttributeType.FullName != "Avalonia.Metadata.UnstableAttribute")))
return;
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
return;
def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
{
ConstructorArguments =
{
new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String,
"This is a part of unstable API and can be changed in minor releases. You have been warned")
}
});
}
public static void GenerateRefAsmsInPackage(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.FullName.StartsWith("ref/"))
entry.Delete();
}
foreach (var entry in archive.Entries.ToList())
{
if (entry.FullName.StartsWith("lib/") && entry.Name.EndsWith(".xml"))
{
var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
CompressionLevel.Optimal);
using (var src = entry.Open())
using (var dst = newEntry.Open())
src.CopyTo(dst);
}
}
var libs = archive.Entries.Where(e => e.FullName.StartsWith("lib/") && e.FullName.EndsWith(".dll"))
.Select((e => new { s = e.FullName.Split('/'), e = e }))
.Select(e => new { Tfm = e.s[1], Name = e.s[2], Entry = e.e })
.GroupBy(x => x.Tfm);
foreach(var tfm in libs)
using (Helpers.UseTempDir(out var temp))
{
foreach (var l in tfm)
l.Entry.ExtractToFile(Path.Combine(temp, l.Name));
foreach (var l in tfm)
PatchRefAssembly(Path.Combine(temp, l.Name));
foreach (var l in tfm)
archive.CreateEntryFromFile(Path.Combine(temp, l.Name), $"ref/{l.Tfm}/{l.Name}");
}
}
}
}

13
nukebuild/_build.csproj

@ -31,18 +31,11 @@
<!-- Common build related files --> <!-- Common build related files -->
<Compile Remove="Numerge/**/*.*" /> <Compile Remove="Numerge/**/*.*" />
<Compile Include="Numerge/Numerge/**/*.cs" /> <Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup> <EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<ItemGroup>
<EmbeddedResource Include="$(NuGetPackageRoot)sourcelink/1.1.0/tools/pdbstr.exe"></EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Remove="il-repack\ILRepack\Application.cs" /> <Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Numerge\Numerge.Console\" />
</ItemGroup>
</Project> </Project>

4
src/Avalonia.Base/Input/PointerEventArgs.cs

@ -77,14 +77,14 @@ namespace Avalonia.Input
/// <summary> /// <summary>
/// Gets the pointer position relative to a control. /// Gets the pointer position relative to a control.
/// </summary> /// </summary>
/// <param name="relativeTo">The control.</param> /// <param name="relativeTo">The visual whose coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns>The pointer position in the control's coordinates.</returns> /// <returns>The pointer position in the control's coordinates.</returns>
public Point GetPosition(Visual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo); public Point GetPosition(Visual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
/// <summary> /// <summary>
/// Returns the PointerPoint associated with the current event /// Returns the PointerPoint associated with the current event
/// </summary> /// </summary>
/// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param> /// <param name="relativeTo">The visual whose coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns></returns> /// <returns></returns>
public PointerPoint GetCurrentPoint(Visual? relativeTo) public PointerPoint GetCurrentPoint(Visual? relativeTo)
=> new PointerPoint(Pointer, GetPosition(relativeTo), _properties); => new PointerPoint(Pointer, GetPosition(relativeTo), _properties);

10
src/Avalonia.Base/Media/PolyLineSegment.cs

@ -10,8 +10,8 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Defines the <see cref="Points"/> property. /// Defines the <see cref="Points"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<Points> PointsProperty public static readonly StyledProperty<IList<Point>> PointsProperty
= AvaloniaProperty.Register<PolyLineSegment, Points>(nameof(Points)); = AvaloniaProperty.Register<PolyLineSegment, IList<Point>>(nameof(Points));
/// <summary> /// <summary>
/// Gets or sets the points. /// Gets or sets the points.
@ -19,7 +19,7 @@ namespace Avalonia.Media
/// <value> /// <value>
/// The points. /// The points.
/// </value> /// </value>
public Points Points public IList<Point> Points
{ {
get => GetValue(PointsProperty); get => GetValue(PointsProperty);
set => SetValue(PointsProperty, value); set => SetValue(PointsProperty, value);
@ -37,9 +37,9 @@ namespace Avalonia.Media
/// Initializes a new instance of the <see cref="PolyLineSegment"/> class. /// Initializes a new instance of the <see cref="PolyLineSegment"/> class.
/// </summary> /// </summary>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
public PolyLineSegment(IEnumerable<Point> points) : this() public PolyLineSegment(IEnumerable<Point> points)
{ {
Points.AddRange(points); Points = new Points(points);
} }
protected internal override void ApplyTo(StreamGeometryContext ctx) protected internal override void ApplyTo(StreamGeometryContext ctx)

18
src/Avalonia.Base/Media/PolylineGeometry.cs

@ -14,8 +14,8 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Defines the <see cref="Points"/> property. /// Defines the <see cref="Points"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<PolylineGeometry, Points> PointsProperty = public static readonly DirectProperty<PolylineGeometry, IList<Point>> PointsProperty =
AvaloniaProperty.RegisterDirect<PolylineGeometry, Points>(nameof(Points), g => g.Points, (g, f) => g.Points = f); AvaloniaProperty.RegisterDirect<PolylineGeometry, IList<Point>>(nameof(Points), g => g.Points, (g, f) => g.Points = f);
/// <summary> /// <summary>
/// Defines the <see cref="IsFilled"/> property. /// Defines the <see cref="IsFilled"/> property.
@ -23,13 +23,13 @@ namespace Avalonia.Media
public static readonly StyledProperty<bool> IsFilledProperty = public static readonly StyledProperty<bool> IsFilledProperty =
AvaloniaProperty.Register<PolylineGeometry, bool>(nameof(IsFilled)); AvaloniaProperty.Register<PolylineGeometry, bool>(nameof(IsFilled));
private Points _points; private IList<Point> _points;
private IDisposable? _pointsObserver; private IDisposable? _pointsObserver;
static PolylineGeometry() static PolylineGeometry()
{ {
AffectsGeometry(IsFilledProperty); AffectsGeometry(IsFilledProperty);
PointsProperty.Changed.AddClassHandler<PolylineGeometry>((s, e) => s.OnPointsChanged(e.NewValue as Points)); PointsProperty.Changed.AddClassHandler<PolylineGeometry>((s, e) => s.OnPointsChanged(e.NewValue as IList<Point>));
} }
/// <summary> /// <summary>
@ -43,9 +43,9 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PolylineGeometry"/> class. /// Initializes a new instance of the <see cref="PolylineGeometry"/> class.
/// </summary> /// </summary>
public PolylineGeometry(IEnumerable<Point> points, bool isFilled) : this() public PolylineGeometry(IEnumerable<Point> points, bool isFilled)
{ {
Points.AddRange(points); _points = new Points(points);
IsFilled = isFilled; IsFilled = isFilled;
} }
@ -56,7 +56,7 @@ namespace Avalonia.Media
/// The points. /// The points.
/// </value> /// </value>
[Content] [Content]
public Points Points public IList<Point> Points
{ {
get => _points; get => _points;
set => SetAndRaise(PointsProperty, ref _points, value); set => SetAndRaise(PointsProperty, ref _points, value);
@ -97,10 +97,10 @@ namespace Avalonia.Media
return geometry; return geometry;
} }
private void OnPointsChanged(Points? newValue) private void OnPointsChanged(IList<Point>? newValue)
{ {
_pointsObserver?.Dispose(); _pointsObserver?.Dispose();
_pointsObserver = newValue?.ForEachItem( _pointsObserver = (newValue as IAvaloniaList<Point>)?.ForEachItem(
_ => InvalidateGeometry(), _ => InvalidateGeometry(),
_ => InvalidateGeometry(), _ => InvalidateGeometry(),
InvalidateGeometry); InvalidateGeometry);

9
src/Avalonia.Base/Metadata/PrivateApiAttribute.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.Metadata;
[AttributeUsage(AttributeTargets.Interface)]
public sealed class PrivateApiAttribute : Attribute
{
}

2
src/Avalonia.Base/Platform/ICursorFactory.cs

@ -1,9 +1,11 @@
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Metadata;
#nullable enable #nullable enable
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
[PrivateApi]
public interface ICursorFactory public interface ICursorFactory
{ {
ICursorImpl GetCursor(StandardCursorType cursorType); ICursorImpl GetCursor(StandardCursorType cursorType);

4
src/Avalonia.Base/Platform/IPlatformRenderInterface.cs

@ -11,7 +11,7 @@ namespace Avalonia.Platform
/// <summary> /// <summary>
/// Defines the main platform-specific interface for the rendering subsystem. /// Defines the main platform-specific interface for the rendering subsystem.
/// </summary> /// </summary>
[Unstable] [Unstable, PrivateApi]
public interface IPlatformRenderInterface public interface IPlatformRenderInterface
{ {
/// <summary> /// <summary>
@ -201,7 +201,7 @@ namespace Avalonia.Platform
bool IsSupportedBitmapPixelFormat(PixelFormat format); bool IsSupportedBitmapPixelFormat(PixelFormat format);
} }
[Unstable] [Unstable, PrivateApi]
public interface IPlatformRenderInterfaceContext : IOptionalFeatureProvider, IDisposable public interface IPlatformRenderInterfaceContext : IOptionalFeatureProvider, IDisposable
{ {
/// <summary> /// <summary>

14
src/Avalonia.Base/Points.cs

@ -1,6 +1,18 @@
using System.Collections.Generic;
using Avalonia.Collections; using Avalonia.Collections;
namespace Avalonia namespace Avalonia
{ {
public sealed class Points : AvaloniaList<Point> { } public sealed class Points : AvaloniaList<Point>
{
public Points()
{
}
public Points(IEnumerable<Point> points) : base(points)
{
}
}
} }

8
src/Avalonia.Base/Threading/IDispatcherImpl.cs

@ -6,7 +6,7 @@ using Avalonia.Platform;
namespace Avalonia.Threading; namespace Avalonia.Threading;
[Unstable] [PrivateApi]
public interface IDispatcherImpl public interface IDispatcherImpl
{ {
bool CurrentThreadIsLoopThread { get; } bool CurrentThreadIsLoopThread { get; }
@ -19,7 +19,7 @@ public interface IDispatcherImpl
void UpdateTimer(long? dueTimeInMs); void UpdateTimer(long? dueTimeInMs);
} }
[Unstable] [PrivateApi]
public interface IDispatcherImplWithPendingInput : IDispatcherImpl public interface IDispatcherImplWithPendingInput : IDispatcherImpl
{ {
// Checks if dispatcher implementation can // Checks if dispatcher implementation can
@ -28,14 +28,14 @@ public interface IDispatcherImplWithPendingInput : IDispatcherImpl
bool HasPendingInput { get; } bool HasPendingInput { get; }
} }
[Unstable] [PrivateApi]
public interface IDispatcherImplWithExplicitBackgroundProcessing : IDispatcherImpl public interface IDispatcherImplWithExplicitBackgroundProcessing : IDispatcherImpl
{ {
event Action ReadyForBackgroundProcessing; event Action ReadyForBackgroundProcessing;
void RequestBackgroundProcessing(); void RequestBackgroundProcessing();
} }
[Unstable] [PrivateApi]
public interface IControlledDispatcherImpl : IDispatcherImplWithPendingInput public interface IControlledDispatcherImpl : IDispatcherImplWithPendingInput
{ {
// Runs the event loop // Runs the event loop

2
src/Avalonia.Controls/Platform/IPlatformIconLoader.cs

@ -3,7 +3,7 @@ using Avalonia.Metadata;
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
[Unstable] [Unstable, PrivateApi]
public interface IPlatformIconLoader public interface IPlatformIconLoader
{ {
IWindowIconImpl LoadIcon(string fileName); IWindowIconImpl LoadIcon(string fileName);

2
src/Avalonia.Controls/Platform/IWindowingPlatform.cs

@ -2,7 +2,7 @@ using Avalonia.Metadata;
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
[Unstable] [Unstable, PrivateApi]
public interface IWindowingPlatform public interface IWindowingPlatform
{ {
IWindowImpl CreateWindow(); IWindowImpl CreateWindow();

6
src/Avalonia.Controls/Primitives/Thumb.cs

@ -85,7 +85,7 @@ namespace Avalonia.Controls.Primitives
{ {
if (_lastPoint.HasValue) if (_lastPoint.HasValue)
{ {
var point = e.GetPosition(this.GetVisualParent()); var point = e.GetPosition(null);
var ev = new VectorEventArgs var ev = new VectorEventArgs
{ {
RoutedEvent = DragDeltaEvent, RoutedEvent = DragDeltaEvent,
@ -100,7 +100,7 @@ namespace Avalonia.Controls.Primitives
protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerPressed(PointerPressedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
_lastPoint = e.GetPosition(this.GetVisualParent()); _lastPoint = e.GetPosition(null);
var ev = new VectorEventArgs var ev = new VectorEventArgs
{ {
@ -123,7 +123,7 @@ namespace Avalonia.Controls.Primitives
var ev = new VectorEventArgs var ev = new VectorEventArgs
{ {
RoutedEvent = DragCompletedEvent, RoutedEvent = DragCompletedEvent,
Vector = (Vector)e.GetPosition(this.GetVisualParent()), Vector = (Vector)e.GetPosition(null),
}; };
RaiseEvent(ev); RaiseEvent(ev);

9
src/Avalonia.Controls/Shapes/Polygon.cs

@ -13,10 +13,15 @@ namespace Avalonia.Controls.Shapes
AffectsGeometry<Polygon>(PointsProperty); AffectsGeometry<Polygon>(PointsProperty);
} }
public Polygon()
{
Points = new Points();
}
public IList<Point> Points public IList<Point> Points
{ {
get { return GetValue(PointsProperty); } get => GetValue(PointsProperty);
set { SetValue(PointsProperty, value); } set => SetValue(PointsProperty, value);
} }
protected override Geometry CreateDefiningGeometry() protected override Geometry CreateDefiningGeometry()

9
src/Avalonia.Controls/Shapes/Polyline.cs

@ -14,10 +14,15 @@ namespace Avalonia.Controls.Shapes
AffectsGeometry<Polyline>(PointsProperty); AffectsGeometry<Polyline>(PointsProperty);
} }
public Polyline()
{
Points = new Points();
}
public IList<Point> Points public IList<Point> Points
{ {
get { return GetValue(PointsProperty); } get => GetValue(PointsProperty);
set { SetValue(PointsProperty, value); } set => SetValue(PointsProperty, value);
} }
protected override Geometry CreateDefiningGeometry() protected override Geometry CreateDefiningGeometry()

71
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlArrayConstantAstNode.cs

@ -0,0 +1,71 @@
using System.Collections.Generic;
using System.Reflection.Emit;
using Avalonia.Controls;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.Transform;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
{
class AvaloniaXamlIlArrayConstantAstNode : XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
{
private readonly IXamlType _elementType;
private readonly IReadOnlyList<IXamlAstValueNode> _values;
public AvaloniaXamlIlArrayConstantAstNode(IXamlLineInfo lineInfo, IXamlType arrayType, IXamlType elementType, IReadOnlyList<IXamlAstValueNode> values) : base(lineInfo)
{
_elementType = elementType;
_values = values;
Type = new XamlAstClrTypeReference(lineInfo, arrayType, false);
foreach (var element in values)
{
if (!elementType.IsAssignableFrom(element.Type.GetClrType()))
{
throw new XamlParseException("x:Array element is not assignable to the array element type!", lineInfo);
}
}
}
public IXamlAstTypeReference Type { get; }
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
codeGen.Ldc_I4(_values.Count)
.Newarr(_elementType);
for (var index = 0; index < _values.Count; index++)
{
var value = _values[index];
codeGen
.Dup()
.Ldc_I4(index);
context.Emit(value, codeGen, _elementType);
if (value.Type.GetClrType() is { IsValueType: true } valTypeInObjArr)
{
if (!_elementType.IsValueType)
{
codeGen.Box(valTypeInObjArr);
}
// It seems like ASM codegen for "stelem valuetype" and "stelem.i4" is identical,
// so we don't need to try to optimize it here.
codeGen.Emit(OpCodes.Stelem, valTypeInObjArr);
}
else
{
codeGen.Stelem_ref();
}
}
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
}

138
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

@ -198,6 +198,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node); throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node);
} }
} }
if (type.Equals(types.ColumnDefinition) || type.Equals(types.RowDefinition))
{
try
{
var gridLength = GridLength.Parse(text);
result = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
var definitionConstructorGridLength = type.GetConstructor(new List<IXamlType> {types.GridLength});
var lengthNode = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
var definitionTypeRef = new XamlAstClrTypeReference(node, type, false);
result = new XamlAstNewClrObjectNode(node, definitionTypeRef,
definitionConstructorGridLength, new List<IXamlAstValueNode> {lengthNode});
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node);
}
}
if (type.Equals(types.Cursor)) if (type.Equals(types.Cursor))
{ {
@ -211,16 +234,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
} }
if (type.Equals(types.ColumnDefinitions))
{
return ConvertDefinitionList(node, text, types, types.ColumnDefinitions, types.ColumnDefinition, "column definitions", out result);
}
if (type.Equals(types.RowDefinitions))
{
return ConvertDefinitionList(node, text, types, types.RowDefinitions, types.RowDefinition, "row definitions", out result);
}
if (types.IBrush.IsAssignableFrom(type)) if (types.IBrush.IsAssignableFrom(type))
{ {
if (Color.TryParse(text, out Color color)) if (Color.TryParse(text, out Color color))
@ -295,46 +308,89 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
} }
} }
result = null; // Keep it in the end, so more specific parsers can be applied.
return false; var elementType = GetElementType(type, context.Configuration.WellKnownTypes);
} if (elementType is not null)
private static bool ConvertDefinitionList(
IXamlAstValueNode node,
string text,
AvaloniaXamlIlWellKnownTypes types,
IXamlType listType,
IXamlType elementType,
string errorDisplayName,
out IXamlAstValueNode result)
{
try
{ {
var lengths = GridLength.ParseLengths(text); string[] items;
// Normalize special case of Points collection.
var definitionTypeRef = new XamlAstClrTypeReference(node, elementType, false); if (elementType == types.Point)
{
var pointParts = text.Split(new[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries);
if (pointParts.Length % 2 == 0)
{
items = new string[pointParts.Length / 2];
for (int i = 0; i < pointParts.Length; i += 2)
{
items[i / 2] = string.Format(CultureInfo.InvariantCulture, "{0} {1}", pointParts[i],
pointParts[i + 1]);
}
}
else
{
throw new XamlX.XamlLoadException($"Invalid PointsList.", node);
}
}
else
{
const StringSplitOptions trimOption = (StringSplitOptions)2; // StringSplitOptions.TrimEntries
var separators = new[] { "," };
var splitOptions = StringSplitOptions.RemoveEmptyEntries | trimOption;
var definitionConstructorGridLength = elementType.GetConstructor(new List<IXamlType> {types.GridLength}); items = text.Split(separators, splitOptions ^ trimOption);
// Compiler targets netstandard, so we need to emulate StringSplitOptions.TrimEntries, if it was requested.
if (splitOptions.HasFlag(trimOption))
{
items = items.Select(i => i.Trim()).ToArray();
}
}
IXamlAstValueNode CreateDefinitionNode(GridLength length) var nodes = new IXamlAstValueNode[items.Length];
for (var index = 0; index < items.Length; index++)
{ {
var lengthNode = new AvaloniaXamlIlGridLengthAstNode(node, types, length); var success = XamlTransformHelpers.TryGetCorrectlyTypedValue(
context,
new XamlAstTextNode(node, items[index], true, context.Configuration.WellKnownTypes.String),
elementType, out var itemNode);
if (!success)
{
result = null;
return false;
}
return new XamlAstNewClrObjectNode(node, definitionTypeRef, nodes[index] = itemNode;
definitionConstructorGridLength, new List<IXamlAstValueNode> {lengthNode});
} }
var definitionNodes = if (types.AvaloniaList.MakeGenericType(elementType).IsAssignableFrom(type))
new List<IXamlAstValueNode>(lengths.Select(CreateDefinitionNode)); {
result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, type, elementType, nodes);
result = new AvaloniaXamlIlAvaloniaListConstantAstNode(node, types, listType, elementType, definitionNodes); return true;
}
else if (type.IsArray)
{
result = new AvaloniaXamlIlArrayConstantAstNode(node, elementType.MakeArrayType(1), elementType, nodes);
return true;
}
else if (type == context.Configuration.WellKnownTypes.IListOfT.MakeGenericType(elementType))
{
var listType = context.Configuration.WellKnownTypes.IListOfT.MakeGenericType(elementType);
result = new AvaloniaXamlIlArrayConstantAstNode(node, listType, elementType, nodes);
return true;
}
return true; result = null;
} return false;
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a {errorDisplayName}", node);
} }
result = null;
return false;
}
private static IXamlType GetElementType(IXamlType type, XamlTypeWellKnownTypes types)
{
return type.GetAllInterfaces().FirstOrDefault(i =>
i.FullName.StartsWith(types.IEnumerableT.FullName))?
.GenericArguments[0];
} }
} }
} }

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -33,6 +33,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType InheritDataTypeFromItemsAttribute { get; } public IXamlType InheritDataTypeFromItemsAttribute { get; }
public IXamlType MarkupExtensionOptionAttribute { get; } public IXamlType MarkupExtensionOptionAttribute { get; }
public IXamlType MarkupExtensionDefaultOptionAttribute { get; } public IXamlType MarkupExtensionDefaultOptionAttribute { get; }
public IXamlType AvaloniaList { get; }
public IXamlType OnExtensionType { get; } public IXamlType OnExtensionType { get; }
public IXamlType UnsetValueType { get; } public IXamlType UnsetValueType { get; }
public IXamlType StyledElement { get; } public IXamlType StyledElement { get; }
@ -141,6 +142,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
InheritDataTypeFromItemsAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.InheritDataTypeFromItemsAttribute"); InheritDataTypeFromItemsAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.InheritDataTypeFromItemsAttribute");
MarkupExtensionOptionAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.MarkupExtensionOptionAttribute"); MarkupExtensionOptionAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.MarkupExtensionOptionAttribute");
MarkupExtensionDefaultOptionAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.MarkupExtensionDefaultOptionAttribute"); MarkupExtensionDefaultOptionAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.MarkupExtensionDefaultOptionAttribute");
AvaloniaList = cfg.TypeSystem.GetType("Avalonia.Collections.AvaloniaList`1");
OnExtensionType = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.On"); OnExtensionType = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.On");
AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, AvaloniaObject, AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, AvaloniaObject,
AvaloniaProperty, AvaloniaProperty,

2
src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

@ -1 +1 @@
Subproject commit 5dd0b042e144e677638224c49fec16dab66143e8 Subproject commit 5d1025f30d0ed6d8f419d82959c148276301f393

4
tests/Avalonia.RenderTests/Shapes/PolygonTests.cs

@ -30,7 +30,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
Stroke = Brushes.DarkBlue, Stroke = Brushes.DarkBlue,
Stretch = Stretch.Uniform, Stretch = Stretch.Uniform,
Fill = Brushes.Violet, Fill = Brushes.Violet,
Points = new [] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, Points = new Points { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) },
StrokeThickness = 1 StrokeThickness = 1
} }
}; };
@ -52,7 +52,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
Stroke = Brushes.DarkBlue, Stroke = Brushes.DarkBlue,
Stretch = Stretch.Fill, Stretch = Stretch.Fill,
Fill = Brushes.Violet, Fill = Brushes.Violet,
Points = new[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, Points = new Points { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) },
StrokeThickness = 5, StrokeThickness = 5,
} }
}; };

4
tests/Avalonia.RenderTests/Shapes/PolylineTests.cs

@ -20,7 +20,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
[Fact] [Fact]
public async Task Polyline_1px_Stroke() public async Task Polyline_1px_Stroke()
{ {
var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), var polylinePoints = new Points { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3),
new Point(9, 1), new Point(10, 0), new Point(15, 0) }; new Point(9, 1), new Point(10, 0), new Point(15, 0) };
Decorator target = new Decorator Decorator target = new Decorator
@ -44,7 +44,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
[Fact] [Fact]
public async Task Polyline_10px_Stroke_PenLineJoin() public async Task Polyline_10px_Stroke_PenLineJoin()
{ {
var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), var polylinePoints = new Points { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3),
new Point(9, 1), new Point(10, 0), new Point(15, 0) }; new Point(9, 1), new Point(10, 0), new Point(15, 0) };
Decorator target = new Decorator Decorator target = new Decorator

Loading…
Cancel
Save