Browse Source

Merge branch 'master' into feature/label-control

pull/4904/head
Jumar Macato 5 years ago
committed by GitHub
parent
commit
2fb35bdffe
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      native/Avalonia.Native/src/OSX/window.mm
  2. 2
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  3. 3
      samples/ControlCatalog.NetCore/Program.cs
  4. 2
      samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
  5. 2
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  6. 8
      src/Avalonia.Controls/ApiCompatBaseline.txt
  7. 20
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  8. 54
      src/Avalonia.Controls/SplitView.cs
  9. 23
      src/Avalonia.Controls/TextBlock.cs
  10. 1
      src/Avalonia.Dialogs/ApiCompatBaseline.txt
  11. 10
      src/Avalonia.OpenGL/Angle/AngleEglInterface.cs
  12. 9
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  13. 6
      src/Avalonia.OpenGL/Egl/EglConsts.cs
  14. 8
      src/Avalonia.Themes.Default/SplitView.xaml
  15. 8
      src/Avalonia.Themes.Fluent/SplitView.xaml
  16. 4
      src/Avalonia.Visuals/Rendering/RenderLayer.cs
  17. 8
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  18. 2
      src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
  19. 2
      src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs
  20. 4
      src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs
  21. 9
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
  22. 4
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs
  23. 3
      src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
  24. 6
      src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
  25. 3
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  26. 18
      src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs
  27. 143
      src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs
  28. 96
      src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs
  29. 91
      src/Windows/Avalonia.Win32/Composition/D2DEffects.cs
  30. 45
      src/Windows/Avalonia.Win32/Composition/EffectBase.cs
  31. 18
      src/Windows/Avalonia.Win32/Composition/GRAPHICS_EFFECT_PROPERTY_MAPPING.cs
  32. 57
      src/Windows/Avalonia.Win32/Composition/GaussianBlurEffect.cs
  33. 8
      src/Windows/Avalonia.Win32/Composition/IBlurHost.cs
  34. 152
      src/Windows/Avalonia.Win32/Composition/ICompositionDrawingSurfaceInterop.cs
  35. 14
      src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop.cs
  36. 69
      src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop1.cs
  37. 139
      src/Windows/Avalonia.Win32/Composition/ICompositorInterop.cs
  38. 24
      src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop.cs
  39. 217
      src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop1.cs
  40. 35
      src/Windows/Avalonia.Win32/Composition/SaturationEffect.cs
  41. 1
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  42. 18
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  43. 12
      src/Windows/Avalonia.Win32/Win32Platform.cs
  44. 119
      src/Windows/Avalonia.Win32/WindowImpl.cs
  45. 3
      src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj
  46. 54
      tests/Avalonia.RenderTests/Controls/TextBlockTests.cs
  47. BIN
      tests/TestFiles/Direct2D1/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png
  48. BIN
      tests/TestFiles/Skia/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png

6
native/Avalonia.Native/src/OSX/window.mm

@ -1338,6 +1338,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
_parent->BaseEvents->RunRenderPriorityJobs();
if (_parent == nullptr)
{
return;
}
_parent->BaseEvents->Paint();
}

2
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -12,7 +12,7 @@
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
</ItemGroup>

3
samples/ControlCatalog.NetCore/Program.cs

@ -7,12 +7,11 @@ using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Dialogs;
using Avalonia.Headless;
using Avalonia.LogicalTree;
using Avalonia.Skia;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using Avalonia.Dialogs;
namespace ControlCatalog.NetCore
{

2
samples/interop/NativeEmbedSample/NativeEmbedSample.csproj

@ -12,7 +12,7 @@
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>

2
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -438,7 +438,7 @@ namespace Avalonia.Controls
_lastMousePositionHeaders = mousePositionHeaders;
if (args.Pointer.Captured != this)
if (args.Pointer.Captured != this && _dragMode == DragMode.Drag)
args.Pointer.Capture(this);
SetDragCursor(mousePosition);

8
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -8,6 +8,12 @@ MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(A
TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.ContentProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.PaneProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Content.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Content.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Pane.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Pane.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract.
@ -17,4 +23,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalo
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
Total Issues: 18
Total Issues: 24

20
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -4,6 +4,7 @@ using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Threading;
using Avalonia.VisualTree;
using Avalonia.Layout;
namespace Avalonia.Controls.Presenters
{
@ -312,7 +313,24 @@ namespace Avalonia.Controls.Presenters
context.FillRectangle(background, new Rect(Bounds.Size));
}
context.DrawText(Foreground, new Point(), FormattedText);
double top = 0;
var textSize = FormattedText.Bounds.Size;
if (Bounds.Height < textSize.Height)
{
switch (VerticalAlignment)
{
case VerticalAlignment.Center:
top += (Bounds.Height - textSize.Height) / 2;
break;
case VerticalAlignment.Bottom:
top += (Bounds.Height - textSize.Height);
break;
}
}
context.DrawText(Foreground, new Point(0, top), FormattedText);
}
public override void Render(DrawingContext context)

54
src/Avalonia.Controls/SplitView.cs

@ -9,6 +9,8 @@ using Avalonia.Platform;
using Avalonia.VisualTree;
using System;
using System.Reactive.Disposables;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
namespace Avalonia.Controls
{
@ -78,7 +80,7 @@ namespace Avalonia.Controls
[PseudoClasses(":compactoverlay", ":compactinline", ":overlay", ":inline")]
[PseudoClasses(":left", ":right")]
[PseudoClasses(":lightdismiss")]
public class SplitView : TemplatedControl
public class SplitView : ContentControl
{
/*
Pseudo classes & combos
@ -87,12 +89,6 @@ namespace Avalonia.Controls
:left :right
*/
/// <summary>
/// Defines the <see cref="Content"/> property
/// </summary>
public static readonly StyledProperty<IControl> ContentProperty =
AvaloniaProperty.Register<SplitView, IControl>(nameof(Content));
/// <summary>
/// Defines the <see cref="CompactPaneLength"/> property
/// </summary>
@ -133,8 +129,14 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Pane"/> property
/// </summary>
public static readonly StyledProperty<IControl> PaneProperty =
AvaloniaProperty.Register<SplitView, IControl>(nameof(Pane));
public static readonly StyledProperty<object?> PaneProperty =
AvaloniaProperty.Register<SplitView, object?>(nameof(Pane));
/// <summary>
/// Defines the <see cref="HeaderTemplate"/> property.
/// </summary>
public static readonly StyledProperty<IDataTemplate?> PaneTemplateProperty =
AvaloniaProperty.Register<HeaderedContentControl, IDataTemplate?>(nameof(PaneTemplate));
/// <summary>
/// Defines the <see cref="UseLightDismissOverlayMode"/> property
@ -166,16 +168,7 @@ namespace Avalonia.Controls
CompactPaneLengthProperty.Changed.AddClassHandler<SplitView>((x, v) => x.OnCompactPaneLengthChanged(v));
PanePlacementProperty.Changed.AddClassHandler<SplitView>((x, v) => x.OnPanePlacementChanged(v));
DisplayModeProperty.Changed.AddClassHandler<SplitView>((x, v) => x.OnDisplayModeChanged(v));
}
/// <summary>
/// Gets or sets the content of the SplitView
/// </summary>
[Content]
public IControl Content
{
get => GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
/// <summary>
@ -265,11 +258,20 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the Pane for the SplitView
/// </summary>
public IControl Pane
public object Pane
{
get => GetValue(PaneProperty);
set => SetValue(PaneProperty, value);
}
/// <summary>
/// Gets or sets the data template used to display the header content of the control.
/// </summary>
public IDataTemplate? PaneTemplate
{
get => GetValue(PaneTemplateProperty);
set => SetValue(PaneTemplateProperty, value);
}
/// <summary>
/// Gets or sets whether WinUI equivalent LightDismissOverlayMode is enabled
@ -312,6 +314,18 @@ namespace Avalonia.Controls
/// </summary>
public event EventHandler<EventArgs> PaneOpening;
protected override bool RegisterContentPresenter(IContentPresenter presenter)
{
var result = base.RegisterContentPresenter(presenter);
if (presenter.Name == "PART_PanePresenter")
{
return true;
}
return result;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);

23
src/Avalonia.Controls/TextBlock.cs

@ -3,6 +3,7 @@ using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Metadata;
using Avalonia.Layout;
namespace Avalonia.Controls
{
@ -427,14 +428,32 @@ namespace Avalonia.Controls
case TextAlignment.Center:
offsetX = (width - TextLayout.Size.Width) / 2;
break;
case TextAlignment.Right:
offsetX = width - TextLayout.Size.Width;
offsetX = width - TextLayout.Size.Width;
break;
}
var padding = Padding;
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top)))
var top = padding.Top;
var textSize = TextLayout.Size;
if (Bounds.Height < textSize.Height)
{
switch (VerticalAlignment)
{
case VerticalAlignment.Center:
top += (Bounds.Height - textSize.Height) / 2;
break;
case VerticalAlignment.Bottom:
top += (Bounds.Height - textSize.Height);
break;
}
}
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, top)))
{
TextLayout.Draw(context);
}

1
src/Avalonia.Dialogs/ApiCompatBaseline.txt

@ -0,0 +1 @@
Total Issues: 0

10
src/Avalonia.OpenGL/Angle/AngleEglInterface.cs

@ -1,15 +1,13 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL.Angle
{
public class AngleEglInterface : EglInterface
{
[DllImport("libegl.dll", CharSet = CharSet.Ansi)]
static extern IntPtr eglGetProcAddress(string proc);
[DllImport("av_libGLESv2.dll", CharSet = CharSet.Ansi)]
static extern IntPtr EGL_GetProcAddress(string proc);
public AngleEglInterface() : base(LoadAngle())
{
@ -20,14 +18,14 @@ namespace Avalonia.OpenGL.Angle
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var disp = eglGetProcAddress("eglGetPlatformDisplayEXT");
var disp = EGL_GetProcAddress("eglGetPlatformDisplayEXT");
if (disp == IntPtr.Zero)
{
throw new OpenGlException("libegl.dll doesn't have eglGetPlatformDisplayEXT entry point");
}
return eglGetProcAddress;
return EGL_GetProcAddress;
}
throw new PlatformNotSupportedException();

9
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

@ -82,7 +82,14 @@ namespace Avalonia.OpenGL.Angle
{
if (PlatformApi != AngleOptions.PlatformApi.DirectX11)
throw new InvalidOperationException("Current platform API is " + PlatformApi);
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
}
public EglSurface WrapDirect3D11Texture(EglPlatformOpenGlInterface egl, IntPtr handle, int offsetX, int offsetY, int width, int height)
{
if (PlatformApi != AngleOptions.PlatformApi.DirectX11)
throw new InvalidOperationException("Current platform API is " + PlatformApi);
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_TRUE, EGL_TEXTURE_OFFSET_X_ANGLE, offsetX, EGL_TEXTURE_OFFSET_Y_ANGLE, offsetY, EGL_NONE });
}
}
}

6
src/Avalonia.OpenGL/Egl/EglConsts.cs

@ -205,5 +205,11 @@ namespace Avalonia.OpenGL.Egl
public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
public const int EGL_D3D_TEXTURE_ANGLE = 0x33A3;
public const int EGL_TEXTURE_OFFSET_X_ANGLE = 0x3490;
public const int EGL_TEXTURE_OFFSET_Y_ANGLE = 0x3491;
public const int EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE = 0x33A6;
}
}

8
src/Avalonia.Themes.Default/SplitView.xaml

@ -32,12 +32,12 @@
ClipToBounds="True"
HorizontalAlignment="Left"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}" />
<Rectangle Name="HCPaneBorder" Fill="{DynamicResource SystemControlForegroundTransparentBrush}" Width="1" HorizontalAlignment="Right" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>
@ -106,14 +106,14 @@
ClipToBounds="True"
HorizontalAlignment="Right"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}"/>
<Rectangle Name="HCPaneBorder"
Fill="{DynamicResource SystemControlForegroundTransparentBrush}"
Width="1" HorizontalAlignment="Left" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>

8
src/Avalonia.Themes.Fluent/SplitView.xaml

@ -32,12 +32,12 @@
ClipToBounds="True"
HorizontalAlignment="Left"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}" />
<Rectangle Name="HCPaneBorder" Fill="{DynamicResource SystemControlForegroundTransparentBrush}" Width="1" HorizontalAlignment="Right" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>
@ -106,14 +106,14 @@
ClipToBounds="True"
HorizontalAlignment="Right"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}"/>
<Rectangle Name="HCPaneBorder"
Fill="{DynamicResource SystemControlForegroundTransparentBrush}"
Width="1" HorizontalAlignment="Left" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>

4
src/Avalonia.Visuals/Rendering/RenderLayer.cs

@ -30,12 +30,12 @@ namespace Avalonia.Rendering
{
if (Size != size || Scaling != scaling)
{
Bitmap.Dispose();
var resized = RefCountable.Create(drawingContext.CreateLayer(size));
using (var context = resized.Item.CreateDrawingContext(null))
{
context.Clear(Colors.Transparent);
Bitmap.Dispose();
context.Clear(default);
Bitmap = resized;
Scaling = scaling;

8
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -36,6 +36,7 @@ namespace Avalonia.Skia
private readonly SKPaint _fillPaint = new SKPaint();
private readonly SKPaint _boxShadowPaint = new SKPaint();
private static SKShader s_acrylicNoiseShader;
private readonly ISkiaGpuRenderSession _session;
/// <summary>
/// Context create info.
@ -76,6 +77,8 @@ namespace Avalonia.Skia
/// Skia GPU provider context (optional)
/// </summary>
public ISkiaGpu Gpu;
public ISkiaGpuRenderSession CurrentSession;
}
/// <summary>
@ -96,6 +99,8 @@ namespace Avalonia.Skia
Surface = createInfo.Surface;
Canvas = createInfo.Canvas ?? createInfo.Surface?.Canvas;
_session = createInfo.CurrentSession;
if (Canvas == null)
{
throw new ArgumentException("Invalid create info - no Canvas provided", nameof(createInfo));
@ -969,7 +974,8 @@ namespace Avalonia.Skia
Format = format,
DisableTextLcdRendering = !_canTextUseLcdRendering,
GrContext = _grContext,
Gpu = _gpu
Gpu = _gpu,
Session = _session
};
return new SurfaceRenderTarget(createInfo);

2
src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs

@ -21,7 +21,7 @@ namespace Avalonia.Skia
/// Creates an offscreen render target surface
/// </summary>
/// <param name="size">size in pixels</param>
ISkiaSurface TryCreateSurface(PixelSize size);
ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session);
}
public interface ISkiaSurface : IDisposable

2
src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs

@ -22,5 +22,7 @@ namespace Avalonia.Skia
/// Scaling factor.
/// </summary>
double ScaleFactor { get; }
GRSurfaceOrigin SurfaceOrigin { get; }
}
}

4
src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs

@ -14,7 +14,7 @@ namespace Avalonia.Skia
private int _texture;
private static readonly bool[] TrueFalse = new[] { true, false };
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize)
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize, GRSurfaceOrigin surfaceOrigin)
{
_grContext = grContext;
_glContext = glContext;
@ -93,7 +93,7 @@ namespace Avalonia.Skia
var target = new GRBackendRenderTarget(pixelSize.Width, pixelSize.Height, 0, 8,
new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat()));
Surface = SKSurface.Create(_grContext, target,
GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888);
surfaceOrigin, SKColorType.Rgba8888);
CanBlit = gl.BlitFramebuffer != null;
}

9
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs

@ -39,6 +39,8 @@ namespace Avalonia.Skia
_backendRenderTarget = backendRenderTarget;
_surface = surface;
_glSession = glSession;
SurfaceOrigin = glSession.IsYFlipped ? GRSurfaceOrigin.TopLeft : GRSurfaceOrigin.BottomLeft;
}
public void Dispose()
{
@ -48,6 +50,8 @@ namespace Avalonia.Skia
GrContext.Flush();
_glSession.Dispose();
}
public GRSurfaceOrigin SurfaceOrigin { get; }
public GRContext GrContext { get; }
public SKSurface SkSurface => _surface;
@ -73,10 +77,6 @@ namespace Avalonia.Skia
$"Can't create drawing context for surface with {size} size and {scaling} scaling");
}
gl.Viewport(0, 0, size.Width, size.Height);
gl.ClearStencil(0);
gl.ClearColor(0, 0, 0, 0);
gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
lock (_grContext)
{
_grContext.ResetContext();
@ -89,6 +89,7 @@ namespace Avalonia.Skia
SKColorType.Rgba8888);
success = true;
return new GlGpuSession(_grContext, renderTarget, surface, glSession);
}
}

4
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@ -47,7 +47,7 @@ namespace Avalonia.Skia
return null;
}
public ISkiaSurface TryCreateSurface(PixelSize size)
public ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session)
{
// Only windows platform needs our FBO trickery
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@ -62,7 +62,7 @@ namespace Avalonia.Skia
return null;
try
{
var surface = new FboSkiaSurface(_grContext, _glContext, size);
var surface = new FboSkiaSurface(_grContext, _glContext, size, session?.SurfaceOrigin ?? GRSurfaceOrigin.TopLeft);
_canCreateSurfaces = true;
return surface;
}

3
src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs

@ -33,7 +33,8 @@ namespace Avalonia.Skia
Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor,
VisualBrushRenderer = visualBrushRenderer,
DisableTextLcdRendering = true,
Gpu = _skiaGpu
Gpu = _skiaGpu,
CurrentSession = session
};
return new DrawingContextImpl(nfo, session);

6
src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs

@ -51,7 +51,7 @@ namespace Avalonia.Skia
_grContext = createInfo.GrContext;
_gpu = createInfo.Gpu;
_surface = _gpu?.TryCreateSurface(PixelSize);
_surface = _gpu?.TryCreateSurface(PixelSize, createInfo.Session);
if (_surface == null)
_surface = new SkiaSurfaceWrapper(CreateSurface(createInfo.GrContext, PixelSize.Width, PixelSize.Height,
createInfo.Format));
@ -100,7 +100,7 @@ namespace Avalonia.Skia
VisualBrushRenderer = visualBrushRenderer,
DisableTextLcdRendering = _disableLcdRendering,
GrContext = _grContext,
Gpu = _gpu
Gpu = _gpu,
};
return new DrawingContextImpl(createInfo, Disposable.Create(() => Version++));
@ -218,6 +218,8 @@ namespace Avalonia.Skia
public GRContext GrContext;
public ISkiaGpu Gpu;
public ISkiaGpuRenderSession Session;
}
}
}

3
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -6,7 +6,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<PackageReference Include="Microsoft.Windows.SDK.NET" Version="10.0.18362.3-preview" />
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
</Project>

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

@ -0,0 +1,18 @@
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;
}
}
}

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

@ -0,0 +1,143 @@
using System;
using System.Runtime.InteropServices;
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 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 blurEffectFactory = _compositor.CreateEffectFactory(blurEffect);
var blurBrush = blurEffectFactory.CreateBrush();
var backDropBrush = _compositor.CreateBackdropBrush();
blurBrush.SetSourceParameter("backdrop", backDropBrush);
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

@ -0,0 +1,96 @@
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

@ -0,0 +1,91 @@
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

@ -0,0 +1,45 @@
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

@ -0,0 +1,18 @@
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

@ -0,0 +1,57 @@
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

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

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

@ -0,0 +1,152 @@
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();
}
}
}

14
src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop.cs

@ -0,0 +1,14 @@
using System;
using System.Runtime.InteropServices;
using WinRT;
namespace Windows.UI.Composition.Desktop
{
[WindowsRuntimeType]
[Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
public interface ICompositorDesktopInterop
{
void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
}
}

69
src/Windows/Avalonia.Win32/Composition/ICompositorDesktopInterop1.cs

@ -0,0 +1,69 @@
using WinRT;
namespace ABI.Windows.UI.Composition.Desktop
{
using global::System;
using global::System.Runtime.InteropServices;
[Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
internal class ICompositorDesktopInterop : global::Windows.UI.Composition.Desktop.ICompositorDesktopInterop
{
[Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
public struct Vftbl
{
public delegate int _CreateDesktopWindowTarget(IntPtr thisPtr, IntPtr hwndTarget, byte isTopMost, out IntPtr desktopWindowTarget);
internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
public _CreateDesktopWindowTarget CreateDesktopWindowTarget;
public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
CreateDesktopWindowTarget = Do_Abi_Create_Desktop_Window_Target
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}
private static int Do_Abi_Create_Desktop_Window_Target(IntPtr thisPtr, IntPtr hwndTarget, byte isTopMost, out IntPtr desktopWindowTarget)
{
try
{
ComWrappersSupport.FindObject<global::Windows.UI.Composition.Desktop.ICompositorDesktopInterop>(thisPtr).CreateDesktopWindowTarget(hwndTarget, isTopMost != 0, out desktopWindowTarget);
return 0;
}
catch (Exception ex)
{
desktopWindowTarget = IntPtr.Zero;
return Marshal.GetHRForException(ex);
}
}
}
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
public static implicit operator ICompositorDesktopInterop(IObjectReference obj) => (obj != null) ? new ICompositorDesktopInterop(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 ICompositorDesktopInterop(IObjectReference obj) : this(obj.As<Vftbl>()) { }
internal ICompositorDesktopInterop(ObjectReference<Vftbl> obj)
{
_obj = obj;
}
public void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test)
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateDesktopWindowTarget(ThisPtr, hwndTarget, isTopmost ? (byte)1 : (byte)0, out test));
}
}
}

139
src/Windows/Avalonia.Win32/Composition/ICompositorInterop.cs

@ -0,0 +1,139 @@
using System;
using System.Runtime.InteropServices;
using WinRT;
namespace Windows.UI.Composition.Interop
{
[WindowsRuntimeType]
[Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")]
public interface ICompositorInterop
{
ICompositionSurface CreateCompositionSurfaceForHandle(IntPtr swapChain);
ICompositionSurface CreateCompositionSurfaceForSwapChain(IntPtr swapChain);
CompositionGraphicsDevice CreateGraphicsDevice(IntPtr renderingDevice);
}
}
namespace ABI.Windows.UI.Composition.Interop
{
using global::System;
using global::System.Runtime.InteropServices;
using global::Windows.UI.Composition;
[Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")]
internal class ICompositorInterop : global::Windows.UI.Composition.Interop.ICompositorInterop
{
[Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")]
public struct Vftbl
{
public delegate int _CreateCompositionSurfaceForHandle(IntPtr ThisPtr, IntPtr swapChain, out IntPtr result);
public delegate int _CreateCompositionSurfaceForSwapChain(IntPtr ThisPtr, IntPtr swapChain, out IntPtr result);
public delegate int _CreateGraphicsDevice(IntPtr ThisPtr, IntPtr renderingDevice, out IntPtr result);
internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
public _CreateCompositionSurfaceForHandle CreateCompositionSurfaceForHandle;
public _CreateCompositionSurfaceForSwapChain CreateCompositionSurfaceForSwapChain;
public _CreateGraphicsDevice CreateGraphicsDevice;
public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
CreateCompositionSurfaceForHandle = Do_Abi_Create_Composition_Surface_For_Handle,
CreateCompositionSurfaceForSwapChain = Do_Abi_Create_Composition_Surface_For_SwapChain,
CreateGraphicsDevice= Do_Abi_Create_Graphics_Device
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}
private static int Do_Abi_Create_Composition_Surface_For_Handle(IntPtr thisPtr, IntPtr swapChain, out IntPtr surface)
{
try
{
surface = IntPtr.Zero;
//surface = ComWrappersSupport.FindObject<global::Windows.UI.Composition.Interop.ICompositorInterop>(thisPtr).CreateCompositionSurfaceForHandle(swapChain);
return 0;
}
catch (Exception ex)
{
surface = IntPtr.Zero;
return Marshal.GetHRForException(ex);
}
}
private static int Do_Abi_Create_Composition_Surface_For_SwapChain(IntPtr thisPtr, IntPtr swapChain, out IntPtr surface)
{
try
{
surface = IntPtr.Zero;
//surface = ComWrappersSupport.FindObject<global::Windows.UI.Composition.Interop.ICompositorInterop>(thisPtr).CreateCompositionSurfaceForSwapChain(swapChain);
return 0;
}
catch (Exception ex)
{
surface = IntPtr.Zero;
return Marshal.GetHRForException(ex);
}
}
private static int Do_Abi_Create_Graphics_Device(IntPtr thisPtr, IntPtr renderingDevice, out IntPtr graphicsDevice)
{
try
{
graphicsDevice = ComWrappersSupport.FindObject<global::Windows.UI.Composition.Interop.ICompositorInterop>(thisPtr).CreateGraphicsDevice(renderingDevice).ThisPtr;
return 0;
}
catch (Exception ex)
{
graphicsDevice = IntPtr.Zero;
return Marshal.GetHRForException(ex);
}
}
}
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
public static implicit operator ICompositorInterop(IObjectReference obj) => (obj != null) ? new ICompositorInterop(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 ICompositorInterop(IObjectReference obj) : this(obj.As<Vftbl>()) { }
internal ICompositorInterop(ObjectReference<Vftbl> obj)
{
_obj = obj;
}
public ICompositionSurface CreateCompositionSurfaceForHandle(IntPtr swapChain)
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateCompositionSurfaceForHandle(ThisPtr, swapChain, out var compositionSurface));
return null;
}
public ICompositionSurface CreateCompositionSurfaceForSwapChain(IntPtr swapChain)
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateCompositionSurfaceForSwapChain(ThisPtr, swapChain, out var compositionSurface));
return null;
}
public CompositionGraphicsDevice CreateGraphicsDevice(IntPtr renderingDevice)
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.CreateGraphicsDevice(ThisPtr, renderingDevice, out var graphicsDevice));
return CompositionGraphicsDevice.FromAbi(graphicsDevice);
}
}
}

24
src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop.cs

@ -0,0 +1,24 @@
using System;
using System.Runtime.InteropServices;
using WinRT;
namespace Windows.Graphics.Effects.Interop
{
[WindowsRuntimeType]
[Guid("2FC57384-A068-44D7-A331-30982FCF7177")]
public interface IGraphicsEffectD2D1Interop
{
Guid EffectId { get; }
uint GetNamedPropertyMapping(string name, out GRAPHICS_EFFECT_PROPERTY_MAPPING mapping);
object GetProperty(uint index);
uint PropertyCount { get; }
IGraphicsEffectSource GetSource(uint index);
uint SourceCount { get; }
}
}

217
src/Windows/Avalonia.Win32/Composition/IGraphicsEffectD2D1Interop1.cs

@ -0,0 +1,217 @@
using WinRT;
namespace ABI.Windows.Graphics.Effects.Interop
{
using global::System;
using global::System.Runtime.InteropServices;
[Guid("2FC57384-A068-44D7-A331-30982FCF7177")]
internal class IGraphicsEffectD2D1Interop : global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop
{
[Guid("2FC57384-A068-44D7-A331-30982FCF7177")]
public struct Vftbl
{
public delegate int _GetEffectId(IntPtr thisPtr, out Guid guid);
public delegate int _GetNamedPropertyMapping(IntPtr thisPtr, IntPtr name, IntPtr index, IntPtr mapping);
public delegate int _GetProperty(IntPtr thisPtr, uint index, out IntPtr value);
public unsafe delegate int _GetPropertyCount(IntPtr thisPtr, uint* count);
public delegate int _GetSource(IntPtr thisPtr, uint index, out IntPtr source);
public delegate int _GetSourceCount(IntPtr thisPtr, out uint count);
internal global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
public _GetEffectId GetEffectId;
public _GetNamedPropertyMapping GetNamedPropertyMapping;
public _GetPropertyCount GetPropertyCount;
public _GetProperty GetProperty;
public _GetSource GetSource;
public _GetSourceCount GetSourceCount;
public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
unsafe static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
GetEffectId = Do_Abi_Get_Effect_Id,
GetNamedPropertyMapping = Do_Abi_Get_Property_Mapping,
GetPropertyCount = Do_Abi_Get_Property_Count,
GetProperty = Do_Abi_Get_Property,
GetSource = Do_Abi_Get_Source,
GetSourceCount = Do_Abi_Get_Source_Count
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}
private static int Do_Abi_Get_Effect_Id(IntPtr thisPtr, out Guid guid)
{
guid = default;
try
{
guid = ComWrappersSupport.FindObject<global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop>(thisPtr).EffectId;
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
private static int Do_Abi_Get_Property_Mapping(IntPtr thisPtr, IntPtr name, IntPtr index, IntPtr mapping)
{
try
{
ComWrappersSupport.FindObject<global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop>(thisPtr).GetNamedPropertyMapping(MarshalString.FromAbi(name), out var mappingResult);
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
private static int Do_Abi_Get_Property(IntPtr thisPtr, uint index, out IntPtr value)
{
value = default;
try
{
value = MarshalInspectable.CreateMarshaler(
ComWrappersSupport.FindObject<global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop>(thisPtr).GetProperty(index))
.As(Guid.Parse("4BD682DD-7554-40E9-9A9B-82654EDE7E62"))
.GetRef();
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
unsafe private static int Do_Abi_Get_Property_Count(IntPtr thisPtr, uint* count)
{
try
{
var res = ComWrappersSupport.FindObject<global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop>(thisPtr).PropertyCount;
if (count != null)
{
*count = res;
}
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
private static int Do_Abi_Get_Source(IntPtr thisPtr, uint index, out IntPtr value)
{
value = default;
try
{
var source = ComWrappersSupport.FindObject<global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop>(thisPtr).GetSource(index);
value = MarshalInterface<global::Windows.Graphics.Effects.IGraphicsEffectSource>.FromManaged(source);
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
private static int Do_Abi_Get_Source_Count(IntPtr thisPtr, out uint count)
{
count = default;
try
{
count = ComWrappersSupport.FindObject<global::Windows.Graphics.Effects.Interop.IGraphicsEffectD2D1Interop>(thisPtr).SourceCount;
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
}
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
public static implicit operator IGraphicsEffectD2D1Interop(IObjectReference obj) => (obj != null) ? new IGraphicsEffectD2D1Interop(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 IGraphicsEffectD2D1Interop(IObjectReference obj) : this(obj.As<Vftbl>()) { }
internal IGraphicsEffectD2D1Interop(ObjectReference<Vftbl> obj)
{
_obj = obj;
}
public Guid EffectId
{
get
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.GetEffectId(ThisPtr, out Guid guid));
return guid;
}
}
public uint PropertyCount
{
get
{
unsafe
{
uint count = default;
Marshal.ThrowExceptionForHR(_obj.Vftbl.GetPropertyCount(ThisPtr, &count));
return count;
}
}
}
public uint SourceCount
{
get
{
Marshal.ThrowExceptionForHR(_obj.Vftbl.GetSourceCount(ThisPtr, out uint count));
return count;
}
}
public uint GetNamedPropertyMapping(string name, out global::Windows.Graphics.Effects.Interop.GRAPHICS_EFFECT_PROPERTY_MAPPING mapping)
{
throw new NotImplementedException();
}
public object GetProperty(uint index)
{
// Marshal.ThrowExceptionForHR(_obj.Vftbl.GetProperty(ThisPtr, index, out IntPtr value));
throw new NotImplementedException();
}
public global::Windows.Graphics.Effects.IGraphicsEffectSource GetSource(uint index)
{
throw new NotImplementedException();
}
}
}

35
src/Windows/Avalonia.Win32/Composition/SaturationEffect.cs

@ -0,0 +1,35 @@
using System;
using Windows.Graphics.Effects;
namespace Avalonia.Win32
{
class SaturationEffect : EffectBase
{
public SaturationEffect(IGraphicsEffect source) : base(source)
{
}
enum D2D1_SATURATION_PROP
{
D2D1_SATURATION_PROP_SATURATION,
D2D1_SATURATION_PROP_FORCE_DWORD
};
public override Guid EffectId => D2DEffects.CLSID_D2D1Saturation;
public override uint PropertyCount => 1;
public override object GetProperty(uint index)
{
switch ((D2D1_SATURATION_PROP)index)
{
case D2D1_SATURATION_PROP.D2D1_SATURATION_PROP_SATURATION:
return 2.0f;
}
return null;
}
}
}

1
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -466,6 +466,7 @@ namespace Avalonia.Win32.Interop
WS_VSCROLL = 0x200000,
WS_EX_DLGMODALFRAME = 0x00000001,
WS_EX_NOPARENTNOTIFY = 0x00000004,
WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
WS_EX_TOPMOST = 0x00000008,
WS_EX_ACCEPTFILES = 0x00000010,
WS_EX_TRANSPARENT = 0x00000020,

18
src/Windows/Avalonia.Win32/Win32GlManager.cs

@ -7,8 +7,6 @@ namespace Avalonia.Win32
{
static class Win32GlManager
{
private static bool s_attemptedToInitialize;
public static void Initialize()
{
AvaloniaLocator.CurrentMutable.Bind<IPlatformOpenGlInterface>().ToLazy<IPlatformOpenGlInterface>(() =>
@ -19,9 +17,21 @@ namespace Avalonia.Win32
var wgl = WglPlatformOpenGlInterface.TryCreate();
return wgl;
}
if (opts?.AllowEglInitialization == true)
return EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
{
var egl = EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
if (egl is { } &&
opts?.UseWindowsUIComposition == true &&
Win32Platform.WindowsVersion.Major >= 10 &&
Win32Platform.WindowsVersion.Build >= 16299)
{
AvaloniaLocator.CurrentMutable.BindToSelf(new CompositionConnector(egl));
}
return egl;
}
return null;
});

12
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -12,6 +12,7 @@ using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
@ -46,6 +47,15 @@ namespace Avalonia
new GlVersion(GlProfileType.OpenGL, 4, 0),
new GlVersion(GlProfileType.OpenGL, 3, 2),
};
/// <summary>
/// Render Avalonia to a Texture inside the Windows.UI.Composition tree.
/// </summary>
/// <remarks>
/// Supported on Windows 10 build 16299 and above. Ignored on other versions.
/// This is recommended if you need to use AcrylicBlur or acrylic in your applications.
/// </remarks>
public bool UseWindowsUIComposition { get; set; } = true;
}
}
@ -104,7 +114,7 @@ namespace Avalonia.Win32
.Bind<IMountedVolumeInfoProvider>().ToConstant(new WindowsMountedVolumeInfoProvider());
Win32GlManager.Initialize();
_uiThread = Thread.CurrentThread;
if (OleContext.Current != null)

119
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -7,6 +7,7 @@ using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Avalonia.Platform;
@ -48,6 +49,8 @@ namespace Avalonia.Win32
private Thickness _extendedMargins;
private Thickness _offScreenMargin;
private double _extendTitleBarHint = -1;
private bool _isUsingComposition;
private IBlurHost _blurHost;
#if USE_MANAGED_DRAG
private readonly ManagedWindowResizeDragHelper _managedDrag;
@ -102,16 +105,37 @@ namespace Avalonia.Win32
};
_rendererLock = new ManagedDeferredRendererLock();
var glPlatform = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
var compositionConnector = AvaloniaLocator.Current.GetService<CompositionConnector>();
_isUsingComposition = compositionConnector is { } &&
glPlatform is EglPlatformOpenGlInterface egl &&
egl.Display is AngleWin32EglDisplay angleDisplay &&
angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
var glPlatform = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>();
if(glPlatform is EglPlatformOpenGlInterface egl)
_gl = new EglGlPlatformSurface(egl, this);
else if (glPlatform is WglPlatformOpenGlInterface wgl)
_gl = new WglGlPlatformSurface(wgl.PrimaryContext, this);
if (glPlatform != null)
{
if (_isUsingComposition)
{
var cgl = new CompositionEglGlPlatformSurface(glPlatform as EglPlatformOpenGlInterface, this);
_blurHost = cgl.AttachToCompositionTree(compositionConnector, _hwnd);
_gl = cgl;
_isUsingComposition = true;
}
else
{
if (glPlatform is EglPlatformOpenGlInterface egl2)
_gl = new EglGlPlatformSurface(egl2, this);
else if (glPlatform is WglPlatformOpenGlInterface wgl)
_gl = new WglGlPlatformSurface(wgl.PrimaryContext, this);
}
}
Screen = new ScreenImpl();
@ -328,54 +352,63 @@ namespace Avalonia.Win32
private WindowTransparencyLevel Win10EnableBlur(WindowTransparencyLevel transparencyLevel)
{
bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628;
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur && !canUseAcrylic)
if (_isUsingComposition)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
_blurHost?.SetBlur(transparencyLevel >= WindowTransparencyLevel.Blur);
switch (transparencyLevel)
return transparencyLevel;
}
else
{
default:
case WindowTransparencyLevel.None:
accent.AccentState = AccentState.ACCENT_DISABLED;
break;
bool canUseAcrylic = Win32Platform.WindowsVersion.Major > 10 || Win32Platform.WindowsVersion.Build >= 19628;
case WindowTransparencyLevel.Transparent:
accent.AccentState = AccentState.ACCENT_ENABLE_TRANSPARENTGRADIENT;
break;
var accent = new AccentPolicy();
var accentStructSize = Marshal.SizeOf(accent);
case WindowTransparencyLevel.Blur:
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
break;
if (transparencyLevel == WindowTransparencyLevel.AcrylicBlur && !canUseAcrylic)
{
transparencyLevel = WindowTransparencyLevel.Blur;
}
case WindowTransparencyLevel.AcrylicBlur:
case (WindowTransparencyLevel.AcrylicBlur + 1): // hack-force acrylic.
accent.AccentState = AccentState.ACCENT_ENABLE_ACRYLIC;
transparencyLevel = WindowTransparencyLevel.AcrylicBlur;
break;
}
switch (transparencyLevel)
{
default:
case WindowTransparencyLevel.None:
accent.AccentState = AccentState.ACCENT_DISABLED;
break;
case WindowTransparencyLevel.Transparent:
accent.AccentState = AccentState.ACCENT_ENABLE_TRANSPARENTGRADIENT;
break;
case WindowTransparencyLevel.Blur:
accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
break;
case WindowTransparencyLevel.AcrylicBlur:
case (WindowTransparencyLevel.AcrylicBlur + 1): // hack-force acrylic.
accent.AccentState = AccentState.ACCENT_ENABLE_ACRYLIC;
transparencyLevel = WindowTransparencyLevel.AcrylicBlur;
break;
}
accent.AccentFlags = 2;
accent.GradientColor = 0x01000000;
accent.AccentFlags = 2;
accent.GradientColor = 0x01000000;
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
var data = new WindowCompositionAttributeData();
data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
SetWindowCompositionAttribute(_hwnd, ref data);
SetWindowCompositionAttribute(_hwnd, ref data);
Marshal.FreeHGlobal(accentPtr);
Marshal.FreeHGlobal(accentPtr);
return transparencyLevel;
return transparencyLevel;
}
}
public IEnumerable<object> Surfaces => new object[] { Handle, _gl, _framebuffer };
@ -622,7 +655,7 @@ namespace Avalonia.Win32
protected virtual IntPtr CreateWindowOverride(ushort atom)
{
return CreateWindowEx(
0,
_isUsingComposition ? (int)WindowStyles.WS_EX_NOREDIRECTIONBITMAP : 0,
atom,
null,
(int)WindowStyles.WS_OVERLAPPEDWINDOW | (int) WindowStyles.WS_CLIPCHILDREN,

3
src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj

@ -23,5 +23,8 @@
<Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\CompilerExtensions\**\*.cs" />
<Compile Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\AvaloniaXamlIlRuntimeCompiler.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
</ItemGroup>
<Import Project="..\..\..\build\NetFX.props" />
</Project>

54
tests/Avalonia.RenderTests/Controls/TextBlockTests.cs

@ -40,5 +40,59 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
await RenderToFile(target);
CompareImages();
}
[Win32Fact("Has text")]
public async Task RestrictedHeight_VerticalAlign()
{
IControl text(VerticalAlignment verticalAlingnment, bool clip = true, bool restrictHeight = true)
{
return new Border()
{
BorderBrush = Brushes.Blue,
BorderThickness = new Thickness(1),
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
Height = restrictHeight ? 20 : double.NaN,
Margin = new Thickness(1),
Child = new TextBlock
{
FontFamily = new FontFamily("Courier New"),
Background = Brushes.Red,
FontSize = 24,
Foreground = Brushes.Black,
Text = "L",
VerticalAlignment = verticalAlingnment,
ClipToBounds = clip
}
};
}
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 180,
Height = 80,
Child = new StackPanel()
{
Orientation = Orientation.Horizontal,
Children =
{
text(VerticalAlignment.Stretch, restrictHeight: false),
text(VerticalAlignment.Center),
text(VerticalAlignment.Stretch),
text(VerticalAlignment.Top),
text(VerticalAlignment.Bottom),
text(VerticalAlignment.Center, clip:false),
text(VerticalAlignment.Stretch, clip:false),
text(VerticalAlignment.Top, clip:false),
text(VerticalAlignment.Bottom, clip:false),
}
}
};
await RenderToFile(target);
CompareImages();
}
}
}

BIN
tests/TestFiles/Direct2D1/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

BIN
tests/TestFiles/Skia/Controls/TextBlock/RestrictedHeight_VerticalAlign.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Loading…
Cancel
Save