Browse Source

Merge branch 'master' into feature/window-showactive

pull/5063/head
Dan Walmsley 6 years ago
committed by GitHub
parent
commit
e34fe48bdf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      Documentation/build.md
  2. 2
      NuGet.Config
  3. 2
      build/ApiDiff.props
  4. 8
      build/MicroCom.targets
  5. 2
      build/Rx.props
  6. 2
      native/Avalonia.Native/src/OSX/platformthreading.mm
  7. 10
      native/Avalonia.Native/src/OSX/rendertarget.mm
  8. 18
      nukebuild/Build.cs
  9. 2
      nukebuild/_build.csproj
  10. 30
      samples/ControlCatalog/DecoratedWindow.xaml
  11. 66
      samples/ControlCatalog/MainWindow.xaml
  12. 29
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  13. 1
      samples/Sandbox/MainWindow.axaml.cs
  14. 34
      src/Avalonia.Base/Data/Core/TypeCastNode.cs
  15. 24
      src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs
  16. 5
      src/Avalonia.Base/Utilities/MathUtilities.cs
  17. 5
      src/Avalonia.Base/Utilities/StringTokenizer.cs
  18. 35
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  19. 4
      src/Avalonia.Build.Tasks/SpanCompat.cs
  20. 4
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  21. 32
      src/Avalonia.Controls/ComboBox.cs
  22. 10
      src/Avalonia.Controls/GridLength.cs
  23. 3
      src/Avalonia.Controls/NativeMenuBar.cs
  24. 18
      src/Avalonia.Controls/NativeMenuItem.cs
  25. 2
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  26. 2
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  27. 9
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  28. 11
      src/Avalonia.Controls/Slider.cs
  29. 2
      src/Avalonia.Input/NavigationDirection.cs
  30. 2
      src/Avalonia.MicroCom/MicroComProxyBase.cs
  31. 28
      src/Avalonia.MicroCom/MicroComRuntime.cs
  32. 4
      src/Avalonia.MicroCom/MicroComVtblBase.cs
  33. 2
      src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
  34. 8
      src/Avalonia.Native/Extensions.cs
  35. 2
      src/Avalonia.Native/IAvnMenuItem.cs
  36. 6
      src/Avalonia.Native/PlatformThreadingInterface.cs
  37. 4
      src/Avalonia.Native/PopupImpl.cs
  38. 4
      src/Avalonia.Native/PredicateCallback.cs
  39. 2
      src/Avalonia.Native/ScreenImpl.cs
  40. 2
      src/Avalonia.Native/SystemDialogs.cs
  41. 12
      src/Avalonia.Native/WindowImpl.cs
  42. 14
      src/Avalonia.Native/WindowImplBase.cs
  43. 1
      src/Avalonia.Native/avn.idl
  44. 8
      src/Avalonia.OpenGL/Egl/EglContext.cs
  45. 3
      src/Avalonia.Styling/ApiCompatBaseline.txt
  46. 13
      src/Avalonia.Styling/Controls/ResourceNodeExtensions.cs
  47. 48
      src/Avalonia.Styling/StyledElement.cs
  48. 15
      src/Avalonia.Themes.Default/PathIcon.xaml
  49. 2
      src/Avalonia.Themes.Default/ToggleSwitch.xaml
  50. 15
      src/Avalonia.Themes.Fluent/PathIcon.xaml
  51. 2
      src/Avalonia.Themes.Fluent/ToggleSwitch.xaml
  52. 42
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  53. 9
      src/Avalonia.Visuals/CornerRadius.cs
  54. 5
      src/Avalonia.Visuals/Matrix.cs
  55. 14
      src/Avalonia.Visuals/Media/Color.cs
  56. 75
      src/Avalonia.Visuals/Media/DashStyle.cs
  57. 56
      src/Avalonia.Visuals/Media/EllipseGeometry.cs
  58. 9
      src/Avalonia.Visuals/Media/KnownColors.cs
  59. 72
      src/Avalonia.Visuals/Media/PathFigure.cs
  60. 20
      src/Avalonia.Visuals/Media/PathGeometry.cs
  61. 9
      src/Avalonia.Visuals/Point.cs
  62. 79
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  63. 7
      src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
  64. 9
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  65. 9
      src/Avalonia.Visuals/Size.cs
  66. 9
      src/Avalonia.Visuals/Thickness.cs
  67. 9
      src/Avalonia.Visuals/Vector.cs
  68. 37
      src/Avalonia.Visuals/Visual.cs
  69. 10
      src/Avalonia.X11/X11Window.cs
  70. 2
      src/Avalonia.X11/XI2Manager.cs
  71. 1
      src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
  72. 39
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs
  73. 34
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlGridLengthAstNode.cs
  74. 54
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlVectorLikeConstantAstNode.cs
  75. 200
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  76. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
  77. 52
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  78. 32
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
  79. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  80. 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  81. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
  82. 51
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
  83. 18
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs
  84. 18
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
  85. 89
      src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs
  86. 19
      src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
  87. 12
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  88. 3
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  89. 5
      src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
  90. 1
      src/Windows/Avalonia.Win32/.gitignore
  91. 4
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  92. 18
      src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs
  93. 171
      src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs
  94. 96
      src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs
  95. 91
      src/Windows/Avalonia.Win32/Composition/D2DEffects.cs
  96. 45
      src/Windows/Avalonia.Win32/Composition/EffectBase.cs
  97. 18
      src/Windows/Avalonia.Win32/Composition/GRAPHICS_EFFECT_PROPERTY_MAPPING.cs
  98. 57
      src/Windows/Avalonia.Win32/Composition/GaussianBlurEffect.cs
  99. 8
      src/Windows/Avalonia.Win32/Composition/IBlurHost.cs
  100. 152
      src/Windows/Avalonia.Win32/Composition/ICompositionDrawingSurfaceInterop.cs

11
Documentation/build.md

@ -60,15 +60,10 @@ git submodule update --init --recursive
### Build native libraries (macOS only)
On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). The steps to get this working correctly are:
- (for revisions after 2 Nov 2020) Run `./build.sh GenerateCppHeaders` to generate `avalonia-native.h` from `avn.idl`
- Navigate to the Avalonia/native/Avalonia.Native/src/OSX folder and open the `Avalonia.Native.OSX.xcodeproj` project
- Build the library via the Product->Build menu. This will generate binaries in your local path under ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-*guid* where "guid" is uniquely generated every time you build.
- Manually install the native library by copying it from the build artifacts folder into the shared dynamic library path:
On macOS it is necessary to build and manually install the respective native libraries using [Xcode](https://developer.apple.com/xcode/). Execute the build script in the root project with the `CompileNative` task. It will build the headers, build the libraries, and place them in the appropriate place to allow .NET to find them at compilation and run time.
```
cd ~/Library/Developer/Xcode/DerivedData/Avalonia.Native.OSX-[guid]/Build/Products/Debug
cp libAvalonia.Native.OSX.dylib /usr/local/lib/libAvaloniaNative.dylib
```bash
./build.sh CompileNative
```
### Build and Run Avalonia

2
NuGet.Config

@ -4,6 +4,6 @@
<packageSources>
<clear />
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
<add key="dotnet-eng" value="https://nuget.avaloniaui.net/repository/avalonia-devdeps/index.json" protocolVersion="3" />
</packageSources>
</configuration>

2
build/ApiDiff.props

@ -1,6 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ApiContractPackageVersion>0.10.0-preview3</ApiContractPackageVersion>
<ApiContractPackageVersion>0.10.0-preview6</ApiContractPackageVersion>
<NugetPackageName Condition="'$(PackageId)' != ''">$(PackageId)</NugetPackageName>
<NugetPackageName Condition="'$(PackageId)' == ''">Avalonia</NugetPackageName>
</PropertyGroup>

8
build/MicroCom.targets

@ -2,7 +2,7 @@
<!-- Ensure that code generator is actually built -->
<ItemGroup>
<ProjectReference Include="..\tools\MicroComGenerator\MicroComGenerator.csproj">
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\src\tools\MicroComGenerator\MicroComGenerator.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<ExcludeAssets>all</ExcludeAssets>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
@ -12,10 +12,10 @@
<Target Name="GenerateAvaloniaNativeComInterop"
BeforeTargets="CoreCompile"
DependsOnTargets="ResolveReferences"
Inputs="@(AvnComIdl);$(MSBuildThisFileDirectory)/../tools/MicroComGenerator/**/*.cs"
Inputs="@(AvnComIdl);$(MSBuildThisFileDirectory)../src/tools/MicroComGenerator/**/*.cs"
Outputs="%(AvnComIdl.OutputFile)">
<Message Importance="high" Text="Generating file %(AvnComIdl.OutputFile) from @(AvnComIdl)" />
<Exec Command="dotnet ../tools/MicroComGenerator/bin/$(Configuration)/netcoreapp3.1/MicroComGenerator.dll -i @(AvnComIdl) --cs %(AvnComIdl.OutputFile)" LogStandardErrorAsError="true" />
<Exec Command="dotnet $(MSBuildThisFileDirectory)../src/tools/MicroComGenerator/bin/$(Configuration)/netcoreapp3.1/MicroComGenerator.dll -i @(AvnComIdl) --cs %(AvnComIdl.OutputFile)" LogStandardErrorAsError="true" />
<ItemGroup>
<!-- Remove and re-add generated file, this is needed for the clean build -->
<Compile Remove="%(AvnComIdl.OutputFile)"/>
@ -24,7 +24,7 @@
</Target>
<ItemGroup>
<UpToDateCheckInput Include="@(AvnComIdl)"/>
<UpToDateCheckInput Include="$(MSBuildThisFileDirectory)/../tools/MicroComGenerator/**/*.cs"/>
<UpToDateCheckInput Include="$(MSBuildThisFileDirectory)/../src/tools/MicroComGenerator/**/*.cs"/>
</ItemGroup>
<PropertyGroup>
<_AvaloniaPatchComInterop>true</_AvaloniaPatchComInterop>

2
build/Rx.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="System.Reactive" Version="4.4.1" />
<PackageReference Include="System.Reactive" Version="5.0" />
</ItemGroup>
</Project>

2
native/Avalonia.Native/src/OSX/platformthreading.mm

@ -101,7 +101,7 @@ public:
virtual bool GetCurrentThreadIsLoopThread() override
{
return [[NSThread currentThread] isMainThread];
return [NSThread isMainThread];
}
virtual void SetSignaledCallback(IAvnSignaledCallback* cb) override
{

10
native/Avalonia.Native/src/OSX/rendertarget.mm

@ -2,6 +2,7 @@
#include "rendertarget.h"
#import <IOSurface/IOSurface.h>
#import <IOSurface/IOSurfaceObjC.h>
#import <QuartzCore/QuartzCore.h>
#include <OpenGL/CGLIOSurface.h>
#include <OpenGL/OpenGL.h>
@ -143,13 +144,17 @@ static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* ta
return _layer;
}
- (void)resize:(AvnPixelSize)size withScale: (float) scale;{
- (void)resize:(AvnPixelSize)size withScale: (float) scale{
@synchronized (lock) {
if(surface == nil
|| surface->size.Width != size.Width
|| surface->size.Height != size.Height
|| surface->scale != scale)
{
surface = [[IOSurfaceHolder alloc] initWithSize:size withScale:scale withOpenGlContext:_glContext.getRaw()];
[self updateLayer];
}
}
}
@ -159,12 +164,15 @@ static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* ta
@synchronized (lock) {
if(_layer == nil)
return;
[CATransaction begin];
[_layer setContents: nil];
if(surface != nil)
{
[_layer setContentsScale: surface->scale];
[_layer setContents: (__bridge IOSurface*) surface->surface];
}
[CATransaction commit];
[CATransaction flush];
}
}
else

18
nukebuild/Build.cs

@ -107,7 +107,7 @@ partial class Build : NukeBuild
.AddProperty("JavaSdkDirectory", GetVariable<string>("JAVA_HOME_8_X64")))
.AddProperty("PackageVersion", Parameters.Version)
.AddProperty("iOSRoslynPathHackRequired", true)
.SetToolPath(MsBuildExe.Value)
.SetProcessToolPath(MsBuildExe.Value)
.SetConfiguration(Parameters.Configuration)
.SetVerbosity(MSBuildVerbosity.Minimal)
.Apply(configurator));
@ -132,10 +132,10 @@ partial class Build : NukeBuild
var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c
.SetWorkingDirectory(webappDir)
.SetArgumentConfigurator(a => a.Add("--silent")));
.SetProcessWorkingDirectory(webappDir)
.SetProcessArgumentConfigurator(a => a.Add("--silent")));
NpmTasks.NpmRun(c => c
.SetWorkingDirectory(webappDir)
.SetProcessWorkingDirectory(webappDir)
.SetCommand("dist"));
});
@ -157,7 +157,7 @@ partial class Build : NukeBuild
{
if (Parameters.IsRunningOnWindows)
MsBuildCommon(Parameters.MSBuildSolution, c => c
.SetArgumentConfigurator(a => a.Add("/r"))
.SetProcessArgumentConfigurator(a => a.Add("/r"))
.AddTargets("Build")
);
@ -194,7 +194,7 @@ partial class Build : NukeBuild
var eventsProject = Path.Combine(eventsDirectory, "Avalonia.ReactiveUI.Events.csproj");
if (Parameters.IsRunningOnWindows)
MsBuildCommon(eventsProject, c => c
.SetArgumentConfigurator(a => a.Add("/r"))
.SetProcessArgumentConfigurator(a => a.Add("/r"))
.AddTargets("Build")
);
else
@ -242,10 +242,10 @@ partial class Build : NukeBuild
var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c
.SetWorkingDirectory(webappTestDir)
.SetArgumentConfigurator(a => a.Add("--silent")));
.SetProcessWorkingDirectory(webappTestDir)
.SetProcessArgumentConfigurator(a => a.Add("--silent")));
NpmTasks.NpmRun(c => c
.SetWorkingDirectory(webappTestDir)
.SetProcessWorkingDirectory(webappTestDir)
.SetCommand("test"));
});

2
nukebuild/_build.csproj

@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nuke.Common" Version="0.24.0" />
<PackageReference Include="Nuke.Common" Version="5.0.0" />
<PackageReference Include="xunit.runner.console" Version="2.3.1" />
<PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />

30
samples/ControlCatalog/DecoratedWindow.xaml

@ -6,25 +6,21 @@
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="Decorated">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Open"/>
<NativeMenuItem Header="Recent">
<NativeMenuItem.Menu>
<NativeMenu/>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItem Header="Quit Avalonia" Gesture="CMD+Q"/>
</NativeMenu>
</NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Open"/>
<NativeMenuItem Header="Recent">
<NativeMenuItem.Menu>
<NativeMenu/>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItem Header="Quit Avalonia" Gesture="CMD+Q"/>
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Edit">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Copy"/>
<NativeMenuItem Header="Paste"/>
</NativeMenu>
</NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Copy"/>
<NativeMenuItem Header="Paste"/>
</NativeMenu>
</NativeMenuItem>
</NativeMenu>
</NativeMenu.Menu>

66
samples/ControlCatalog/MainWindow.xaml

@ -16,47 +16,39 @@
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="File">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Clicked="OnOpenClicked" Gesture="Ctrl+O"/>
<NativeMenuItemSeperator/>
<NativeMenuItem Icon="/Assets/github_icon.png" Header="Recent">
<NativeMenuItem.Menu>
<NativeMenu/>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItemSeperator/>
<NativeMenuItem Header="{x:Static local:MainWindow.MenuQuitHeader}"
Gesture="{x:Static local:MainWindow.MenuQuitGesture}"
Clicked="OnCloseClicked" />
</NativeMenu>
</NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Icon="/Assets/test_icon.ico" Header="Open" Clicked="OnOpenClicked" Gesture="Ctrl+O"/>
<NativeMenuItemSeperator/>
<NativeMenuItem Icon="/Assets/github_icon.png" Header="Recent">
<NativeMenu/>
</NativeMenuItem>
<NativeMenuItemSeperator/>
<NativeMenuItem Header="{x:Static local:MainWindow.MenuQuitHeader}"
Gesture="{x:Static local:MainWindow.MenuQuitGesture}"
Clicked="OnCloseClicked" />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Edit">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Copy"/>
<NativeMenuItem Header="Paste"/>
</NativeMenu>
</NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Copy"/>
<NativeMenuItem Header="Paste"/>
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Options">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Check Me (None)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="None"
IsChecked="{Binding IsMenuItemChecked}" />
<NativeMenuItem Header="Check Me (CheckBox)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="CheckBox"
IsChecked="{Binding IsMenuItemChecked}" />
<NativeMenuItem Header="Check Me (Radio)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="Radio"
IsChecked="{Binding IsMenuItemChecked}" />
</NativeMenu>
</NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Check Me (None)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="None"
IsChecked="{Binding IsMenuItemChecked}" />
<NativeMenuItem Header="Check Me (CheckBox)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="CheckBox"
IsChecked="{Binding IsMenuItemChecked}" />
<NativeMenuItem Header="Check Me (Radio)"
Command="{Binding ToggleMenuItemCheckedCommand}"
ToggleType="Radio"
IsChecked="{Binding IsMenuItemChecked}" />
</NativeMenu>
</NativeMenuItem>
</NativeMenu>
</NativeMenu.Menu>

29
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -4,6 +4,7 @@ using System.Linq;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Dialogs;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
#pragma warning disable 4014
@ -112,11 +113,29 @@ namespace ControlCatalog.Pages
private Window CreateSampleWindow()
{
var window = new Window();
window.Height = 200;
window.Width = 200;
window.Content = new TextBlock { Text = "Hello world!" };
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
Button button;
var window = new Window
{
Height = 200,
Width = 200,
Content = new StackPanel
{
Spacing = 4,
Children =
{
new TextBlock { Text = "Hello world!" },
(button = new Button
{
HorizontalAlignment = HorizontalAlignment.Center,
Content = "Click to close"
})
}
},
WindowStartupLocation = WindowStartupLocation.CenterOwner
};
button.Click += (_, __) => window.Close();
return window;
}

1
samples/Sandbox/MainWindow.axaml.cs

@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Win32.WinRT.Composition;
namespace Sandbox
{

34
src/Avalonia.Base/Data/Core/TypeCastNode.cs

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Data.Core
{
public class TypeCastNode : ExpressionNode
{
public override string Description => $"as {TargetType.FullName}";
public Type TargetType { get; }
public TypeCastNode(Type type)
{
TargetType = type;
}
protected virtual object Cast(object value)
{
return TargetType.IsInstanceOfType(value) ? value : null;
}
protected override void StartListeningCore(WeakReference<object> reference)
{
if (reference.TryGetTarget(out object target))
{
target = Cast(target);
reference = target == null ? NullReference : new WeakReference<object>(target);
}
base.StartListeningCore(reference);
}
}
}

24
src/Avalonia.Base/Utilities/AvaloniaPropertyValueStore.cs

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
#nullable enable
namespace Avalonia.Utilities
{
@ -9,12 +12,14 @@ namespace Avalonia.Utilities
/// <typeparam name="TValue">Stored value type.</typeparam>
internal sealed class AvaloniaPropertyValueStore<TValue>
{
// The last item in the list is always int.MaxValue.
private static readonly Entry[] s_emptyEntries = { new Entry { PropertyId = int.MaxValue, Value = default! } };
private Entry[] _entries;
public AvaloniaPropertyValueStore()
{
// The last item in the list is always int.MaxValue
_entries = new[] { new Entry { PropertyId = int.MaxValue, Value = default } };
_entries = s_emptyEntries;
}
private (int, bool) TryFindEntry(int propertyId)
@ -86,7 +91,7 @@ namespace Avalonia.Utilities
return (0, false);
}
public bool TryGetValue(AvaloniaProperty property, out TValue value)
public bool TryGetValue(AvaloniaProperty property, [MaybeNull] out TValue value)
{
(int index, bool found) = TryFindEntry(property.Id);
if (!found)
@ -132,7 +137,18 @@ namespace Avalonia.Utilities
if (found)
{
Entry[] entries = new Entry[_entries.Length - 1];
var newLength = _entries.Length - 1;
// Special case - one element left means that value store is empty so we can just reuse our "empty" array.
if (newLength == 1)
{
_entries = s_emptyEntries;
return;
}
var entries = new Entry[newLength];
int ix = 0;
for (int i = 0; i < _entries.Length; ++i)

5
src/Avalonia.Base/Utilities/MathUtilities.cs

@ -5,7 +5,10 @@ namespace Avalonia.Utilities
/// <summary>
/// Provides math utilities not provided in System.Math.
/// </summary>
public static class MathUtilities
#if !BUILDTASK
public
#endif
static class MathUtilities
{
// smallest such that 1.0+DoubleEpsilon != 1.0
internal static readonly double DoubleEpsilon = 2.2204460492503131e-016;

5
src/Avalonia.Base/Utilities/StringTokenizer.cs

@ -4,7 +4,10 @@ using static System.Char;
namespace Avalonia.Utilities
{
public struct StringTokenizer : IDisposable
#if !BUILDTASK
public
#endif
struct StringTokenizer : IDisposable
{
private const char DefaultSeparatorChar = ',';

35
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="$(Configuration) == 'Debug'">netstandard2.0;netcoreapp2.0</TargetFrameworks>
<TargetFrameworks Condition="$(Configuration) == 'Debug'">netstandard2.0;netcoreapp3.1</TargetFrameworks>
<OutputType>exe</OutputType>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
@ -45,6 +45,12 @@
<Compile Include="../Avalonia.Base/Utilities/IdentifierParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Base/Utilities/StringTokenizer.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Base/Utilities/MathUtilities.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\Markup\Avalonia.Markup\Markup\Parsers\ArgumentListParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
@ -57,6 +63,33 @@
<Compile Include="../Avalonia.Base/Utilities/StyleClassParser.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Thickness.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Size.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Vector.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Point.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Matrix.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/CornerRadius.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Media/Color.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Visuals/Media/KnownColors.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="../Avalonia.Controls/GridLength.cs">
<Link>Markup/%(RecursiveDir)%(FileName)%(Extension)</Link>
</Compile>
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />

4
src/Avalonia.Build.Tasks/SpanCompat.cs

@ -1,3 +1,4 @@
#if !NETCOREAPP3_1
namespace System
{
// This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory
@ -63,6 +64,8 @@ namespace System
}
public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length);
public static implicit operator ReadOnlySpan<T>(char[] arr) => new ReadOnlySpan<T>(new string(arr));
}
static class SpanCompatExtensions
@ -71,3 +74,4 @@ namespace System
}
}
#endif

4
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -46,7 +46,9 @@ namespace Avalonia.Build.Tasks
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom,
bool skipXamlCompilation)
{
var typeSystem = new CecilTypeSystem(references.Concat(new[] { input }), input);
var typeSystem = new CecilTypeSystem(references
.Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll"))
.Concat(new[] { input }), input);
var asm = typeSystem.TargetAssemblyDefinition;

32
src/Avalonia.Controls/ComboBox.cs

@ -173,11 +173,10 @@ namespace Avalonia.Controls
ComboBoxItem.ContentTemplateProperty);
}
/// <inheritdoc/>
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
this.UpdateSelectionBoxItem(this.SelectedItem);
base.OnAttachedToVisualTree(e);
this.UpdateSelectionBoxItem(SelectedItem);
}
/// <inheritdoc/>
@ -373,19 +372,22 @@ namespace Avalonia.Controls
if (control != null)
{
control.Measure(Size.Infinity);
SelectionBoxItem = new Rectangle
if (VisualRoot is object)
{
Width = control.DesiredSize.Width,
Height = control.DesiredSize.Height,
Fill = new VisualBrush
control.Measure(Size.Infinity);
SelectionBoxItem = new Rectangle
{
Visual = control,
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
}
};
Width = control.DesiredSize.Width,
Height = control.DesiredSize.Height,
Fill = new VisualBrush
{
Visual = control,
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
}
};
}
}
else
{

10
src/Avalonia.Controls/GridLength.cs

@ -8,7 +8,10 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the valid units for a <see cref="GridLength"/>.
/// </summary>
public enum GridUnitType
#if !BUILDTASK
public
#endif
enum GridUnitType
{
/// <summary>
/// The row or column is auto-sized to fit its content.
@ -29,7 +32,10 @@ namespace Avalonia.Controls
/// <summary>
/// Holds the width or height of a <see cref="Grid"/>'s column and row definitions.
/// </summary>
public struct GridLength : IEquatable<GridLength>
#if !BUILDTASK
public
#endif
struct GridLength : IEquatable<GridLength>
{
private readonly GridUnitType _type;

3
src/Avalonia.Controls/NativeMenuBar.cs

@ -1,7 +1,6 @@
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Styling;
namespace Avalonia.Controls
{
@ -16,7 +15,7 @@ namespace Avalonia.Controls
EnableMenuItemClickForwardingProperty.Changed.Subscribe(args =>
{
var item = (MenuItem)args.Sender;
if (args.NewValue.Equals(true))
if (args.NewValue.GetValueOrDefault<bool>())
item.Click += OnMenuItemClick;
else
item.Click -= OnMenuItemClick;

18
src/Avalonia.Controls/NativeMenuItem.cs

@ -2,6 +2,7 @@ using System;
using System.Windows.Input;
using Avalonia.Input;
using Avalonia.Media.Imaging;
using Avalonia.Metadata;
using Avalonia.Utilities;
namespace Avalonia.Controls
@ -62,6 +63,7 @@ namespace Avalonia.Controls
public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty =
AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o.Menu, (o, v) => o.Menu = v);
[Content]
public NativeMenu Menu
{
get => _menu;
@ -151,7 +153,7 @@ namespace Avalonia.Controls
IsEnabled = _command?.CanExecute(null) ?? true;
}
public bool HasClickHandlers => Clicked != null;
public bool HasClickHandlers => Click != null;
public ICommand Command
{
@ -182,11 +184,21 @@ namespace Avalonia.Controls
set { SetValue(CommandParameterProperty, value); }
}
public event EventHandler Clicked;
/// <summary>
/// Occurs when a <see cref="NativeMenuItem"/> is clicked.
/// </summary>
public event EventHandler Click;
[Obsolete("Use Click event.")]
public event EventHandler Clicked
{
add => Click += value;
remove => Click -= value;
}
void INativeMenuItemExporterEventsImplBridge.RaiseClicked()
{
Clicked?.Invoke(this, new EventArgs());
Click?.Invoke(this, new EventArgs());
if (Command?.CanExecute(CommandParameter) == true)
{

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

@ -231,7 +231,7 @@ namespace Avalonia.Controls.Platform
{
var direction = e.Key.ToNavigationDirection();
if (direction.HasValue)
if (direction?.IsDirectional() == true)
{
if (item == null && _isContextMenu)
{

2
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -35,7 +35,7 @@ namespace Avalonia.Controls.Primitives
/// Defines the <see cref="Visibility"/> property.
/// </summary>
public static readonly StyledProperty<ScrollBarVisibility> VisibilityProperty =
AvaloniaProperty.Register<ScrollBar, ScrollBarVisibility>(nameof(Visibility));
AvaloniaProperty.Register<ScrollBar, ScrollBarVisibility>(nameof(Visibility), ScrollBarVisibility.Visible);
/// <summary>
/// Defines the <see cref="Orientation"/> property.

9
src/Avalonia.Controls/Primitives/TemplatedControl.cs

@ -354,11 +354,14 @@ namespace Avalonia.Controls.Primitives
{
control.SetValue(TemplatedParentProperty, this);
foreach (var child in control.LogicalChildren)
var children = control.LogicalChildren;
var count = children.Count;
for (var i = 0; i < count; i++)
{
if (child is IControl c)
if (children[i] is IControl child)
{
ApplyTemplatedParent(c);
ApplyTemplatedParent(child);
}
}
}

11
src/Avalonia.Controls/Slider.cs

@ -3,6 +3,7 @@ using Avalonia.Collections;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
@ -94,6 +95,8 @@ namespace Avalonia.Controls
Thumb.DragStartedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler<Slider>((x, e) => x.OnThumbDragCompleted(e),
RoutingStrategies.Bubble);
ValueProperty.OverrideMetadata<Slider>(new DirectPropertyMetadata<double>(enableDataValidation: true));
}
/// <summary>
@ -225,6 +228,14 @@ namespace Avalonia.Controls
Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
}
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
{
if (property == ValueProperty)
{
DataValidationErrors.SetError(this, value.Error);
}
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);

2
src/Avalonia.Input/NavigationDirection.cs

@ -83,7 +83,7 @@ namespace Avalonia.Input
/// </returns>
public static bool IsDirectional(this NavigationDirection direction)
{
return direction > NavigationDirection.Previous ||
return direction > NavigationDirection.Previous &&
direction <= NavigationDirection.PageDown;
}

2
src/Avalonia.MicroCom/MicroComProxyBase.cs

@ -56,7 +56,7 @@ namespace Avalonia.MicroCom
{
var guid = MicroComRuntime.GetGuidFor(typeof(T));
var rv = QueryInterface(guid, out var ppv);
if (rv != 0)
if (rv == 0)
return (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true);
throw new COMException("QueryInterface failed", rv);
}

28
src/Avalonia.MicroCom/MicroComRuntime.cs

@ -38,13 +38,20 @@ namespace Avalonia.MicroCom
public static T CreateProxyFor<T>(IntPtr pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), pObject, ownsHandle);
public static object CreateProxyFor(Type type, IntPtr pObject, bool ownsHandle) => _factories[type](pObject, ownsHandle);
public static IntPtr GetNativeIntPtr<T>(this T obj, bool owned = false) where T : IUnknown
=> new IntPtr(GetNativePointer(obj, owned));
public static void* GetNativePointer<T>(T obj, bool owned = false) where T : IUnknown
{
if (obj == null)
return null;
if (obj is MicroComProxyBase proxy)
{
if(owned)
proxy.AddRef();
return (void*)proxy.NativePointer;
}
if (obj is IMicroComShadowContainer container)
{
container.Shadow ??= new MicroComShadow(container);
@ -89,10 +96,27 @@ namespace Avalonia.MicroCom
}
public static T CloneReference<T>(T iface) where T : IUnknown
public static T CloneReference<T>(this T iface) where T : IUnknown
{
var proxy = (MicroComProxyBase)(object)iface;
var ownedPointer = GetNativePointer(iface, true);
return CreateProxyFor<T>(ownedPointer, true);
}
public static T QueryInterface<T>(this IUnknown unknown) where T : IUnknown
{
var proxy = (MicroComProxyBase)unknown;
return proxy.QueryInterface<T>();
}
public static void UnsafeAddRef(this IUnknown unknown)
{
((MicroComProxyBase)unknown).AddRef();
}
public static void UnsafeRelease(this IUnknown unknown)
{
((MicroComProxyBase)unknown).Release();
}
}
}

4
src/Avalonia.MicroCom/MicroComVtblBase.cs

@ -7,10 +7,10 @@ namespace Avalonia.MicroCom
public unsafe class MicroComVtblBase
{
private List<IntPtr> _methods = new List<IntPtr>();
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
private delegate int AddRefDelegate(Ccw* ccw);
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
private delegate int QueryInterfaceDelegate(Ccw* ccw, Guid* guid, void** ppv);
public static IntPtr Vtable { get; } = new MicroComVtblBase().CreateVTable();

2
src/Avalonia.Native/AvaloniaNativeMenuExporter.cs

@ -60,7 +60,7 @@ namespace Avalonia.Native
Header = "About Avalonia",
};
aboutItem.Clicked += async (sender, e) =>
aboutItem.Click += async (sender, e) =>
{
var dialog = new AboutAvaloniaDialog();

8
src/Avalonia.Native/Extensions.cs

@ -0,0 +1,8 @@
namespace Avalonia.Native
{
internal static class Extensions
{
public static int AsComBool(this bool b) => b ? 1 : 0;
public static bool FromComBool(this int b) => b != 0;
}
}

2
src/Avalonia.Native/IAvnMenuItem.cs

@ -24,7 +24,7 @@ namespace Avalonia.Native.Interop.Impl
private void UpdateTitle(string title) => SetTitle(title ?? "");
private void UpdateIsChecked(bool isChecked) => SetIsChecked(isChecked);
private void UpdateIsChecked(bool isChecked) => SetIsChecked(isChecked.AsComBool());
private void UpdateToggleType(NativeMenuItemToggleType toggleType)
{

6
src/Avalonia.Native/PlatformThreadingInterface.cs

@ -33,9 +33,9 @@ namespace Avalonia.Native
_parent = parent;
}
public void Signaled(int priority, bool priorityContainsMeaningfulValue)
public void Signaled(int priority, int priorityContainsMeaningfulValue)
{
_parent.Signaled?.Invoke(priorityContainsMeaningfulValue ? (DispatcherPriority?)priority : null);
_parent.Signaled?.Invoke(priorityContainsMeaningfulValue.FromComBool() ? (DispatcherPriority?)priority : null);
}
}
@ -50,7 +50,7 @@ namespace Avalonia.Native
_native.SetSignaledCallback(cb);
}
public bool CurrentThreadIsLoopThread => _native.CurrentThreadIsLoopThread;
public bool CurrentThreadIsLoopThread => _native.CurrentThreadIsLoopThread.FromComBool();
public event Action<DispatcherPriority?> Signaled;

4
src/Avalonia.Native/PopupImpl.cs

@ -50,9 +50,9 @@ namespace Avalonia.Native
// NOP on Popup
}
bool IAvnWindowEvents.Closing()
int IAvnWindowEvents.Closing()
{
return true;
return true.AsComBool();
}
void IAvnWindowEvents.WindowStateChanged(AvnWindowState state)

4
src/Avalonia.Native/PredicateCallback.cs

@ -12,9 +12,9 @@ namespace Avalonia.Native
_predicate = predicate;
}
bool IAvnPredicateCallback.Evaluate()
int IAvnPredicateCallback.Evaluate()
{
return _predicate();
return _predicate().AsComBool();
}
}
}

2
src/Avalonia.Native/ScreenImpl.cs

@ -33,7 +33,7 @@ namespace Avalonia.Native
screen.PixelDensity,
screen.Bounds.ToAvaloniaPixelRect(),
screen.WorkingArea.ToAvaloniaPixelRect(),
screen.Primary);
screen.Primary.FromComBool());
}
return result;

2
src/Avalonia.Native/SystemDialogs.cs

@ -26,7 +26,7 @@ namespace Avalonia.Native
if (dialog is OpenFileDialog ofd)
{
_native.OpenFileDialog(nativeParent,
events, ofd.AllowMultiple,
events, ofd.AllowMultiple.AsComBool(),
ofd.Title ?? "",
ofd.Directory ?? "",
ofd.InitialFileName ?? "",

12
src/Avalonia.Native/WindowImpl.cs

@ -42,14 +42,14 @@ namespace Avalonia.Native
_parent = parent;
}
bool IAvnWindowEvents.Closing()
int IAvnWindowEvents.Closing()
{
if (_parent.Closing != null)
{
return _parent.Closing();
return _parent.Closing().AsComBool();
}
return true;
return true.AsComBool();
}
void IAvnWindowEvents.WindowStateChanged(AvnWindowState state)
@ -69,7 +69,7 @@ namespace Avalonia.Native
public void CanResize(bool value)
{
_native.SetCanResize(value);
_native.SetCanResize(value.AsComBool());
}
public void SetSystemDecorations(Controls.SystemDecorations enabled)
@ -145,7 +145,7 @@ namespace Avalonia.Native
{
_isExtended = extendIntoClientAreaHint;
_native.SetExtendClientArea(extendIntoClientAreaHint);
_native.SetExtendClientArea(extendIntoClientAreaHint.AsComBool());
InvalidateExtendedMargins();
}
@ -198,7 +198,7 @@ namespace Avalonia.Native
public void SetEnabled(bool enable)
{
_native.SetEnabled(enable);
_native.SetEnabled(enable.AsComBool());
}
}
}

14
src/Avalonia.Native/WindowImplBase.cs

@ -174,7 +174,7 @@ namespace Avalonia.Native
void IAvnWindowBaseEvents.Resized(AvnSize* size)
{
if (_parent._native != null)
if (_parent?._native != null)
{
var s = new Size(size->Width, size->Height);
_parent._savedLogicalSize = s;
@ -192,14 +192,14 @@ namespace Avalonia.Native
_parent.RawMouseEvent(type, timeStamp, modifiers, point, delta);
}
bool IAvnWindowBaseEvents.RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
int IAvnWindowBaseEvents.RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
{
return _parent.RawKeyEvent(type, timeStamp, modifiers, key);
return _parent.RawKeyEvent(type, timeStamp, modifiers, key).AsComBool();
}
bool IAvnWindowBaseEvents.RawTextInputEvent(uint timeStamp, string text)
int IAvnWindowBaseEvents.RawTextInputEvent(uint timeStamp, string text)
{
return _parent.RawTextInputEvent(timeStamp, text);
return _parent.RawTextInputEvent(timeStamp, text).AsComBool();
}
@ -388,7 +388,7 @@ namespace Avalonia.Native
public void SetTopmost(bool value)
{
_native.SetTopMost(value);
_native.SetTopMost(value.AsComBool());
}
public double RenderScaling => _native?.Scaling ?? 1;
@ -456,7 +456,7 @@ namespace Avalonia.Native
TransparencyLevel = transparencyLevel;
_native?.SetBlurEnabled(TransparencyLevel >= WindowTransparencyLevel.Blur);
_native?.SetBlurEnabled((TransparencyLevel >= WindowTransparencyLevel.Blur).AsComBool());
TransparencyLevelChanged?.Invoke(TransparencyLevel);
}
}

1
src/Avalonia.Native/avn.idl

@ -1,5 +1,6 @@
@clr-namespace Avalonia.Native.Interop
@clr-access internal
@clr-map bool int
@cpp-preamble @@
#include "com.h"
#include "key.h"

8
src/Avalonia.OpenGL/Egl/EglContext.cs

@ -93,6 +93,14 @@ namespace Avalonia.OpenGL.Egl
return MakeCurrent();
}
public IDisposable EnsureLocked()
{
if (IsCurrent)
return Disposable.Empty;
Monitor.Enter(_lock);
return Disposable.Create(() => Monitor.Exit(_lock));
}
public bool IsSharedWith(IGlContext context)
{
var c = (EglContext)context;

3
src/Avalonia.Styling/ApiCompatBaseline.txt

@ -0,0 +1,3 @@
Compat issues with assembly Avalonia.Styling:
MembersMustExist : Member 'public System.IObservable<System.Object> Avalonia.Controls.ResourceNodeExtensions.GetResourceObservable(Avalonia.IStyledElement, System.Object, System.Func<System.Object, System.Object>)' does not exist in the implementation but it does exist in the contract.
Total Issues: 1

13
src/Avalonia.Styling/Controls/ResourceNodeExtensions.cs

@ -60,7 +60,7 @@ namespace Avalonia.Controls
}
public static IObservable<object?> GetResourceObservable(
this IStyledElement control,
this IResourceHost control,
object key,
Func<object?, object?>? converter = null)
{
@ -83,11 +83,11 @@ namespace Avalonia.Controls
private class ResourceObservable : LightweightObservableBase<object?>
{
private readonly IStyledElement _target;
private readonly IResourceHost _target;
private readonly object _key;
private readonly Func<object?, object?>? _converter;
public ResourceObservable(IStyledElement target, object key, Func<object?, object?>? converter)
public ResourceObservable(IResourceHost target, object key, Func<object?, object?>? converter)
{
_target = target;
_key = key;
@ -147,13 +147,16 @@ namespace Avalonia.Controls
{
if (_target.Owner is object)
{
observer.OnNext(Convert(_target.Owner?.FindResource(_key)));
observer.OnNext(Convert(_target.Owner.FindResource(_key)));
}
}
private void PublishNext()
{
PublishNext(Convert(_target.Owner?.FindResource(_key)));
if (_target.Owner is object)
{
PublishNext(Convert(_target.Owner.FindResource(_key)));
}
}
private void OwnerChanged(object sender, EventArgs e)

48
src/Avalonia.Styling/StyledElement.cs

@ -1,8 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Avalonia.Animation;
using Avalonia.Collections;
using Avalonia.Controls;
@ -479,16 +479,16 @@ namespace Avalonia
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
SetLogicalParent(e.NewItems.Cast<ILogical>());
SetLogicalParent(e.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
ClearLogicalParent(e.OldItems.Cast<ILogical>());
ClearLogicalParent(e.OldItems);
break;
case NotifyCollectionChangedAction.Replace:
ClearLogicalParent(e.OldItems.Cast<ILogical>());
SetLogicalParent(e.NewItems.Cast<ILogical>());
ClearLogicalParent(e.OldItems);
SetLogicalParent(e.NewItems);
break;
case NotifyCollectionChangedAction.Reset:
@ -702,13 +702,32 @@ namespace Avalonia
OnDataContextChanged(EventArgs.Empty);
}
private void SetLogicalParent(IEnumerable<ILogical> children)
private void SetLogicalParent(IList children)
{
foreach (var i in children)
var count = children.Count;
for (var i = 0; i < count; i++)
{
var logical = (ILogical) children[i];
if (logical.LogicalParent is null)
{
((ISetLogicalParent)logical).SetParent(this);
}
}
}
private void ClearLogicalParent(IList children)
{
var count = children.Count;
for (var i = 0; i < count; i++)
{
if (i.LogicalParent == null)
var logical = (ILogical) children[i];
if (logical.LogicalParent == this)
{
((ISetLogicalParent)i).SetParent(this);
((ISetLogicalParent)logical).SetParent(null);
}
}
}
@ -784,17 +803,6 @@ namespace Avalonia
}
}
private void ClearLogicalParent(IEnumerable<ILogical> children)
{
foreach (var i in children)
{
if (i.LogicalParent == this)
{
((ISetLogicalParent)i).SetParent(null);
}
}
}
private void NotifyResourcesChanged(
ResourcesChangedEventArgs? e = null,
bool propagate = true)

15
src/Avalonia.Themes.Default/PathIcon.xaml

@ -2,16 +2,19 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="PathIcon">
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{DynamicResource IconElementThemeHeight}" />
<Setter Property="Width" Value="{DynamicResource IconElementThemeWidth}" />
<Setter Property="Template">
<ControlTemplate>
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}"
Stretch="Uniform" />
</Viewbox>
<Border Background="{TemplateBinding Background}">
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}"
Stretch="Uniform" />
</Viewbox>
</Border>
</ControlTemplate>
</Setter>
</Style>

2
src/Avalonia.Themes.Default/ToggleSwitch.xaml

@ -5,7 +5,7 @@
<Thickness x:Key="ToggleSwitchTopHeaderMargin">0,0,0,6</Thickness>
<GridLength x:Key="ToggleSwitchPreContentMargin">6</GridLength>
<GridLength x:Key="ToggleSwitchPostContentMargin">6</GridLength>
<x:Double x:Key="ToggleSwitchThemeMinWidth">154</x:Double>
<x:Double x:Key="ToggleSwitchThemeMinWidth">0</x:Double>
<Thickness x:Key="ToggleSwitchOnStrokeThickness">0</Thickness>
<Thickness x:Key="ToggleSwitchOuterBorderStrokeThickness">1</Thickness>
<SolidColorBrush x:Key="ToggleSwitchContentForeground" Color="{DynamicResource ThemeForegroundColor}" />

15
src/Avalonia.Themes.Fluent/PathIcon.xaml

@ -10,16 +10,19 @@
</Design.PreviewWith>
<Style Selector="PathIcon">
<Setter Property="Foreground" Value="{DynamicResource TextControlForeground}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{DynamicResource IconElementThemeHeight}" />
<Setter Property="Width" Value="{DynamicResource IconElementThemeWidth}" />
<Setter Property="Template">
<ControlTemplate>
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}"
Stretch="Uniform" />
</Viewbox>
<Border Background="{TemplateBinding Background}">
<Viewbox Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}">
<Path Fill="{TemplateBinding Foreground}"
Data="{TemplateBinding Data}"
Stretch="Uniform" />
</Viewbox>
</Border>
</ControlTemplate>
</Setter>
</Style>

2
src/Avalonia.Themes.Fluent/ToggleSwitch.xaml

@ -5,7 +5,7 @@
<Thickness x:Key="ToggleSwitchTopHeaderMargin">0,0,0,6</Thickness>
<GridLength x:Key="ToggleSwitchPreContentMargin">6</GridLength>
<GridLength x:Key="ToggleSwitchPostContentMargin">6</GridLength>
<x:Double x:Key="ToggleSwitchThemeMinWidth">154</x:Double>
<x:Double x:Key="ToggleSwitchThemeMinWidth">0</x:Double>
</Styles.Resources>
<Design.PreviewWith>
<StackPanel Margin="20" Width="250" Spacing="24" >

42
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -1,39 +1,5 @@
Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
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.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.Geometry.GetRenderBounds(Avalonia.Media.Pen)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Boolean Avalonia.Media.Geometry.StrokeContains(Avalonia.Media.Pen, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.GlyphRunDrawing.BaselineOrigin.set(Avalonia.Point)' 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.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.DrawableTextRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
CannotAddAbstractMembers : Member 'public Avalonia.Size Avalonia.Media.TextFormatting.DrawableTextRun.Size.get()' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.TextFormatting.ShapedTextCharacters.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.ShapedTextCharacters.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLayout.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' 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.
CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext)' is abstract in the implementation but is missing in the contract.
MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.TextLine.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' does not exist in the implementation but it does exist 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 Avalonia.Platform.IDrawingContextLayerImpl Avalonia.Platform.IDrawingContextImpl.CreateLayer(Avalonia.Size)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IRenderTargetBitmapImpl Avalonia.Platform.IDrawingContextImpl.CreateLayer(Avalonia.Size)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public Avalonia.Platform.IRenderTargetBitmapImpl Avalonia.Platform.IDrawingContextImpl.CreateLayer(Avalonia.Size)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IDrawingContextImpl.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' 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.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.
MembersMustExist : Member 'public Avalonia.Utilities.IRef<Avalonia.Platform.IRenderTargetBitmapImpl> Avalonia.Rendering.RenderLayer.Bitmap.get()' does not exist in the implementation but it does exist in the contract.
Total Issues: 37
MembersMustExist : Member 'public Avalonia.StyledProperty<System.Collections.Generic.IReadOnlyList<System.Double>> Avalonia.StyledProperty<System.Collections.Generic.IReadOnlyList<System.Double>> Avalonia.Media.DashStyle.DashesProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyList<System.Double> Avalonia.Media.DashStyle.Dashes.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.DashStyle.Dashes.set(System.Collections.Generic.IReadOnlyList<System.Double>)' does not exist in the implementation but it does exist in the contract.
Total Issues: 3

9
src/Avalonia.Visuals/CornerRadius.cs

@ -1,6 +1,8 @@
using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
using Avalonia.Utilities;
namespace Avalonia
@ -8,11 +10,16 @@ namespace Avalonia
/// <summary>
/// Represents the radii of a rectangle's corners.
/// </summary>
public readonly struct CornerRadius : IEquatable<CornerRadius>
#if !BUILDTASK
public
#endif
readonly struct CornerRadius : IEquatable<CornerRadius>
{
static CornerRadius()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator<CornerRadiusAnimator>(prop => typeof(CornerRadius).IsAssignableFrom(prop.PropertyType));
#endif
}
public CornerRadius(double uniformRadius)

5
src/Avalonia.Visuals/Matrix.cs

@ -7,7 +7,10 @@ namespace Avalonia
/// <summary>
/// A 2x3 matrix.
/// </summary>
public readonly struct Matrix : IEquatable<Matrix>
#if !BUILDTASK
public
#endif
readonly struct Matrix : IEquatable<Matrix>
{
private readonly double _m11;
private readonly double _m12;

14
src/Avalonia.Visuals/Media/Color.cs

@ -1,17 +1,24 @@
using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
namespace Avalonia.Media
{
/// <summary>
/// An ARGB color.
/// </summary>
public readonly struct Color : IEquatable<Color>
#if !BUILDTASK
public
#endif
readonly struct Color : IEquatable<Color>
{
static Color()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator<ColorAnimator>(prop => typeof(Color).IsAssignableFrom(prop.PropertyType));
#endif
}
/// <summary>
@ -223,7 +230,12 @@ namespace Avalonia.Media
if (input.Length == 3 || input.Length == 4)
{
var extendedLength = 2 * input.Length;
#if !BUILDTASK
Span<char> extended = stackalloc char[extendedLength];
#else
char[] extended = new char[extendedLength];
#endif
for (int i = 0; i < input.Length; i++)
{

75
src/Avalonia.Visuals/Media/DashStyle.cs

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Animation;
using Avalonia.Collections;
using Avalonia.Media.Immutable;
#nullable enable
namespace Avalonia.Media
{
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Animation;
using Avalonia.Media.Immutable;
/// <summary>
/// Represents the sequence of dashes and gaps that will be applied by a <see cref="Pen"/>.
/// </summary>
@ -14,8 +17,8 @@ namespace Avalonia.Media
/// <summary>
/// Defines the <see cref="Dashes"/> property.
/// </summary>
public static readonly StyledProperty<IReadOnlyList<double>> DashesProperty =
AvaloniaProperty.Register<DashStyle, IReadOnlyList<double>>(nameof(Dashes));
public static readonly StyledProperty<AvaloniaList<double>> DashesProperty =
AvaloniaProperty.Register<DashStyle, AvaloniaList<double>>(nameof(Dashes));
/// <summary>
/// Defines the <see cref="Offset"/> property.
@ -23,10 +26,10 @@ namespace Avalonia.Media
public static readonly StyledProperty<double> OffsetProperty =
AvaloniaProperty.Register<DashStyle, double>(nameof(Offset));
private static ImmutableDashStyle s_dash;
private static ImmutableDashStyle s_dot;
private static ImmutableDashStyle s_dashDot;
private static ImmutableDashStyle s_dashDotDot;
private static ImmutableDashStyle? s_dash;
private static ImmutableDashStyle? s_dot;
private static ImmutableDashStyle? s_dashDot;
private static ImmutableDashStyle? s_dashDotDot;
/// <summary>
/// Initializes a new instance of the <see cref="DashStyle"/> class.
@ -41,9 +44,9 @@ namespace Avalonia.Media
/// </summary>
/// <param name="dashes">The dashes collection.</param>
/// <param name="offset">The dash sequence offset.</param>
public DashStyle(IEnumerable<double> dashes, double offset)
public DashStyle(IEnumerable<double>? dashes, double offset)
{
Dashes = (IReadOnlyList<double>)dashes?.ToList() ?? Array.Empty<double>();
Dashes = (dashes as AvaloniaList<double>) ?? new AvaloniaList<double>(dashes ?? Array.Empty<double>());
Offset = offset;
}
@ -61,31 +64,27 @@ namespace Avalonia.Media
/// <summary>
/// Represents a dashed <see cref="DashStyle"/>.
/// </summary>
public static IDashStyle Dash =>
s_dash ?? (s_dash = new ImmutableDashStyle(new double[] { 2, 2 }, 1));
public static IDashStyle Dash => s_dash ??= new ImmutableDashStyle(new double[] { 2, 2 }, 1);
/// <summary>
/// Represents a dotted <see cref="DashStyle"/>.
/// </summary>
public static IDashStyle Dot =>
s_dot ?? (s_dot = new ImmutableDashStyle(new double[] { 0, 2 }, 0));
public static IDashStyle Dot => s_dot ??= new ImmutableDashStyle(new double[] { 0, 2 }, 0);
/// <summary>
/// Represents a dashed dotted <see cref="DashStyle"/>.
/// </summary>
public static IDashStyle DashDot =>
s_dashDot ?? (s_dashDot = new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1));
public static IDashStyle DashDot => s_dashDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1);
/// <summary>
/// Represents a dashed double dotted <see cref="DashStyle"/>.
/// </summary>
public static IDashStyle DashDotDot =>
s_dashDotDot ?? (s_dashDotDot = new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1));
public static IDashStyle DashDotDot => s_dashDotDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1);
/// <summary>
/// Gets or sets the length of alternating dashes and gaps.
/// </summary>
public IReadOnlyList<double> Dashes
public AvaloniaList<double> Dashes
{
get => GetValue(DashesProperty);
set => SetValue(DashesProperty, value);
@ -100,15 +99,43 @@ namespace Avalonia.Media
set => SetValue(OffsetProperty, value);
}
IReadOnlyList<double> IDashStyle.Dashes => Dashes;
/// <summary>
/// Raised when the dash style changes.
/// </summary>
public event EventHandler Invalidated;
public event EventHandler? Invalidated;
/// <summary>
/// Returns an immutable clone of the <see cref="DashStyle"/>.
/// </summary>
/// <returns></returns>
public ImmutableDashStyle ToImmutable() => new ImmutableDashStyle(Dashes, Offset);
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == DashesProperty)
{
var oldValue = change.OldValue.GetValueOrDefault<AvaloniaList<double>>();
var newValue = change.NewValue.GetValueOrDefault<AvaloniaList<double>>();
if (oldValue is object)
{
oldValue.CollectionChanged -= DashesChanged;
}
if (newValue is object)
{
newValue.CollectionChanged += DashesChanged;
}
}
}
private void DashesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Invalidated?.Invoke(this, e);
}
}
}

56
src/Avalonia.Visuals/Media/EllipseGeometry.cs

@ -12,10 +12,28 @@ namespace Avalonia.Media
/// </summary>
public static readonly StyledProperty<Rect> RectProperty =
AvaloniaProperty.Register<EllipseGeometry, Rect>(nameof(Rect));
/// <summary>
/// Defines the <see cref="RadiusX"/> property.
/// </summary>
public static readonly StyledProperty<double> RadiusXProperty =
AvaloniaProperty.Register<EllipseGeometry, double>(nameof(RadiusX));
/// <summary>
/// Defines the <see cref="RadiusY"/> property.
/// </summary>
public static readonly StyledProperty<double> RadiusYProperty =
AvaloniaProperty.Register<EllipseGeometry, double>(nameof(RadiusY));
/// <summary>
/// Defines the <see cref="Center"/> property.
/// </summary>
public static readonly StyledProperty<Point> CenterProperty =
AvaloniaProperty.Register<EllipseGeometry, Point>(nameof(Center));
static EllipseGeometry()
{
AffectsGeometry(RectProperty);
AffectsGeometry(RectProperty, RadiusXProperty, RadiusYProperty, CenterProperty);
}
/// <summary>
@ -43,6 +61,33 @@ namespace Avalonia.Media
set => SetValue(RectProperty, value);
}
/// <summary>
/// Gets or sets a double that defines the radius in the X-axis of the ellipse.
/// </summary>
public double RadiusX
{
get => GetValue(RadiusXProperty);
set => SetValue(RadiusXProperty, value);
}
/// <summary>
/// Gets or sets a double that defines the radius in the Y-axis of the ellipse.
/// </summary>
public double RadiusY
{
get => GetValue(RadiusYProperty);
set => SetValue(RadiusYProperty, value);
}
/// <summary>
/// Gets or sets a point that defines the center of the ellipse.
/// </summary>
public Point Center
{
get => GetValue(CenterProperty);
set => SetValue(CenterProperty, value);
}
/// <inheritdoc/>
public override Geometry Clone()
{
@ -54,7 +99,14 @@ namespace Avalonia.Media
{
var factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
return factory.CreateEllipseGeometry(Rect);
if (Rect != default) return factory.CreateEllipseGeometry(Rect);
var originX = Center.X - RadiusX;
var originY = Center.Y - RadiusY;
var width = RadiusX * 2;
var height = RadiusY * 2;
return factory.CreateEllipseGeometry(new Rect(originX, originY, width, height));
}
}
}

9
src/Avalonia.Visuals/Media/KnownColors.cs

@ -8,7 +8,9 @@ namespace Avalonia.Media
{
private static readonly IReadOnlyDictionary<string, KnownColor> _knownColorNames;
private static readonly IReadOnlyDictionary<uint, string> _knownColors;
#if !BUILDTASK
private static readonly Dictionary<KnownColor, ISolidColorBrush> _knownBrushes;
#endif
static KnownColors()
{
@ -32,14 +34,19 @@ namespace Avalonia.Media
_knownColorNames = knownColorNames;
_knownColors = knownColors;
#if !BUILDTASK
_knownBrushes = new Dictionary<KnownColor, ISolidColorBrush>();
#endif
}
#if !BUILDTASK
public static ISolidColorBrush GetKnownBrush(string s)
{
var color = GetKnownColor(s);
return color != KnownColor.None ? color.ToBrush() : null;
}
#endif
public static KnownColor GetKnownColor(string s)
{
@ -61,6 +68,7 @@ namespace Avalonia.Media
return Color.FromUInt32((uint)color);
}
#if !BUILDTASK
public static ISolidColorBrush ToBrush(this KnownColor color)
{
lock (_knownBrushes)
@ -74,6 +82,7 @@ namespace Avalonia.Media
return brush;
}
}
#endif
}
internal enum KnownColor : uint

72
src/Avalonia.Visuals/Media/PathFigure.cs

@ -1,3 +1,7 @@
#nullable enable
using System;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Metadata;
namespace Avalonia.Media
@ -8,22 +12,36 @@ namespace Avalonia.Media
/// Defines the <see cref="IsClosed"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsClosedProperty
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsClosed), true);
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsClosed), true);
/// <summary>
/// Defines the <see cref="IsFilled"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsFilledProperty
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsFilled), true);
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsFilled), true);
/// <summary>
/// Defines the <see cref="Segments"/> property.
/// </summary>
public static readonly DirectProperty<PathFigure, PathSegments> SegmentsProperty
= AvaloniaProperty.RegisterDirect<PathFigure, PathSegments>(nameof(Segments), f => f.Segments, (f, s) => f.Segments = s);
public static readonly DirectProperty<PathFigure, PathSegments?> SegmentsProperty
= AvaloniaProperty.RegisterDirect<PathFigure, PathSegments?>(
nameof(Segments),
f => f.Segments,
(f, s) => f.Segments = s);
/// <summary>
/// Defines the <see cref="StartPoint"/> property.
/// </summary>
public static readonly StyledProperty<Point> StartPointProperty
= AvaloniaProperty.Register<PathFigure, Point>(nameof(StartPoint));
= AvaloniaProperty.Register<PathFigure, Point>(nameof(StartPoint));
internal event EventHandler? SegmentsInvalidated;
private PathSegments? _segments;
private IDisposable? _segmentsDisposable;
private IDisposable? _segmentsPropertiesDisposable;
/// <summary>
/// Initializes a new instance of the <see cref="PathFigure"/> class.
@ -33,6 +51,31 @@ namespace Avalonia.Media
Segments = new PathSegments();
}
static PathFigure()
{
SegmentsProperty.Changed.AddClassHandler<PathFigure>(
(s, e) =>
s.OnSegmentsChanged());
}
private void OnSegmentsChanged()
{
_segmentsDisposable?.Dispose();
_segmentsPropertiesDisposable?.Dispose();
_segmentsDisposable = _segments?.ForEachItem(
_ => InvalidateSegments(),
_ => InvalidateSegments(),
InvalidateSegments);
_segmentsPropertiesDisposable = _segments?.TrackItemPropertyChanged(_ => InvalidateSegments());
}
private void InvalidateSegments()
{
SegmentsInvalidated?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Gets or sets a value indicating whether this instance is closed.
/// </summary>
@ -64,7 +107,7 @@ namespace Avalonia.Media
/// The segments.
/// </value>
[Content]
public PathSegments Segments
public PathSegments? Segments
{
get { return _segments; }
set { SetAndRaise(SegmentsProperty, ref _segments, value); }
@ -81,22 +124,23 @@ namespace Avalonia.Media
get { return GetValue(StartPointProperty); }
set { SetValue(StartPointProperty, value); }
}
public override string ToString()
=> $"M {StartPoint} {string.Join(" ", _segments ?? Enumerable.Empty<PathSegment>())}{(IsClosed ? "Z" : "")}";
internal void ApplyTo(StreamGeometryContext ctx)
{
ctx.BeginFigure(StartPoint, IsFilled);
foreach (var segment in Segments)
if (Segments != null)
{
segment.ApplyTo(ctx);
foreach (var segment in Segments)
{
segment.ApplyTo(ctx);
}
}
ctx.EndFigure(IsClosed);
}
private PathSegments _segments;
public override string ToString()
=> $"M {StartPoint} {string.Join(" ", _segments)}{(IsClosed ? "Z" : "")}";
}
}
}

20
src/Avalonia.Visuals/Media/PathGeometry.cs

@ -104,12 +104,26 @@ namespace Avalonia.Media
_figuresPropertiesObserver?.Dispose();
_figuresObserver = figures?.ForEachItem(
_ => InvalidateGeometry(),
_ => InvalidateGeometry(),
() => InvalidateGeometry());
s =>
{
s.SegmentsInvalidated += InvalidateGeometryFromSegments;
InvalidateGeometry();
},
s =>
{
s.SegmentsInvalidated -= InvalidateGeometryFromSegments;
InvalidateGeometry();
},
InvalidateGeometry);
_figuresPropertiesObserver = figures?.TrackItemPropertyChanged(_ => InvalidateGeometry());
}
private void InvalidateGeometryFromSegments(object _, EventArgs __)
{
InvalidateGeometry();
}
public override string ToString()
=> $"{(FillRule != FillRule.EvenOdd ? "F1 " : "")}{(string.Join(" ", Figures))}";

9
src/Avalonia.Visuals/Point.cs

@ -1,6 +1,8 @@
using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
using Avalonia.Utilities;
namespace Avalonia
@ -8,11 +10,16 @@ namespace Avalonia
/// <summary>
/// Defines a point.
/// </summary>
public readonly struct Point : IEquatable<Point>
#if !BUILDTASK
public
#endif
readonly struct Point : IEquatable<Point>
{
static Point()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator<PointAnimator>(prop => typeof(Point).IsAssignableFrom(prop.PropertyType));
#endif
}
/// <summary>

79
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -99,6 +99,11 @@ namespace Avalonia.Rendering
/// </summary>
public string DebugFramesPath { get; set; }
/// <summary>
/// Forces the renderer to only draw frames on the render thread. Makes Paint to wait until frame is rendered
/// </summary>
public bool RenderOnlyOnRenderThread { get; set; }
/// <inheritdoc/>
public event EventHandler<SceneInvalidatedEventArgs> SceneInvalidated;
@ -180,11 +185,44 @@ namespace Avalonia.Rendering
/// <inheritdoc/>
public void Paint(Rect rect)
{
var t = (IRenderLoopTask)this;
if(t.NeedsUpdate)
UpdateScene();
if(_scene?.Item != null)
Render(true);
if (RenderOnlyOnRenderThread)
{
// Renderer is stopped and doesn't tick on the render thread
// This indicates a bug somewhere in our code
// (currently happens when a window gets minimized with Show desktop on Windows 10)
if(!_running)
return;
while (true)
{
Scene scene;
bool? updated;
lock (_sceneLock)
{
updated = UpdateScene();
scene = _scene?.Item;
}
// Renderer is in invalid state, skip drawing
if(updated == null)
return;
// Wait for the scene to be rendered or disposed
scene?.Rendered.Wait();
// That was an up-to-date scene, we can return immediately
if (updated == true)
return;
}
}
else
{
var t = (IRenderLoopTask)this;
if (t.NeedsUpdate)
UpdateScene();
if (_scene?.Item != null)
Render(true);
}
}
/// <inheritdoc/>
@ -270,13 +308,20 @@ namespace Avalonia.Rendering
{
if (scene?.Item != null)
{
var overlay = DrawDirtyRects || DrawFps;
if (DrawDirtyRects)
_dirtyRectsDisplay.Tick();
if (overlay)
RenderOverlay(scene.Item, ref context);
if (updated || forceComposite || overlay)
RenderComposite(scene.Item, ref context);
try
{
var overlay = DrawDirtyRects || DrawFps;
if (DrawDirtyRects)
_dirtyRectsDisplay.Tick();
if (overlay)
RenderOverlay(scene.Item, ref context);
if (updated || forceComposite || overlay)
RenderComposite(scene.Item, ref context);
}
finally
{
scene.Item.MarkAsRendered();
}
}
}
}
@ -559,15 +604,15 @@ namespace Avalonia.Rendering
UpdateScene();
}
private void UpdateScene()
private bool? UpdateScene()
{
Dispatcher.UIThread.VerifyAccess();
lock (_sceneLock)
{
if (_disposed)
return;
return null;
if (_scene?.Item.Generation > _lastSceneId)
return;
return false;
}
if (_root.IsVisible)
{
@ -619,6 +664,8 @@ namespace Avalonia.Rendering
SceneInvalidated(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect));
}
return true;
}
else
{
@ -628,6 +675,8 @@ namespace Avalonia.Rendering
_scene = null;
oldScene?.Dispose();
}
return null;
}
}

7
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Collections.Pooled;
using Avalonia.VisualTree;
@ -13,6 +14,7 @@ namespace Avalonia.Rendering.SceneGraph
public class Scene : IDisposable
{
private readonly Dictionary<IVisual, IVisualNode> _index;
private readonly TaskCompletionSource<bool> _rendered = new TaskCompletionSource<bool>();
/// <summary>
/// Initializes a new instance of the <see cref="Scene"/> class.
@ -41,6 +43,8 @@ namespace Avalonia.Rendering.SceneGraph
root.LayerRoot = root.Visual;
}
public Task Rendered => _rendered.Task;
/// <summary>
/// Gets a value identifying the scene's generation. This is incremented each time the scene is cloned.
/// </summary>
@ -97,6 +101,7 @@ namespace Avalonia.Rendering.SceneGraph
public void Dispose()
{
_rendered.TrySetResult(false);
foreach (var node in _index.Values)
{
node.Dispose();
@ -340,5 +345,7 @@ namespace Avalonia.Rendering.SceneGraph
}
}
}
public void MarkAsRendered() => _rendered.TrySetResult(true);
}
}

9
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -24,7 +24,8 @@ namespace Avalonia.Rendering.SceneGraph
using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
using (var context = new DrawingContext(impl))
{
Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
var clip = new Rect(scene.Root.Visual.Bounds.Size);
Update(context, scene, (VisualNode)scene.Root, clip, true);
}
}
@ -77,7 +78,7 @@ namespace Avalonia.Rendering.SceneGraph
using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
using (var context = new DrawingContext(impl))
{
var clip = scene.Root.Visual.Bounds;
var clip = new Rect(scene.Root.Visual.Bounds.Size);
if (node.Parent != null)
{
@ -174,7 +175,9 @@ namespace Avalonia.Rendering.SceneGraph
if (visual.IsVisible)
{
var m = Matrix.CreateTranslation(visual.Bounds.Position);
var m = node != scene.Root ?
Matrix.CreateTranslation(visual.Bounds.Position) :
Matrix.Identity;
var renderTransform = Matrix.Identity;

9
src/Avalonia.Visuals/Size.cs

@ -1,6 +1,8 @@
using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
using Avalonia.Utilities;
namespace Avalonia
@ -8,11 +10,16 @@ namespace Avalonia
/// <summary>
/// Defines a size.
/// </summary>
public readonly struct Size : IEquatable<Size>
#if !BUILDTASK
public
#endif
readonly struct Size : IEquatable<Size>
{
static Size()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator<SizeAnimator>(prop => typeof(Size).IsAssignableFrom(prop.PropertyType));
#endif
}
/// <summary>

9
src/Avalonia.Visuals/Thickness.cs

@ -1,6 +1,8 @@
using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
using Avalonia.Utilities;
namespace Avalonia
@ -8,11 +10,16 @@ namespace Avalonia
/// <summary>
/// Describes the thickness of a frame around a rectangle.
/// </summary>
public readonly struct Thickness : IEquatable<Thickness>
#if !BUILDTASK
public
#endif
readonly struct Thickness : IEquatable<Thickness>
{
static Thickness()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator<ThicknessAnimator>(prop => typeof(Thickness).IsAssignableFrom(prop.PropertyType));
#endif
}
/// <summary>

9
src/Avalonia.Visuals/Vector.cs

@ -1,6 +1,8 @@
using System;
using System.Globalization;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
using Avalonia.Utilities;
#nullable enable
@ -10,11 +12,16 @@ namespace Avalonia
/// <summary>
/// Defines a vector.
/// </summary>
public readonly struct Vector : IEquatable<Vector>
#if !BUILDTASK
public
#endif
readonly struct Vector : IEquatable<Vector>
{
static Vector()
{
#if !BUILDTASK
Animation.Animation.RegisterAnimator<VectorAnimator>(prop => typeof(Vector).IsAssignableFrom(prop.PropertyType));
#endif
}
/// <summary>

37
src/Avalonia.Visuals/Visual.cs

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using Avalonia.Collections;
using Avalonia.Data;
@ -619,34 +620,30 @@ namespace Avalonia
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (Visual v in e.NewItems)
{
v.SetVisualParent(this);
}
SetVisualParent(e.NewItems, this);
break;
case NotifyCollectionChangedAction.Remove:
foreach (Visual v in e.OldItems)
{
v.SetVisualParent(null);
}
SetVisualParent(e.OldItems, null);
break;
case NotifyCollectionChangedAction.Replace:
foreach (Visual v in e.OldItems)
{
v.SetVisualParent(null);
}
foreach (Visual v in e.NewItems)
{
v.SetVisualParent(this);
}
SetVisualParent(e.OldItems, null);
SetVisualParent(e.NewItems, this);
break;
}
}
private static void SetVisualParent(IList children, Visual parent)
{
var count = children.Count;
for (var i = 0; i < count; i++)
{
var visual = (Visual) children[i];
visual.SetVisualParent(parent);
}
}
}
}

10
src/Avalonia.X11/X11Window.cs

@ -189,6 +189,11 @@ namespace Avalonia.X11
if (platform.Options.UseDBusMenu)
NativeMenuExporter = DBusMenuExporter.TryCreate(_handle);
NativeControlHost = new X11NativeControlHost(_platform, this);
DispatcherTimer.Run(() =>
{
Paint?.Invoke(default);
return _handle != IntPtr.Zero;
}, TimeSpan.FromMilliseconds(100));
}
class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
@ -338,7 +343,10 @@ namespace Avalonia.X11
return customRendererFactory.Create(root, loop);
return _platform.Options.UseDeferredRendering ?
new DeferredRenderer(root, loop) :
new DeferredRenderer(root, loop)
{
RenderOnlyOnRenderThread = true
} :
(IRenderer)new X11ImmediateRendererProxy(root, loop);
}

2
src/Avalonia.X11/XI2Manager.cs

@ -351,7 +351,7 @@ namespace Avalonia.X11
if (state.HasFlag(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta;
Modifiers = ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Modifiers |= ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Valuators = new Dictionary<int, double>();
Position = new Point(ev->event_x, ev->event_y);

1
src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj

@ -4,6 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>true</IsPackable>
<PackageId>Avalonia.Markup.Xaml.Loader</PackageId>
<DefineConstants>$(DefineConstants);XAMLX_INTERNAL</DefineConstants>
</PropertyGroup>
<Import Project="IncludeXamlIlSre.props" />
<ItemGroup>

39
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlFontFamilyAstNode.cs

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
{
class AvaloniaXamlIlFontFamilyAstNode: XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
{
private readonly AvaloniaXamlIlWellKnownTypes _types;
private readonly string _text;
public IXamlAstTypeReference Type { get; }
public AvaloniaXamlIlFontFamilyAstNode(AvaloniaXamlIlWellKnownTypes types,
string text,
IXamlLineInfo lineInfo) : base(lineInfo)
{
_types = types;
_text = text;
Type = new XamlAstClrTypeReference(lineInfo, types.FontFamily, false);
}
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
codeGen
.Ldloc(context.ContextLocal)
.Castclass(context.Configuration.TypeMappings.UriContextProvider)
.EmitCall(context.Configuration.TypeMappings.UriContextProvider.FindMethod(
"get_BaseUri", _types.Uri, false))
.Ldstr(_text)
.Newobj(_types.FontFamilyConstructorUriName);
return XamlILNodeEmitResult.Type(0, _types.FontFamily);
}
}
}

34
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlGridLengthAstNode.cs

@ -0,0 +1,34 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
{
class AvaloniaXamlIlGridLengthAstNode : XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
{
private readonly AvaloniaXamlIlWellKnownTypes _types;
private readonly GridLength _gridLength;
public AvaloniaXamlIlGridLengthAstNode(IXamlLineInfo lineInfo, AvaloniaXamlIlWellKnownTypes types, GridLength gridLength) : base(lineInfo)
{
_types = types;
_gridLength = gridLength;
Type = new XamlAstClrTypeReference(lineInfo, types.GridLength, false);
}
public IXamlAstTypeReference Type { get; }
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
codeGen
.Ldc_R8(_gridLength.Value)
.Ldc_I4((int)_gridLength.GridUnitType)
.Newobj(_types.GridLengthConstructorValueType);
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
}

54
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AstNodes/AvaloniaXamlIlVectorLikeConstantAstNode.cs

@ -0,0 +1,54 @@
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes
{
class AvaloniaXamlIlVectorLikeConstantAstNode : XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
{
private readonly IXamlConstructor _constructor;
private readonly double[] _values;
public AvaloniaXamlIlVectorLikeConstantAstNode(IXamlLineInfo lineInfo, AvaloniaXamlIlWellKnownTypes types, IXamlType type, IXamlConstructor constructor, double[] values) : base(lineInfo)
{
var parameters = constructor.Parameters;
if (parameters.Count != values.Length)
{
throw new XamlTypeSystemException($"Constructor that takes {values.Length} parameters is expected, got {parameters.Count} instead.");
}
var elementType = types.XamlIlTypes.Double;
foreach (var parameter in parameters)
{
if (parameter != elementType)
{
throw new XamlTypeSystemException($"Expected parameter of type {elementType}, got {parameter} instead.");
}
}
_constructor = constructor;
_values = values;
Type = new XamlAstClrTypeReference(lineInfo, type, false);
}
public IXamlAstTypeReference Type { get; }
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
foreach (var value in _values)
{
codeGen.Ldc_R8(value);
}
codeGen.Newobj(_constructor);
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
}

200
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@ -1,7 +1,11 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.AstNodes;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using Avalonia.Media;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
@ -166,28 +170,196 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public static bool CustomValueConverter(AstTransformationContext context,
IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result)
{
if (type.FullName == "System.TimeSpan"
&& node is XamlAstTextNode tn
&& !tn.Text.Contains(":"))
{
var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture);
result = new XamlStaticOrTargetedReturnMethodCallNode(tn,
type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double),
new[]
{
new XamlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds)
});
if (!(node is XamlAstTextNode textNode))
{
result = null;
return false;
}
var text = textNode.Text;
var types = context.GetAvaloniaTypes();
if (type.FullName == "System.TimeSpan")
{
var tsText = text.Trim();
if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan))
{
// // shorthand seconds format (ie. "0.25")
if (!tsText.Contains(":") && double.TryParse(tsText,
NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture, out var seconds))
timeSpan = TimeSpan.FromSeconds(seconds);
else
throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node);
}
result = new XamlStaticOrTargetedReturnMethodCallNode(node,
type.FindMethod("FromTicks", type, false, types.Long),
new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) });
return true;
}
if (type.Equals(types.FontFamily))
{
result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node);
return true;
}
if (type.Equals(types.Thickness))
{
try
{
var thickness = Thickness.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Thickness, types.ThicknessFullConstructor,
new[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom });
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a thickness", node);
}
}
if (type.Equals(types.Point))
{
try
{
var point = Point.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Point, types.PointFullConstructor,
new[] { point.X, point.Y });
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a point", node);
}
}
if (type.Equals(types.Vector))
{
try
{
var vector = Vector.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Vector, types.VectorFullConstructor,
new[] { vector.X, vector.Y });
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a vector", node);
}
}
if (type.Equals(types.Size))
{
try
{
var size = Size.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Size, types.SizeFullConstructor,
new[] { size.Width, size.Height });
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a size", node);
}
}
if (type.Equals(types.Matrix))
{
try
{
var matrix = Matrix.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Matrix, types.MatrixFullConstructor,
new[] { matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32 });
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a matrix", node);
}
}
if (type.Equals(types.CornerRadius))
{
try
{
var cornerRadius = CornerRadius.Parse(text);
result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.CornerRadius, types.CornerRadiusFullConstructor,
new[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft });
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a corner radius", node);
}
}
if (type.Equals(types.Color))
{
if (!Color.TryParse(text, out Color color))
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a color", node);
}
result = new XamlStaticOrTargetedReturnMethodCallNode(node,
type.GetMethod(
new FindMethodMethodSignature("FromUInt32", type, types.UInt) { IsStatic = true }),
new[] { new XamlConstantNode(node, types.UInt, color.ToUint32()) });
return true;
}
if (type.Equals(types.GridLength))
{
try
{
var gridLength = GridLength.Parse(text);
result = new AvaloniaXamlIlGridLengthAstNode(node, types, gridLength);
return true;
}
catch
{
throw new XamlX.XamlLoadException($"Unable to parse \"{text}\" as a grid length", node);
}
}
if (type.Equals(types.Cursor))
{
if (TypeSystemHelpers.TryGetEnumValueNode(types.StandardCursorType, text, node, out var enumConstantNode))
{
var cursorTypeRef = new XamlAstClrTypeReference(node, types.Cursor, false);
result = new XamlAstNewClrObjectNode(node, cursorTypeRef, types.CursorTypeConstructor, new List<IXamlAstValueNode> { enumConstantNode });
return true;
}
}
if (type.FullName == "Avalonia.AvaloniaProperty")
{
var scope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
if (scope == null)
throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
if (!(node is XamlAstTextNode text))
throw new XamlX.XamlLoadException("Property should be a text node", node);
result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text);
result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node );
return true;
}

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

@ -22,7 +22,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
var avaloniaObject = context.Configuration.TypeSystem.FindType("Avalonia.AvaloniaObject");
if (avaloniaObject.IsAssignableFrom(targetRef.Type)
&& avaloniaObject.IsAssignableFrom(declaringRef.Type)
&& !targetRef.Type.IsAssignableFrom(declaringRef.Type))
&& !declaringRef.Type.IsAssignableFrom(targetRef.Type))
{
// Instance property
var clrProp = declaringRef.Type.GetAllProperties().FirstOrDefault(p => p.Name == prop.Name);

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

@ -1,3 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using XamlX.Emit;
using XamlX.IL;
using XamlX.Transform;
@ -47,6 +49,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType ReflectionBindingExtension { get; }
public IXamlType RelativeSource { get; }
public IXamlType UInt { get; }
public IXamlType Long { get; }
public IXamlType Uri { get; }
public IXamlType FontFamily { get; }
public IXamlConstructor FontFamilyConstructorUriName { get; }
public IXamlType Thickness { get; }
public IXamlConstructor ThicknessFullConstructor { get; }
public IXamlType Point { get; }
public IXamlConstructor PointFullConstructor { get; }
public IXamlType Vector { get; }
public IXamlConstructor VectorFullConstructor { get; }
public IXamlType Size { get; }
public IXamlConstructor SizeFullConstructor { get; }
public IXamlType Matrix { get; }
public IXamlConstructor MatrixFullConstructor { get; }
public IXamlType CornerRadius { get; }
public IXamlConstructor CornerRadiusFullConstructor { get; }
public IXamlType GridLength { get; }
public IXamlConstructor GridLengthConstructorValueType { get; }
public IXamlType Color { get; }
public IXamlType StandardCursorType { get; }
public IXamlType Cursor { get; }
public IXamlConstructor CursorTypeConstructor { get; }
public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
{
@ -104,6 +129,33 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
ItemsRepeater = cfg.TypeSystem.GetType("Avalonia.Controls.ItemsRepeater");
ReflectionBindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.ReflectionBindingExtension");
RelativeSource = cfg.TypeSystem.GetType("Avalonia.Data.RelativeSource");
UInt = cfg.TypeSystem.GetType("System.UInt32");
Long = cfg.TypeSystem.GetType("System.Int64");
Uri = cfg.TypeSystem.GetType("System.Uri");
FontFamily = cfg.TypeSystem.GetType("Avalonia.Media.FontFamily");
FontFamilyConstructorUriName = FontFamily.GetConstructor(new List<IXamlType> { Uri, XamlIlTypes.String });
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
{
var type = cfg.TypeSystem.GetType(name);
var ctor = type.GetConstructor(Enumerable.Range(0, componentCount).Select(_ => componentType).ToList());
return (type, ctor);
}
(Thickness, ThicknessFullConstructor) = GetNumericTypeInfo("Avalonia.Thickness", XamlIlTypes.Double, 4);
(Point, PointFullConstructor) = GetNumericTypeInfo("Avalonia.Point", XamlIlTypes.Double, 2);
(Vector, VectorFullConstructor) = GetNumericTypeInfo("Avalonia.Vector", XamlIlTypes.Double, 2);
(Size, SizeFullConstructor) = GetNumericTypeInfo("Avalonia.Size", XamlIlTypes.Double, 2);
(Matrix, MatrixFullConstructor) = GetNumericTypeInfo("Avalonia.Matrix", XamlIlTypes.Double, 6);
(CornerRadius, CornerRadiusFullConstructor) = GetNumericTypeInfo("Avalonia.CornerRadius", XamlIlTypes.Double, 4);
GridLength = cfg.TypeSystem.GetType("Avalonia.Controls.GridLength");
GridLengthConstructorValueType = GridLength.GetConstructor(new List<IXamlType> { XamlIlTypes.Double, cfg.TypeSystem.GetType("Avalonia.Controls.GridUnitType") });
Color = cfg.TypeSystem.GetType("Avalonia.Media.Color");
StandardCursorType = cfg.TypeSystem.GetType("Avalonia.Input.StandardCursorType");
Cursor = cfg.TypeSystem.GetType("Avalonia.Input.Cursor");
CursorTypeConstructor = Cursor.GetConstructor(new List<IXamlType> { StandardCursorType });
}
}

32
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs

@ -203,6 +203,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.ParentNodes()
.OfType<XamlAstConstructableObjectNode>()
.Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
.Skip(1)
.ElementAtOrDefault(ancestor.Level)
?.Type.GetClrType();
@ -242,6 +243,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
case RawSourceBindingExpressionNode rawSource:
nodes.Add(new RawSourcePathElementNode(rawSource.RawSource));
break;
case BindingExpressionGrammar.TypeCastNode typeCastNode:
var castType = GetType(typeCastNode.Namespace, typeCastNode.TypeName);
if (castType is null)
{
throw new XamlX.XamlParseException($"Unable to resolve cast to type {typeCastNode.Namespace}:{typeCastNode.TypeName} based on XAML tree.", lineInfo);
}
nodes.Add(new TypeCastPathElementNode(castType));
break;
}
}
@ -422,7 +433,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{
codeGen.Ldtype(Type)
.Ldc_I4(_level)
.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "FindAncestor"));
.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "Ancestor"));
}
}
@ -608,10 +619,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
private readonly IXamlAstValueNode _rawSource;
public RawSourcePathElementNode(IXamlAstValueNode rawSource)
:base(rawSource)
: base(rawSource)
{
_rawSource = rawSource;
}
public IXamlType Type => _rawSource.Type.GetClrType();
@ -625,6 +636,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
class TypeCastPathElementNode : IXamlIlBindingPathElementNode
{
public TypeCastPathElementNode(IXamlType ancestorType)
{
Type = ancestorType;
}
public IXamlType Type { get; }
public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{
codeGen.EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "TypeCast").MakeGenericMethod(new[] { Type }));
}
}
class XamlIlBindingPathNode : XamlAstNode, IXamlIlBindingPathNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
{
private readonly List<IXamlIlBindingPathElementNode> _transformElements;

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

@ -1 +1 @@
Subproject commit 5420df861ce6f2be5ead9efa078fe7242ce88f18
Subproject commit ea80a607c5e9d8f000160dbbb48c27ed4cfafbc9

1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -23,6 +23,7 @@
<Compile Include="MarkupExtensions\CompiledBindings\ObservableStreamPlugin.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\PropertyInfoAccessorFactory.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\PropertyInfoAccessorPlugin.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\StrongTypeCastNode.cs" />
<Compile Include="MarkupExtensions\CompiledBindings\TaskStreamPlugin.cs" />
<Compile Include="MarkupExtensions\DynamicResourceExtension.cs" />
<Compile Include="MarkupExtensions\ResolveByNameExtension.cs" />

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs

@ -26,6 +26,8 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
Path = Path,
Converter = Converter,
ConverterParameter = ConverterParameter,
TargetNullValue = TargetNullValue,
FallbackValue = FallbackValue,
Mode = Mode,
Priority = Priority,

51
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
@ -53,6 +54,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
case IStronglyTypedStreamElement stream:
node = new StreamNode(stream.CreatePlugin());
break;
case ITypeCastElement typeCast:
node = new StrongTypeCastNode(typeCast.Type, typeCast.Cast);
break;
default:
throw new InvalidOperationException($"Unknown binding path element type {element.GetType().FullName}");
}
@ -66,6 +70,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal SourceMode SourceMode => _elements.Count > 0 && _elements[0] is IControlSourceBindingPathElement ? SourceMode.Control : SourceMode.Data;
internal object RawSource { get; }
public override string ToString()
=> string.Concat(_elements.Select(e => e.ToString()));
}
public class CompiledBindingPathBuilder
@ -126,6 +133,12 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
return this;
}
public CompiledBindingPathBuilder TypeCast<T>()
{
_elements.Add(new TypeCastPathElement<T>());
return this;
}
public CompiledBindingPathBuilder SetRawSource(object rawSource)
{
_rawSource = rawSource;
@ -157,6 +170,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public IPropertyInfo Property { get; }
public Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; }
public override string ToString()
=> $".{Property.Name}";
}
internal interface IStronglyTypedStreamElement : ICompiledBindingPathElement
@ -164,6 +180,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
IStreamPlugin CreatePlugin();
}
internal interface ITypeCastElement : ICompiledBindingPathElement
{
Type Type { get; }
Func<object, object> Cast { get; }
}
internal class TaskStreamPathElement<T> : IStronglyTypedStreamElement
{
public static readonly TaskStreamPathElement<T> Instance = new TaskStreamPathElement<T>();
@ -181,6 +204,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class SelfPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
{
public static readonly SelfPathElement Instance = new SelfPathElement();
public override string ToString()
=> "$self";
}
internal class AncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
@ -193,6 +219,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public Type AncestorType { get; }
public int Level { get; }
public override string ToString()
=> $"$parent[{AncestorType?.Name},{Level}]";
}
internal class VisualAncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
@ -217,6 +246,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public INameScope NameScope { get; }
public string Name { get; }
public override string ToString()
=> $"#{Name}";
}
internal class ArrayElementPathElement : ICompiledBindingPathElement
@ -229,5 +261,24 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public int[] Indices { get; }
public Type ElementType { get; }
public override string ToString()
=> $"[{string.Join(",", Indices)}]";
}
internal class TypeCastPathElement<T> : ITypeCastElement
{
private static object TryCast(object obj)
{
if (obj is T result)
return result;
return null;
}
public Type Type => typeof(T);
public Func<object, object> Cast => TryCast;
public override string ToString()
=> $"({Type.FullName})";
}
}

18
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/StrongTypeCastNode.cs

@ -0,0 +1,18 @@
using System;
using Avalonia.Data.Core;
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
{
public class StrongTypeCastNode : TypeCastNode
{
private Func<object, object> _cast;
public StrongTypeCastNode(Type type, Func<object, object> cast) : base(type)
{
_cast = cast;
}
protected override object Cast(object value)
=> _cast(value);
}
}

18
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs

@ -10,8 +10,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
{
public class DynamicResourceExtension : IBinding
{
private IStyledElement? _anchor;
private IResourceProvider? _resourceProvider;
private object? _anchor;
public DynamicResourceExtension()
{
@ -30,12 +29,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
if (!(provideTarget.TargetObject is IStyledElement))
{
_anchor = serviceProvider.GetFirstParent<IStyledElement>();
if (_anchor is null)
{
_resourceProvider = serviceProvider.GetFirstParent<IResourceProvider>();
}
_anchor = serviceProvider.GetFirstParent<IStyledElement>() ??
serviceProvider.GetFirstParent<IResourceProvider>() ??
(object?)serviceProvider.GetFirstParent<IResourceHost>();
}
return this;
@ -52,16 +48,16 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
return null;
}
var control = target as IStyledElement ?? _anchor as IStyledElement;
var control = target as IResourceHost ?? _anchor as IResourceHost;
if (control != null)
{
var source = control.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
return InstancedBinding.OneWay(source);
}
else if (_resourceProvider is object)
else if (_anchor is IResourceProvider resourceProvider)
{
var source = _resourceProvider.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
var source = resourceProvider.GetResourceObservable(ResourceKey, GetConverter(targetProperty));
return InstancedBinding.OneWay(source);
}

89
src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs

@ -46,6 +46,10 @@ namespace Avalonia.Markup.Parsers
state = ParseIndexer(ref r, nodes);
break;
case State.TypeCast:
state = ParseTypeCast(ref r, nodes);
break;
case State.ElementName:
state = ParseElementName(ref r, nodes);
mode = SourceMode.Control;
@ -84,6 +88,11 @@ namespace Avalonia.Markup.Parsers
}
else if (ParseOpenBrace(ref r))
{
if (PeekOpenBrace(ref r))
{
return State.TypeCast;
}
return State.AttachedProperty;
}
else if (PeekOpenBracket(ref r))
@ -124,6 +133,10 @@ namespace Avalonia.Markup.Parsers
{
return State.Indexer;
}
else if (ParseOpenBrace(ref r))
{
return State.TypeCast;
}
return State.End;
}
@ -132,6 +145,11 @@ namespace Avalonia.Markup.Parsers
{
if (ParseOpenBrace(ref r))
{
if (PeekOpenBrace(ref r))
{
return State.TypeCast;
}
return State.AttachedProperty;
}
else
@ -152,6 +170,12 @@ namespace Avalonia.Markup.Parsers
{
var (ns, owner) = ParseTypeName(ref r);
if(!r.End && r.TakeIf(')'))
{
nodes.Add(new TypeCastNode() { Namespace = ns, TypeName = owner });
return State.AfterMember;
}
if (r.End || !r.TakeIf('.'))
{
throw new ExpressionParseException(r.Position, "Invalid attached property name.");
@ -159,6 +183,11 @@ namespace Avalonia.Markup.Parsers
var name = r.ParseIdentifier();
if (name.Length == 0)
{
throw new ExpressionParseException(r.Position, "Attached Property name expected after '.'.");
}
if (r.End || !r.TakeIf(')'))
{
throw new ExpressionParseException(r.Position, "Expected ')'.");
@ -186,6 +215,39 @@ namespace Avalonia.Markup.Parsers
return State.AfterMember;
}
private static State ParseTypeCast(ref CharacterReader r, List<INode> nodes)
{
bool parseMemberBeforeAddCast = ParseOpenBrace(ref r);
var (ns, typeName) = ParseTypeName(ref r);
var result = State.AfterMember;
if (parseMemberBeforeAddCast)
{
if (!ParseCloseBrace(ref r))
{
throw new ExpressionParseException(r.Position, "Expected ')'.");
}
result = ParseBeforeMember(ref r, nodes);
if(r.Peek == '[')
{
result = ParseIndexer(ref r, nodes);
}
}
nodes.Add(new TypeCastNode { Namespace = ns, TypeName = typeName });
if (r.End || !r.TakeIf(')'))
{
throw new ExpressionParseException(r.Position, "Expected ')'.");
}
return result;
}
private static State ParseElementName(ref CharacterReader r, List<INode> nodes)
{
var name = r.ParseIdentifier();
@ -288,11 +350,21 @@ namespace Avalonia.Markup.Parsers
return !r.End && r.TakeIf('(');
}
private static bool ParseCloseBrace(ref CharacterReader r)
{
return !r.End && r.TakeIf(')');
}
private static bool PeekOpenBracket(ref CharacterReader r)
{
return !r.End && r.Peek == '[';
}
private static bool PeekOpenBrace(ref CharacterReader r)
{
return !r.End && r.Peek == '(';
}
private static bool ParseStreamOperator(ref CharacterReader r)
{
return !r.End && r.TakeIf('^');
@ -322,6 +394,7 @@ namespace Avalonia.Markup.Parsers
BeforeMember,
AttachedProperty,
Indexer,
TypeCast,
End,
}
@ -343,9 +416,9 @@ namespace Avalonia.Markup.Parsers
}
}
public interface INode {}
public interface INode { }
public interface ITransformNode {}
public interface ITransformNode { }
public class EmptyExpressionNode : INode { }
@ -366,11 +439,11 @@ namespace Avalonia.Markup.Parsers
public IList<string> Arguments { get; set; }
}
public class NotNode : INode, ITransformNode {}
public class NotNode : INode, ITransformNode { }
public class StreamNode : INode {}
public class StreamNode : INode { }
public class SelfNode : INode {}
public class SelfNode : INode { }
public class NameNode : INode
{
@ -383,5 +456,11 @@ namespace Avalonia.Markup.Parsers
public string TypeName { get; set; }
public int Level { get; set; }
}
public class TypeCastNode : INode
{
public string Namespace { get; set; }
public string TypeName { get; set; }
}
}
}

19
src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs

@ -59,6 +59,9 @@ namespace Avalonia.Markup.Parsers
case BindingExpressionGrammar.NameNode elementName:
nextNode = new ElementNameNode(_nameScope, elementName.Name);
break;
case BindingExpressionGrammar.TypeCastNode typeCast:
nextNode = ParseTypeCastNode(typeCast);
break;
}
if (rootNode is null)
{
@ -92,6 +95,22 @@ namespace Avalonia.Markup.Parsers
return new FindAncestorNode(ancestorType, ancestorLevel);
}
private TypeCastNode ParseTypeCastNode(BindingExpressionGrammar.TypeCastNode node)
{
Type castType = null;
if (!(node.Namespace is null) && !(node.TypeName is null))
{
if (_typeResolver == null)
{
throw new InvalidOperationException("Cannot parse a binding path with a typed Cast without a type resolver. Maybe you can use a LINQ Expression binding path instead?");
}
castType = _typeResolver(node.Namespace, node.TypeName);
}
return new TypeCastNode(castType);
}
private AvaloniaPropertyAccessorNode ParseAttachedProperty(BindingExpressionGrammar.AttachedPropertyNameNode node)
{
if (_typeResolver == null)

12
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -434,7 +434,7 @@ namespace Avalonia.Skia
/// <inheritdoc />
public IDrawingContextLayerImpl CreateLayer(Size size)
{
return CreateRenderTarget( size);
return CreateRenderTarget(size, true);
}
/// <inheritdoc />
@ -673,7 +673,7 @@ namespace Avalonia.Skia
private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage)
{
var calc = new TileBrushCalculator(tileBrush, tileBrushImage.PixelSize.ToSizeWithDpi(_dpi), targetSize);
var intermediate = CreateRenderTarget(calc.IntermediateSize);
var intermediate = CreateRenderTarget(calc.IntermediateSize, false);
paintWrapper.AddDisposable(intermediate);
@ -748,7 +748,7 @@ namespace Avalonia.Skia
if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1)
{
var intermediate = CreateRenderTarget(intermediateSize);
var intermediate = CreateRenderTarget(intermediateSize, false);
using (var ctx = intermediate.CreateDrawingContext(visualBrushRenderer))
{
@ -978,9 +978,10 @@ namespace Avalonia.Skia
/// Create new render target compatible with this drawing context.
/// </summary>
/// <param name="size">The size of the render target in DIPs.</param>
/// <param name="isLayer">Whether the render target is being created for a layer.</param>
/// <param name="format">Pixel format.</param>
/// <returns></returns>
private SurfaceRenderTarget CreateRenderTarget(Size size, PixelFormat? format = null)
private SurfaceRenderTarget CreateRenderTarget(Size size, bool isLayer, PixelFormat? format = null)
{
var pixelSize = PixelSize.FromSizeWithDpi(size, _dpi);
var createInfo = new SurfaceRenderTarget.CreateInfo
@ -992,7 +993,8 @@ namespace Avalonia.Skia
DisableTextLcdRendering = !_canTextUseLcdRendering,
GrContext = _grContext,
Gpu = _gpu,
Session = _session
Session = _session,
DisableManualFbo = !isLayer,
};
return new SurfaceRenderTarget(createInfo);

3
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -124,7 +124,8 @@ namespace Avalonia.Skia
Width = size.Width,
Height = size.Height,
Dpi = dpi,
DisableTextLcdRendering = false
DisableTextLcdRendering = false,
DisableManualFbo = true,
};
return new SurfaceRenderTarget(createInfo);

5
src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs

@ -51,7 +51,8 @@ namespace Avalonia.Skia
_grContext = createInfo.GrContext;
_gpu = createInfo.Gpu;
_surface = _gpu?.TryCreateSurface(PixelSize, createInfo.Session);
if (!createInfo.DisableManualFbo)
_surface = _gpu?.TryCreateSurface(PixelSize, createInfo.Session);
if (_surface == null)
_surface = new SkiaSurfaceWrapper(CreateSurface(createInfo.GrContext, PixelSize.Width, PixelSize.Height,
createInfo.Format));
@ -220,6 +221,8 @@ namespace Avalonia.Skia
public ISkiaGpu Gpu;
public ISkiaGpuRenderSession Session;
public bool DisableManualFbo;
}
}
}

1
src/Windows/Avalonia.Win32/.gitignore

@ -0,0 +1 @@
*.Generated.cs

4
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -5,9 +5,11 @@
<PackageId>Avalonia.Win32</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<PackageReference Include="Microsoft.Windows.SDK.NET" Version="10.0.18362.3-preview" />
<AvnComIdl Include="WinRT\winrt.idl" OutputFile="WinRT\WinRT.Generated.cs" />
</ItemGroup>
<Import Project="../../../build/MicroCom.targets" />
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
</Project>

18
src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs

@ -1,18 +0,0 @@
namespace Avalonia.Win32
{
internal class CompositionBlurHost : IBlurHost
{
Windows.UI.Composition.Visual _blurVisual;
public CompositionBlurHost(Windows.UI.Composition.Visual blurVisual)
{
_blurVisual = blurVisual;
}
public void SetBlur(bool enabled)
{
_blurVisual.IsVisible = enabled;
}
}
}

171
src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs

@ -1,171 +0,0 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Logging;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Windows.UI.Composition;
using Windows.UI.Composition.Interop;
using WinRT;
namespace Avalonia.Win32
{
internal class CompositionConnector
{
private Compositor _compositor;
private Windows.System.DispatcherQueueController _dispatcherQueueController;
private CompositionGraphicsDevice _graphicsDevice;
internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
{
DQTAT_COM_NONE = 0,
DQTAT_COM_ASTA = 1,
DQTAT_COM_STA = 2
};
internal enum DISPATCHERQUEUE_THREAD_TYPE
{
DQTYPE_THREAD_DEDICATED = 1,
DQTYPE_THREAD_CURRENT = 2,
};
[StructLayout(LayoutKind.Sequential)]
internal struct DispatcherQueueOptions
{
public int dwSize;
[MarshalAs(UnmanagedType.I4)]
public DISPATCHERQUEUE_THREAD_TYPE threadType;
[MarshalAs(UnmanagedType.I4)]
public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
};
[DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options, out IntPtr dispatcherQueueController);
public static CompositionConnector TryCreate(EglPlatformOpenGlInterface egl)
{
const int majorRequired = 10;
const int buildRequired = 16299;
var majorInstalled = Win32Platform.WindowsVersion.Major;
var buildInstalled = Win32Platform.WindowsVersion.Build;
if (majorInstalled >= majorRequired &&
buildInstalled >= buildRequired)
{
try
{
return new CompositionConnector(egl);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "WinUIComposition")?.Log(null, "Unable to initialize WinUI compositor: {0}", e);
return null;
}
}
var osVersionNotice = $"Windows {majorRequired} Build {buildRequired} is required. Your machine has Windows {majorInstalled} Build {buildInstalled} installed.";
Logger.TryGet(LogEventLevel.Warning, "WinUIComposition")?.Log(null,
$"Unable to initialize WinUI compositor: {osVersionNotice}");
return null;
}
public CompositionConnector(EglPlatformOpenGlInterface egl)
{
EnsureDispatcherQueue();
if (_dispatcherQueueController != null)
_compositor = new Compositor();
var interop = _compositor.As<ICompositorInterop>();
var display = egl.Display as AngleWin32EglDisplay;
_graphicsDevice = interop.CreateGraphicsDevice(display.GetDirect3DDevice());
}
public ICompositionDrawingSurfaceInterop InitialiseWindowCompositionTree(IntPtr hwnd, out Windows.UI.Composition.Visual surfaceVisual, out IBlurHost blurHost)
{
var target = CreateDesktopWindowTarget(hwnd);
var surface = _graphicsDevice.CreateDrawingSurface(new Windows.Foundation.Size(0, 0),
Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized,
Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
var surfaceInterop = surface.As<ICompositionDrawingSurfaceInterop>();
var brush = _compositor.CreateSurfaceBrush(surface);
var visual = _compositor.CreateSpriteVisual();
visual.Brush = brush;
visual.RelativeSizeAdjustment = new System.Numerics.Vector2(1, 1);
var container = _compositor.CreateContainerVisual();
target.Root = container;
var blur = CreateBlur();
blurHost = new CompositionBlurHost(blur);
container.Children.InsertAtTop(blur);
container.Children.InsertAtTop(visual);
visual.CompositeMode = CompositionCompositeMode.SourceOver;
surfaceVisual = container;
return surfaceInterop;
}
private SpriteVisual CreateBlur()
{
var blurEffect = new GaussianBlurEffect(new CompositionEffectSourceParameter("backdrop"));
var backDropBrush = _compositor.CreateBackdropBrush();
var saturateEffect = new SaturationEffect(blurEffect);
var satEffectFactory = _compositor.CreateEffectFactory(saturateEffect);
var satBrush = satEffectFactory.CreateBrush();
satBrush.SetSourceParameter("backdrop", backDropBrush);
var visual = _compositor.CreateSpriteVisual();
visual.IsVisible = false;
visual.RelativeSizeAdjustment = new System.Numerics.Vector2(1.0f, 1.0f);
visual.Brush = satBrush;
return visual;
}
private CompositionTarget CreateDesktopWindowTarget(IntPtr window)
{
var interop = _compositor.As<global::Windows.UI.Composition.Desktop.ICompositorDesktopInterop>();
interop.CreateDesktopWindowTarget(window, false, out var windowTarget);
return Windows.UI.Composition.Desktop.DesktopWindowTarget.FromAbi(windowTarget);
}
private void EnsureDispatcherQueue()
{
if (_dispatcherQueueController == null)
{
DispatcherQueueOptions options = new DispatcherQueueOptions();
options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_NONE;
options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
CreateDispatcherQueueController(options, out var queue);
_dispatcherQueueController = Windows.System.DispatcherQueueController.FromAbi(queue);
}
}
}
}

96
src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs

@ -1,96 +0,0 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Windows.UI.Composition.Interop;
namespace Avalonia.Win32
{
internal class CompositionEglGlPlatformSurface : EglGlPlatformSurfaceBase
{
private EglPlatformOpenGlInterface _egl;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private ICompositionDrawingSurfaceInterop _surfaceInterop;
private Windows.UI.Composition.Visual _surface;
public CompositionEglGlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) : base()
{
_egl = egl;
_info = info;
}
public IBlurHost AttachToCompositionTree(CompositionConnector connector, IntPtr hwnd)
{
using (_egl.PrimaryContext.MakeCurrent())
{
_surfaceInterop = connector.InitialiseWindowCompositionTree(hwnd, out _surface, out var blurHost);
return blurHost;
}
}
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
return new CompositionRenderTarget(_egl, _surface, _surfaceInterop, _info);
}
class CompositionRenderTarget : EglPlatformSurfaceRenderTargetBase
{
private readonly EglPlatformOpenGlInterface _egl;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _currentSize;
private readonly ICompositionDrawingSurfaceInterop _surfaceInterop;
private static Guid s_Iid = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
private Windows.UI.Composition.Visual _compositionVisual;
public CompositionRenderTarget(EglPlatformOpenGlInterface egl,
Windows.UI.Composition.Visual compositionVisual,
ICompositionDrawingSurfaceInterop interopSurface,
IEglWindowGlPlatformSurfaceInfo info)
: base(egl)
{
_egl = egl;
_surfaceInterop = interopSurface;
_info = info;
_currentSize = info.Size;
_compositionVisual = compositionVisual;
using (_egl.PrimaryContext.MakeCurrent())
{
_surfaceInterop.Resize(new POINT { X = _info.Size.Width, Y = _info.Size.Height });
}
_compositionVisual.Size = new System.Numerics.Vector2(_info.Size.Width, _info.Size.Height);
}
public override IGlPlatformSurfaceRenderingSession BeginDraw()
{
IntPtr texture;
EglSurface surface;
using (_egl.PrimaryEglContext.EnsureCurrent())
{
if (_info.Size != _currentSize)
{
_surfaceInterop.Resize(new POINT { X = _info.Size.Width, Y = _info.Size.Height });
_compositionVisual.Size = new System.Numerics.Vector2(_info.Size.Width, _info.Size.Height);
_currentSize = _info.Size;
}
var offset = new POINT();
_surfaceInterop.BeginDraw(
IntPtr.Zero,
ref s_Iid,
out texture, ref offset);
surface = (_egl.Display as AngleWin32EglDisplay).WrapDirect3D11Texture(_egl, texture, offset.X, offset.Y, _info.Size.Width, _info.Size.Height);
}
return base.BeginDraw(surface, _info, () => { _surfaceInterop.EndDraw(); Marshal.Release(texture); surface.Dispose(); }, true);
}
}
}
}

91
src/Windows/Avalonia.Win32/Composition/D2DEffects.cs

@ -1,91 +0,0 @@
using System;
namespace Avalonia.Win32
{
class D2DEffects
{
public static readonly Guid CLSID_D2D12DAffineTransform = new Guid(0x6AA97485, 0x6354, 0x4CFC, 0x90, 0x8C, 0xE4, 0xA7, 0x4F, 0x62, 0xC9, 0x6C);
public static readonly Guid CLSID_D2D13DPerspectiveTransform = new Guid(0xC2844D0B, 0x3D86, 0x46E7, 0x85, 0xBA, 0x52, 0x6C, 0x92, 0x40, 0xF3, 0xFB);
public static readonly Guid CLSID_D2D13DTransform = new Guid(0xE8467B04, 0xEC61, 0x4B8A, 0xB5, 0xDE, 0xD4, 0xD7, 0x3D, 0xEB, 0xEA, 0x5A);
public static readonly Guid CLSID_D2D1ArithmeticComposite = new Guid(0xFC151437, 0x049A, 0x4784, 0xA2, 0x4A, 0xF1, 0xC4, 0xDA, 0xF2, 0x09, 0x87);
public static readonly Guid CLSID_D2D1Atlas = new Guid(0x913E2BE4, 0xFDCF, 0x4FE2, 0xA5, 0xF0, 0x24, 0x54, 0xF1, 0x4F, 0xF4, 0x08);
public static readonly Guid CLSID_D2D1BitmapSource = new Guid(0x5FB6C24D, 0xC6DD, 0x4231, 0x94, 0x4, 0x50, 0xF4, 0xD5, 0xC3, 0x25, 0x2D);
public static readonly Guid CLSID_D2D1Blend = new Guid(0x81C5B77B, 0x13F8, 0x4CDD, 0xAD, 0x20, 0xC8, 0x90, 0x54, 0x7A, 0xC6, 0x5D);
public static readonly Guid CLSID_D2D1Border = new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27);
public static readonly Guid CLSID_D2D1Brightness = new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87);
public static readonly Guid CLSID_D2D1ColorManagement = new Guid(0x1A28524C, 0xFDD6, 0x4AA4, 0xAE, 0x8F, 0x83, 0x7E, 0xB8, 0x26, 0x7B, 0x37);
public static readonly Guid CLSID_D2D1ColorMatrix = new Guid(0x921F03D6, 0x641C, 0x47DF, 0x85, 0x2D, 0xB4, 0xBB, 0x61, 0x53, 0xAE, 0x11);
public static readonly Guid CLSID_D2D1Composite = new Guid(0x48FC9F51, 0xF6AC, 0x48F1, 0x8B, 0x58, 0x3B, 0x28, 0xAC, 0x46, 0xF7, 0x6D);
public static readonly Guid CLSID_D2D1ConvolveMatrix = new Guid(0x407F8C08, 0x5533, 0x4331, 0xA3, 0x41, 0x23, 0xCC, 0x38, 0x77, 0x84, 0x3E);
public static readonly Guid CLSID_D2D1Crop = new Guid(0xE23F7110, 0x0E9A, 0x4324, 0xAF, 0x47, 0x6A, 0x2C, 0x0C, 0x46, 0xF3, 0x5B);
public static readonly Guid CLSID_D2D1DirectionalBlur = new Guid(0x174319A6, 0x58E9, 0x49B2, 0xBB, 0x63, 0xCA, 0xF2, 0xC8, 0x11, 0xA3, 0xDB);
public static readonly Guid CLSID_D2D1DiscreteTransfer = new Guid(0x90866FCD, 0x488E, 0x454B, 0xAF, 0x06, 0xE5, 0x04, 0x1B, 0x66, 0xC3, 0x6C);
public static readonly Guid CLSID_D2D1DisplacementMap = new Guid(0xEDC48364, 0x417, 0x4111, 0x94, 0x50, 0x43, 0x84, 0x5F, 0xA9, 0xF8, 0x90);
public static readonly Guid CLSID_D2D1DistantDiffuse = new Guid(0x3E7EFD62, 0xA32D, 0x46D4, 0xA8, 0x3C, 0x52, 0x78, 0x88, 0x9A, 0xC9, 0x54);
public static readonly Guid CLSID_D2D1DistantSpecular = new Guid(0x428C1EE5, 0x77B8, 0x4450, 0x8A, 0xB5, 0x72, 0x21, 0x9C, 0x21, 0xAB, 0xDA);
public static readonly Guid CLSID_D2D1DpiCompensation = new Guid(0x6C26C5C7, 0x34E0, 0x46FC, 0x9C, 0xFD, 0xE5, 0x82, 0x37, 0x6, 0xE2, 0x28);
public static readonly Guid CLSID_D2D1Flood = new Guid(0x61C23C20, 0xAE69, 0x4D8E, 0x94, 0xCF, 0x50, 0x07, 0x8D, 0xF6, 0x38, 0xF2);
public static readonly Guid CLSID_D2D1GammaTransfer = new Guid(0x409444C4, 0xC419, 0x41A0, 0xB0, 0xC1, 0x8C, 0xD0, 0xC0, 0xA1, 0x8E, 0x42);
public static readonly Guid CLSID_D2D1GaussianBlur = new Guid(0x1FEB6D69, 0x2FE6, 0x4AC9, 0x8C, 0x58, 0x1D, 0x7F, 0x93, 0xE7, 0xA6, 0xA5);
public static readonly Guid CLSID_D2D1Scale = new Guid(0x9DAF9369, 0x3846, 0x4D0E, 0xA4, 0x4E, 0xC, 0x60, 0x79, 0x34, 0xA5, 0xD7);
public static readonly Guid CLSID_D2D1Histogram = new Guid(0x881DB7D0, 0xF7EE, 0x4D4D, 0xA6, 0xD2, 0x46, 0x97, 0xAC, 0xC6, 0x6E, 0xE8);
public static readonly Guid CLSID_D2D1HueRotation = new Guid(0x0F4458EC, 0x4B32, 0x491B, 0x9E, 0x85, 0xBD, 0x73, 0xF4, 0x4D, 0x3E, 0xB6);
public static readonly Guid CLSID_D2D1LinearTransfer = new Guid(0xAD47C8FD, 0x63EF, 0x4ACC, 0x9B, 0x51, 0x67, 0x97, 0x9C, 0x03, 0x6C, 0x06);
public static readonly Guid CLSID_D2D1LuminanceToAlpha = new Guid(0x41251AB7, 0x0BEB, 0x46F8, 0x9D, 0xA7, 0x59, 0xE9, 0x3F, 0xCC, 0xE5, 0xDE);
public static readonly Guid CLSID_D2D1Morphology = new Guid(0xEAE6C40D, 0x626A, 0x4C2D, 0xBF, 0xCB, 0x39, 0x10, 0x01, 0xAB, 0xE2, 0x02);
public static readonly Guid CLSID_D2D1OpacityMetadata = new Guid(0x6C53006A, 0x4450, 0x4199, 0xAA, 0x5B, 0xAD, 0x16, 0x56, 0xFE, 0xCE, 0x5E);
public static readonly Guid CLSID_D2D1PointDiffuse = new Guid(0xB9E303C3, 0xC08C, 0x4F91, 0x8B, 0x7B, 0x38, 0x65, 0x6B, 0xC4, 0x8C, 0x20);
public static readonly Guid CLSID_D2D1PointSpecular = new Guid(0x09C3CA26, 0x3AE2, 0x4F09, 0x9E, 0xBC, 0xED, 0x38, 0x65, 0xD5, 0x3F, 0x22);
public static readonly Guid CLSID_D2D1Premultiply = new Guid(0x06EAB419, 0xDEED, 0x4018, 0x80, 0xD2, 0x3E, 0x1D, 0x47, 0x1A, 0xDE, 0xB2);
public static readonly Guid CLSID_D2D1Saturation = new Guid(0x5CB2D9CF, 0x327D, 0x459F, 0xA0, 0xCE, 0x40, 0xC0, 0xB2, 0x08, 0x6B, 0xF7);
public static readonly Guid CLSID_D2D1Shadow = new Guid(0xC67EA361, 0x1863, 0x4E69, 0x89, 0xDB, 0x69, 0x5D, 0x3E, 0x9A, 0x5B, 0x6B);
public static readonly Guid CLSID_D2D1SpotDiffuse = new Guid(0x818A1105, 0x7932, 0x44F4, 0xAA, 0x86, 0x08, 0xAE, 0x7B, 0x2F, 0x2C, 0x93);
public static readonly Guid CLSID_D2D1SpotSpecular = new Guid(0xEDAE421E, 0x7654, 0x4A37, 0x9D, 0xB8, 0x71, 0xAC, 0xC1, 0xBE, 0xB3, 0xC1);
public static readonly Guid CLSID_D2D1TableTransfer = new Guid(0x5BF818C3, 0x5E43, 0x48CB, 0xB6, 0x31, 0x86, 0x83, 0x96, 0xD6, 0xA1, 0xD4);
public static readonly Guid CLSID_D2D1Tile = new Guid(0xB0784138, 0x3B76, 0x4BC5, 0xB1, 0x3B, 0x0F, 0xA2, 0xAD, 0x02, 0x65, 0x9F);
public static readonly Guid CLSID_D2D1Turbulence = new Guid(0xCF2BB6AE, 0x889A, 0x4AD7, 0xBA, 0x29, 0xA2, 0xFD, 0x73, 0x2C, 0x9F, 0xC9);
public static readonly Guid CLSID_D2D1UnPremultiply = new Guid(0xFB9AC489, 0xAD8D, 0x41ED, 0x99, 0x99, 0xBB, 0x63, 0x47, 0xD1, 0x10, 0xF7);
}
}

45
src/Windows/Avalonia.Win32/Composition/EffectBase.cs

@ -1,45 +0,0 @@
using System;
using Windows.Graphics.Effects;
using Windows.Graphics.Effects.Interop;
namespace Avalonia.Win32
{
abstract class EffectBase : IGraphicsEffect, IGraphicsEffectSource, global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop
{
private IGraphicsEffectSource[] _sources;
public EffectBase(params IGraphicsEffectSource[] sources)
{
_sources = sources;
}
private IGraphicsEffectSource _source;
public virtual string Name { get; set; }
public abstract Guid EffectId { get; }
public abstract uint PropertyCount { get; }
public uint SourceCount => (uint)_sources.Length;
public IGraphicsEffectSource GetSource(uint index)
{
if(index < _sources.Length)
{
return _sources[index];
}
return null;
}
public uint GetNamedPropertyMapping(string name, out GRAPHICS_EFFECT_PROPERTY_MAPPING mapping)
{
throw new NotImplementedException();
}
public abstract object GetProperty(uint index);
}
}

18
src/Windows/Avalonia.Win32/Composition/GRAPHICS_EFFECT_PROPERTY_MAPPING.cs

@ -1,18 +0,0 @@
namespace Windows.Graphics.Effects.Interop
{
public enum GRAPHICS_EFFECT_PROPERTY_MAPPING
{
GRAPHICS_EFFECT_PROPERTY_MAPPING_UNKNOWN,
GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT,
GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORX,
GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORY,
GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORZ,
GRAPHICS_EFFECT_PROPERTY_MAPPING_VECTORW,
GRAPHICS_EFFECT_PROPERTY_MAPPING_RECT_TO_VECTOR4,
GRAPHICS_EFFECT_PROPERTY_MAPPING_RADIANS_TO_DEGREES,
GRAPHICS_EFFECT_PROPERTY_MAPPING_COLORMATRIX_ALPHA_MODE,
GRAPHICS_EFFECT_PROPERTY_MAPPING_COLOR_TO_VECTOR3,
GRAPHICS_EFFECT_PROPERTY_MAPPING_COLOR_TO_VECTOR4
};
}

57
src/Windows/Avalonia.Win32/Composition/GaussianBlurEffect.cs

@ -1,57 +0,0 @@
using System;
using Windows.Graphics.Effects;
namespace Avalonia.Win32
{
class GaussianBlurEffect : EffectBase
{
public GaussianBlurEffect(IGraphicsEffectSource source) : base(source)
{
}
enum D2D1_GAUSSIANBLUR_OPTIMIZATION
{
D2D1_GAUSSIANBLUR_OPTIMIZATION_SPEED,
D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED,
D2D1_GAUSSIANBLUR_OPTIMIZATION_QUALITY,
D2D1_GAUSSIANBLUR_OPTIMIZATION_FORCE_DWORD
};
enum D2D1_BORDER_MODE
{
D2D1_BORDER_MODE_SOFT,
D2D1_BORDER_MODE_HARD,
D2D1_BORDER_MODE_FORCE_DWORD
};
enum D2D1GaussianBlurProp
{
D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION,
D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION,
D2D1_GAUSSIANBLUR_PROP_BORDER_MODE,
D2D1_GAUSSIANBLUR_PROP_FORCE_DWORD
};
public override Guid EffectId => D2DEffects.CLSID_D2D1GaussianBlur;
public override uint PropertyCount => 3;
public override object GetProperty(uint index)
{
switch ((D2D1GaussianBlurProp)index)
{
case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION:
return 30.0f;
case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION:
return (uint)D2D1_GAUSSIANBLUR_OPTIMIZATION.D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED;
case D2D1GaussianBlurProp.D2D1_GAUSSIANBLUR_PROP_BORDER_MODE:
return (uint)D2D1_BORDER_MODE.D2D1_BORDER_MODE_HARD;
}
return null;
}
}
}

8
src/Windows/Avalonia.Win32/Composition/IBlurHost.cs

@ -1,8 +0,0 @@
namespace Avalonia.Win32
{
internal interface IBlurHost
{
void SetBlur(bool enabled);
}
}

152
src/Windows/Avalonia.Win32/Composition/ICompositionDrawingSurfaceInterop.cs

@ -1,152 +0,0 @@
using System;
using System.Runtime.InteropServices;
using WinRT;
namespace Windows.UI.Composition.Interop
{
public struct POINT
{
public int X;
public int Y;
}
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
public int Width => right - left;
public int Height => bottom - top;
}
[WindowsRuntimeType]
[Guid("FD04E6E3-FE0C-4C3C-AB19-A07601A576EE")]
public interface ICompositionDrawingSurfaceInterop
{
void BeginDraw(IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT point);
void EndDraw();
void Resize(POINT sizePixels);
void ResumeDraw();
void Scroll(RECT scrollRect, RECT clipRect, int offsetX, int offsetY);
void SuspendDraw();
}
}
namespace ABI.Windows.UI.Composition.Interop
{
using global::System;
using global::System.Runtime.InteropServices;
using global::Windows.UI.Composition;
using global::Windows.UI.Composition.Interop;
[Guid("FD04E6E3-FE0C-4C3C-AB19-A07601A576EE")]
internal class ICompositionDrawingSurfaceInterop : global::Windows.UI.Composition.Interop.ICompositionDrawingSurfaceInterop
{
[Guid("FD04E6E3-FE0C-4C3C-AB19-A07601A576EE")]
public unsafe struct Vftbl
{
public delegate int _BeginDraw(IntPtr ThisPtr, IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT updateOffset);
public delegate int _EndDraw(IntPtr ThisPtr);
public delegate int _Resize(IntPtr ThisPtr, POINT sizePixels);
public delegate int _ResumeDraw(IntPtr ThisPtr);
public delegate int _Scroll(IntPtr ThisPtr, RECT scrollRect, RECT clipRect, int offsetX, int offsetY);
public delegate int _SuspendDraw(IntPtr ThisPtr);
internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
public _BeginDraw BeginDraw;
public _EndDraw EndDraw;
public _Resize Resize;
public _ResumeDraw ResumeDraw;
public _Scroll Scroll;
public _SuspendDraw SuspendDraw;
public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
BeginDraw = Do_Abi_BeginDraw,
EndDraw = Do_Abi_EndDraw,
Resize = Do_Abi_Resize
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}
private static int Do_Abi_BeginDraw(IntPtr ThisPtr, IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT updateOffset)
{
updateObject = IntPtr.Zero;
return 0;
}
private static int Do_Abi_EndDraw(IntPtr ThisPtr)
{
return 0;
}
private static int Do_Abi_Resize(IntPtr ThisPtr, POINT sizePixels)
{
return 0;
}
}
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
public static implicit operator ICompositionDrawingSurfaceInterop(IObjectReference obj) => (obj != null) ? new ICompositionDrawingSurfaceInterop(obj) : null;
protected readonly ObjectReference<Vftbl> _obj;
public IObjectReference ObjRef { get => _obj; }
public IntPtr ThisPtr => _obj.ThisPtr;
public ObjectReference<I> AsInterface<I>() => _obj.As<I>();
public A As<A>() => _obj.AsType<A>();
public ICompositionDrawingSurfaceInterop(IObjectReference obj) : this(obj.As<Vftbl>()) { }
internal ICompositionDrawingSurfaceInterop(ObjectReference<Vftbl> obj)
{
_obj = obj;
}
public void BeginDraw(IntPtr updateRect, ref Guid iid, out IntPtr updateObject, ref POINT point)
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.BeginDraw(ThisPtr, updateRect, ref iid, out updateObject, ref point));
}
public void EndDraw()
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.EndDraw(ThisPtr));
}
public void Resize(POINT sizePixels)
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.Resize(ThisPtr, sizePixels));
}
public void ResumeDraw()
{
throw new NotImplementedException();
}
public void Scroll(RECT scrollRect, RECT clipRect, int offsetX, int offsetY)
{
throw new NotImplementedException();
}
public void SuspendDraw()
{
throw new NotImplementedException();
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save