102 changed files with 1358 additions and 636 deletions
@ -1,6 +1,6 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="HarfBuzzSharp" Version="2.6.1.5" /> |
<PackageReference Include="HarfBuzzSharp" Version="2.6.1.6" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.6.1.5" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.6.1.6" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Platform.Interop; |
||||
|
|
||||
|
namespace Avalonia.OpenGL.Angle |
||||
|
{ |
||||
|
public class AngleEglInterface : EglInterface |
||||
|
{ |
||||
|
[DllImport("libegl.dll", CharSet = CharSet.Ansi)] |
||||
|
static extern IntPtr eglGetProcAddress(string proc); |
||||
|
|
||||
|
public AngleEglInterface() : base(LoadAngle()) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
static Func<string, IntPtr> LoadAngle() |
||||
|
{ |
||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
||||
|
throw new PlatformNotSupportedException(); |
||||
|
{ |
||||
|
var disp = eglGetProcAddress("eglGetPlatformDisplayEXT"); |
||||
|
if (disp == IntPtr.Zero) |
||||
|
throw new OpenGlException("libegl.dll doesn't have eglGetPlatformDisplayEXT entry point"); |
||||
|
return eglGetProcAddress; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,88 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
using static Avalonia.OpenGL.EglConsts; |
||||
|
|
||||
|
namespace Avalonia.OpenGL.Angle |
||||
|
{ |
||||
|
public class AngleWin32EglDisplay : EglDisplay |
||||
|
{ |
||||
|
struct AngleInfo |
||||
|
{ |
||||
|
public IntPtr Display { get; set; } |
||||
|
public AngleOptions.PlatformApi PlatformApi { get; set; } |
||||
|
} |
||||
|
|
||||
|
static AngleInfo CreateAngleDisplay(EglInterface _egl) |
||||
|
{ |
||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
||||
|
throw new PlatformNotSupportedException(); |
||||
|
var display = IntPtr.Zero; |
||||
|
AngleOptions.PlatformApi angleApi = default; |
||||
|
{ |
||||
|
if (_egl.GetPlatformDisplayEXT == null) |
||||
|
throw new OpenGlException("eglGetPlatformDisplayEXT is not supported by libegl.dll"); |
||||
|
|
||||
|
var allowedApis = AvaloniaLocator.Current.GetService<AngleOptions>()?.AllowedPlatformApis |
||||
|
?? new [] { AngleOptions.PlatformApi.DirectX11, AngleOptions.PlatformApi.DirectX9 }; |
||||
|
|
||||
|
foreach (var platformApi in allowedApis) |
||||
|
{ |
||||
|
int dapi; |
||||
|
if (platformApi == AngleOptions.PlatformApi.DirectX9) |
||||
|
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE; |
||||
|
else if (platformApi == AngleOptions.PlatformApi.DirectX11) |
||||
|
dapi = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE; |
||||
|
else |
||||
|
continue; |
||||
|
|
||||
|
display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, |
||||
|
new[] { EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE }); |
||||
|
if (display != IntPtr.Zero) |
||||
|
{ |
||||
|
angleApi = platformApi; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (display == IntPtr.Zero) |
||||
|
throw new OpenGlException("Unable to create ANGLE display"); |
||||
|
return new AngleInfo { Display = display, PlatformApi = angleApi }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private AngleWin32EglDisplay(EglInterface egl, AngleInfo info) : base(egl, info.Display) |
||||
|
{ |
||||
|
PlatformApi = info.PlatformApi; |
||||
|
} |
||||
|
|
||||
|
public AngleWin32EglDisplay(EglInterface egl) : this(egl, CreateAngleDisplay(egl)) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public AngleWin32EglDisplay() : this(new AngleEglInterface()) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public AngleOptions.PlatformApi PlatformApi { get; } |
||||
|
|
||||
|
public IntPtr GetDirect3DDevice() |
||||
|
{ |
||||
|
if (!EglInterface.QueryDisplayAttribExt(Handle, EglConsts.EGL_DEVICE_EXT, out var eglDevice)) |
||||
|
throw new OpenGlException("Unable to get EGL_DEVICE_EXT"); |
||||
|
if (!EglInterface.QueryDeviceAttribExt(eglDevice, PlatformApi == AngleOptions.PlatformApi.DirectX9 ? EGL_D3D9_DEVICE_ANGLE : EGL_D3D11_DEVICE_ANGLE, out var d3dDeviceHandle)) |
||||
|
throw new OpenGlException("Unable to get EGL_D3D9_DEVICE_ANGLE"); |
||||
|
return d3dDeviceHandle; |
||||
|
} |
||||
|
|
||||
|
public EglSurface WrapDirect3D11Texture(IntPtr handle) |
||||
|
{ |
||||
|
if (PlatformApi != AngleOptions.PlatformApi.DirectX11) |
||||
|
throw new InvalidOperationException("Current platform API is " + PlatformApi); |
||||
|
return CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,103 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.OpenGL |
||||
|
{ |
||||
|
public abstract class EglGlPlatformSurfaceBase : IGlPlatformSurface |
||||
|
{ |
||||
|
public interface IEglWindowGlPlatformSurfaceInfo |
||||
|
{ |
||||
|
IntPtr Handle { get; } |
||||
|
PixelSize Size { get; } |
||||
|
double Scaling { get; } |
||||
|
} |
||||
|
|
||||
|
public abstract IGlPlatformSurfaceRenderTarget CreateGlRenderTarget(); |
||||
|
} |
||||
|
|
||||
|
public abstract class EglPlatformSurfaceRenderTargetBase : IGlPlatformSurfaceRenderTargetWithCorruptionInfo |
||||
|
{ |
||||
|
private readonly EglDisplay _display; |
||||
|
private readonly EglContext _context; |
||||
|
|
||||
|
protected EglPlatformSurfaceRenderTargetBase(EglDisplay display, EglContext context) |
||||
|
{ |
||||
|
_display = display; |
||||
|
_context = context; |
||||
|
} |
||||
|
|
||||
|
public abstract bool IsCorrupted { get; } |
||||
|
|
||||
|
public virtual void Dispose() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public abstract IGlPlatformSurfaceRenderingSession BeginDraw(); |
||||
|
|
||||
|
protected IGlPlatformSurfaceRenderingSession BeginDraw(EglSurface surface, |
||||
|
EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info, Action onFinish = null, bool isYFlipped = false) |
||||
|
{ |
||||
|
var l = _context.Lock(); |
||||
|
try |
||||
|
{ |
||||
|
if (IsCorrupted) |
||||
|
throw new RenderTargetCorruptedException(); |
||||
|
var restoreContext = _context.MakeCurrent(surface); |
||||
|
_display.EglInterface.WaitClient(); |
||||
|
_display.EglInterface.WaitGL(); |
||||
|
_display.EglInterface.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE); |
||||
|
|
||||
|
return new Session(_display, _context, surface, info, l, restoreContext, onFinish, isYFlipped); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
l.Dispose(); |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class Session : IGlPlatformSurfaceRenderingSession |
||||
|
{ |
||||
|
private readonly EglContext _context; |
||||
|
private readonly EglSurface _glSurface; |
||||
|
private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info; |
||||
|
private readonly EglDisplay _display; |
||||
|
private readonly IDisposable _lock; |
||||
|
private readonly IDisposable _restoreContext; |
||||
|
private readonly Action _onFinish; |
||||
|
|
||||
|
|
||||
|
public Session(EglDisplay display, EglContext context, |
||||
|
EglSurface glSurface, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info, |
||||
|
IDisposable @lock, IDisposable restoreContext, Action onFinish, bool isYFlipped) |
||||
|
{ |
||||
|
IsYFlipped = isYFlipped; |
||||
|
_context = context; |
||||
|
_display = display; |
||||
|
_glSurface = glSurface; |
||||
|
_info = info; |
||||
|
_lock = @lock; |
||||
|
_restoreContext = restoreContext; |
||||
|
_onFinish = onFinish; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
_context.GlInterface.Flush(); |
||||
|
_display.EglInterface.WaitGL(); |
||||
|
_glSurface.SwapBuffers(); |
||||
|
_display.EglInterface.WaitClient(); |
||||
|
_display.EglInterface.WaitGL(); |
||||
|
_display.EglInterface.WaitNative(EglConsts.EGL_CORE_NATIVE_ENGINE); |
||||
|
_restoreContext.Dispose(); |
||||
|
_lock.Dispose(); |
||||
|
_onFinish?.Invoke(); |
||||
|
} |
||||
|
|
||||
|
public IGlContext Context => _context; |
||||
|
public PixelSize Size => _info.Size; |
||||
|
public double Scaling => _info.Scaling; |
||||
|
public bool IsYFlipped { get; } |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<PackageId>Avalonia.ReactiveUI</PackageId> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Pharmacist.Common" Version="1.8.1" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
Compat issues with assembly Avalonia.Visuals: |
||||
|
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract. |
||||
|
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract. |
||||
|
CannotSealType : Type 'Avalonia.Media.Typeface' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. |
||||
|
TypeCannotChangeClassification : Type 'Avalonia.Media.Typeface' is a 'struct' in the implementation but is a 'class' in the contract. |
||||
|
CannotMakeMemberNonVirtual : Member 'public System.Boolean Avalonia.Media.Typeface.Equals(System.Object)' is non-virtual in the implementation but is virtual in the contract. |
||||
|
CannotMakeMemberNonVirtual : Member 'public System.Int32 Avalonia.Media.Typeface.GetHashCode()' is non-virtual in the implementation but is virtual in the contract. |
||||
|
TypesMustExist : Type 'Avalonia.Media.Fonts.FontKey' does not exist in the implementation but it does exist in the contract. |
||||
|
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak' is abstract in the implementation but is missing in the contract. |
||||
|
MembersMustExist : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.LineBreak.get()' does not exist in the implementation but it does exist in the contract. |
||||
|
CannotAddAbstractMembers : Member 'public Avalonia.Media.TextFormatting.TextLineBreak Avalonia.Media.TextFormatting.TextLine.TextLineBreak.get()' is abstract in the implementation but is missing in the contract. |
||||
|
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' is present in the contract but not in the implementation. |
||||
|
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract. |
||||
|
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract. |
||||
|
Total Issues: 13 |
||||
@ -1,40 +0,0 @@ |
|||||
using System; |
|
||||
|
|
||||
namespace Avalonia.Media.Fonts |
|
||||
{ |
|
||||
public readonly struct FontKey : IEquatable<FontKey> |
|
||||
{ |
|
||||
public FontKey(string familyName, FontStyle style, FontWeight weight) |
|
||||
{ |
|
||||
FamilyName = familyName; |
|
||||
Style = style; |
|
||||
Weight = weight; |
|
||||
} |
|
||||
|
|
||||
public string FamilyName { get; } |
|
||||
public FontStyle Style { get; } |
|
||||
public FontWeight Weight { get; } |
|
||||
|
|
||||
public override int GetHashCode() |
|
||||
{ |
|
||||
var hash = FamilyName.GetHashCode(); |
|
||||
|
|
||||
hash = hash * 31 + (int)Style; |
|
||||
hash = hash * 31 + (int)Weight; |
|
||||
|
|
||||
return hash; |
|
||||
} |
|
||||
|
|
||||
public override bool Equals(object other) |
|
||||
{ |
|
||||
return other is FontKey key && Equals(key); |
|
||||
} |
|
||||
|
|
||||
public bool Equals(FontKey other) |
|
||||
{ |
|
||||
return FamilyName == other.FamilyName && |
|
||||
Style == other.Style && |
|
||||
Weight == other.Weight; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="..\..\build\UnitTests.NetCore.targets" /> |
||||
|
<Import Project="..\..\build\Moq.props" /> |
||||
|
<Import Project="..\..\build\XUnit.props" /> |
||||
|
<Import Project="..\..\build\Rx.props" /> |
||||
|
<Import Project="..\..\build\Microsoft.Reactive.Testing.props" /> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj" /> |
||||
|
<ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI.Events\Avalonia.ReactiveUI.Events.csproj" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,44 @@ |
|||||
|
using System; |
||||
|
using System.Reactive.Linq; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.UnitTests; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.ReactiveUI.Events.UnitTests |
||||
|
{ |
||||
|
public class BasicControlEventsTest |
||||
|
{ |
||||
|
public class EventsControl : UserControl |
||||
|
{ |
||||
|
public bool IsAttached { get; private set; } |
||||
|
|
||||
|
public EventsControl() |
||||
|
{ |
||||
|
var attached = this |
||||
|
.Events() |
||||
|
.AttachedToVisualTree |
||||
|
.Select(args => true); |
||||
|
|
||||
|
this.Events() |
||||
|
.DetachedFromVisualTree |
||||
|
.Select(args => false) |
||||
|
.Merge(attached) |
||||
|
.Subscribe(marker => IsAttached = marker); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Generate_Events_Wrappers() |
||||
|
{ |
||||
|
var root = new TestRoot(); |
||||
|
var control = new EventsControl(); |
||||
|
Assert.False(control.IsAttached); |
||||
|
|
||||
|
root.Child = control; |
||||
|
Assert.True(control.IsAttached); |
||||
|
|
||||
|
root.Child = null; |
||||
|
Assert.False(control.IsAttached); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue