Browse Source

Merge branch 'master' into feature/CustomizedNotifications

pull/12178/head
Max Katz 3 years ago
committed by GitHub
parent
commit
4222524c71
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      src/Avalonia.Base/Media/DrawingContext.cs
  2. 14
      src/Avalonia.Base/Media/DrawingGroup.cs
  3. 4
      src/Avalonia.Base/Media/PlatformDrawingContext.cs
  4. 11
      src/Avalonia.Base/Platform/IDrawingContextImpl.cs
  5. 15
      src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs
  6. 8
      src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs
  7. 10
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
  8. 10
      src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  9. 34
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs
  10. 16
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  11. 14
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  12. 42
      src/Windows/Avalonia.Win32/Win32Platform.cs
  13. 26
      src/Windows/Avalonia.Win32/Win32PlatformOptions.cs
  14. 18
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs

20
src/Avalonia.Base/Media/DrawingContext.cs

@ -283,7 +283,8 @@ namespace Avalonia.Media
Opacity,
Clip,
GeometryClip,
OpacityMask
OpacityMask,
RenderOptions
}
public RestoreState(DrawingContext context, PushedStateType type)
@ -308,6 +309,8 @@ namespace Avalonia.Media
_context.PopGeometryClipCore();
else if (_type == PushedStateType.OpacityMask)
_context.PopOpacityMaskCore();
else if (_type == PushedStateType.RenderOptions)
_context.PopRenderOptionsCore();
}
}
@ -400,6 +403,20 @@ namespace Avalonia.Media
return new PushedState(this);
}
/// <summary>
/// Pushes render options.
/// </summary>
/// <param name="renderOptions">The render options.</param>
/// <returns>A disposable to undo the render options.</returns>
public PushedState PushRenderOptions(RenderOptions renderOptions)
{
PushRenderOptionsCore(renderOptions);
_states ??= StateStackPool.Get();
_states.Push(new RestoreState(this, RestoreState.PushedStateType.RenderOptions));
return new PushedState(this);
}
protected abstract void PushRenderOptionsCore(RenderOptions renderOptions);
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushPreTransform(Matrix matrix) => PushTransform(matrix);
[Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
@ -415,6 +432,7 @@ namespace Avalonia.Media
protected abstract void PopOpacityCore();
protected abstract void PopOpacityMaskCore();
protected abstract void PopTransformCore();
protected abstract void PopRenderOptionsCore();
private static bool PenIsVisible(IPen? pen)
{

14
src/Avalonia.Base/Media/DrawingGroup.cs

@ -53,6 +53,8 @@ namespace Avalonia.Media
set => SetValue(OpacityMaskProperty, value);
}
internal RenderOptions? RenderOptions { get; set; }
/// <summary>
/// Gets or sets the collection that contains the child geometries.
/// </summary>
@ -75,6 +77,7 @@ namespace Avalonia.Media
using (context.PushOpacity(Opacity))
using (ClipGeometry != null ? context.PushGeometryClip(ClipGeometry) : default)
using (OpacityMask != null ? context.PushOpacityMask(OpacityMask, bounds) : default)
using (RenderOptions != null ? context.PushRenderOptions(RenderOptions.Value) : default)
{
foreach (var drawing in Children)
{
@ -313,6 +316,15 @@ namespace Avalonia.Media
drawingGroup.Transform = new MatrixTransform(matrix);
}
protected override void PushRenderOptionsCore(RenderOptions renderOptions)
{
// Instantiate a new drawing group and set it as the _currentDrawingGroup
var drawingGroup = PushNewDrawingGroup();
// Set the render options on the new DrawingGroup
drawingGroup.RenderOptions = renderOptions;
}
protected override void PopClipCore() => Pop();
protected override void PopGeometryClipCore() => Pop();
@ -323,6 +335,8 @@ namespace Avalonia.Media
protected override void PopTransformCore() => Pop();
protected override void PopRenderOptionsCore() => Pop();
/// <summary>
/// Creates a new DrawingGroup for a Push* call by setting the
/// _currentDrawingGroup to a newly instantiated DrawingGroup,

4
src/Avalonia.Base/Media/PlatformDrawingContext.cs

@ -90,6 +90,8 @@ internal sealed class PlatformDrawingContext : DrawingContext
_impl.Transform = matrix * current;
}
protected override void PushRenderOptionsCore(RenderOptions renderOptions) => _impl.PushRenderOptions(renderOptions);
protected override void PopClipCore() => _impl.PopClip();
protected override void PopGeometryClipCore() => _impl.PopGeometryClip();
@ -102,6 +104,8 @@ internal sealed class PlatformDrawingContext : DrawingContext
_impl.Transform =
(_transforms ?? throw new ObjectDisposedException(nameof(PlatformDrawingContext))).Pop();
protected override void PopRenderOptionsCore() => _impl.PopRenderOptions();
protected override void DisposeCore()
{
if (_ownsImpl)

11
src/Avalonia.Base/Platform/IDrawingContextImpl.cs

@ -160,6 +160,17 @@ namespace Avalonia.Platform
/// </summary>
void PopGeometryClip();
/// <summary>
/// Pushes render options.
/// </summary>
/// <param name="renderOptions">The render options.</param>
void PushRenderOptions(RenderOptions renderOptions);
/// <summary>
/// Pops the latest render options.
/// </summary>
void PopRenderOptions();
/// <summary>
/// Attempts to get an optional feature from the drawing context implementation.
/// </summary>

15
src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs

@ -211,3 +211,18 @@ abstract class RenderDataBrushAndPenNode : IRenderDataItemWithServerResources
public abstract Rect? Bounds { get; }
public abstract bool HitTest(Point p);
}
class RenderDataRenderOptionsNode : RenderDataPushNode
{
public RenderOptions RenderOptions { get; set; }
public override void Push(ref RenderDataNodeRenderContext context)
{
context.Context.PushRenderOptions(RenderOptions);
}
public override void Pop(ref RenderDataNodeRenderContext context)
{
context.Context.PopRenderOptions();
}
}

8
src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs

@ -259,6 +259,12 @@ internal class RenderDataDrawingContext : DrawingContext
});
}
protected override void PushRenderOptionsCore(RenderOptions renderOptions) => Push(new RenderDataRenderOptionsNode()
{
RenderOptions = renderOptions
});
protected override void PopClipCore() => Pop<RenderDataClipNode>();
protected override void PopGeometryClipCore() => Pop<RenderDataGeometryClipNode>();
@ -269,6 +275,8 @@ internal class RenderDataDrawingContext : DrawingContext
protected override void PopTransformCore() => Pop<RenderDataPushMatrixNode>();
protected override void PopRenderOptionsCore() => Pop<RenderDataRenderOptionsNode>();
internal override void DrawBitmap(IRef<IBitmapImpl>? source, double opacity, Rect sourceRect, Rect destRect)
{
if (source == null || sourceRect.IsEmpty() || destRect.IsEmpty())

10
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@ -122,6 +122,11 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
_impl.PushOpacityMask(mask, bounds);
}
public void PushRenderOptions(RenderOptions renderOptions)
{
_impl.PushRenderOptions(renderOptions);
}
public void PopOpacityMask()
{
_impl.PopOpacityMask();
@ -137,6 +142,11 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
_impl.PopGeometryClip();
}
public void PopRenderOptions()
{
_impl.PopRenderOptions();
}
public object? GetFeature(Type t) => _impl.GetFeature(t);

10
src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -542,6 +542,16 @@ namespace Avalonia.Headless
{
}
public void PushRenderOptions(RenderOptions renderOptions)
{
}
public void PopRenderOptions()
{
}
}
private class HeadlessRenderTarget : IRenderTarget

34
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs

@ -1,6 +1,7 @@
using System.Linq;
using XamlX.Ast;
using XamlX.Transform;
using XamlX.Transform.Transformers;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
@ -22,26 +23,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
IXamlAstTypeReference targetType;
var templatableBaseType = context.Configuration.TypeSystem.GetType("Avalonia.Controls.Control");
if ((tt?.Values.FirstOrDefault() is XamlTypeExtensionNode tn))
{
targetType = tn.Value;
}
else
targetType = tt?.Values.FirstOrDefault() switch
{
var parentScope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
.FirstOrDefault();
if (parentScope?.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style)
targetType = parentScope.TargetType;
else if (context.ParentNodes().Skip(1).FirstOrDefault() is XamlAstObjectNode directParentNode
&& templatableBaseType.IsAssignableFrom(directParentNode.Type.GetClrType()))
targetType = directParentNode.Type;
else
targetType = new XamlAstClrTypeReference(node,
templatableBaseType, false);
}
XamlTypeExtensionNode tn => tn.Value,
XamlAstTextNode textNode => TypeReferenceResolver.ResolveType(context, textNode.Text, false, textNode, true),
_ when context.ParentNodes()
.OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
.FirstOrDefault() is { ScopeType: AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style } parentScope => parentScope.TargetType,
_ when context.ParentNodes().Skip(1).FirstOrDefault() is XamlAstObjectNode directParentNode
&& templatableBaseType.IsAssignableFrom(directParentNode.Type.GetClrType()) => directParentNode.Type,
_ => new XamlAstClrTypeReference(node,
templatableBaseType, false)
};
return new AvaloniaXamlIlTargetTypeMetadataNode(on, targetType,
AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate);
@ -59,7 +53,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
ControlTemplate,
Transitions
}
public AvaloniaXamlIlTargetTypeMetadataNode(IXamlAstValueNode value, IXamlAstTypeReference targetType,
ScopeTypes type)
: base(value, value)

16
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -23,6 +23,7 @@ namespace Avalonia.Skia
private readonly Vector _dpi;
private readonly Stack<PaintWrapper> _maskStack = new();
private readonly Stack<double> _opacityStack = new();
private readonly Stack<RenderOptions> _renderOptionsStack = new();
private readonly Matrix? _postTransform;
private double _currentOpacity = 1.0f;
private readonly bool _disableSubpixelTextRendering;
@ -634,6 +635,21 @@ namespace Avalonia.Skia
_currentOpacity = _opacityStack.Pop();
}
/// <inheritdoc />
public void PushRenderOptions(RenderOptions renderOptions)
{
CheckLease();
_renderOptionsStack.Push(RenderOptions);
RenderOptions = RenderOptions.MergeWith(renderOptions);
}
public void PopRenderOptions()
{
RenderOptions = _renderOptionsStack.Pop();
}
/// <inheritdoc />
public virtual void Dispose()
{

14
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -24,6 +24,8 @@ namespace Avalonia.Direct2D1.Media
private readonly SharpDX.DXGI.SwapChain1 _swapChain;
private readonly Action _finishedCallback;
private readonly Stack<RenderOptions> _renderOptionsStack = new();
/// <summary>
/// Initializes a new instance of the <see cref="DrawingContextImpl"/> class.
/// </summary>
@ -488,6 +490,18 @@ namespace Avalonia.Direct2D1.Media
PopLayer();
}
public void PushRenderOptions(RenderOptions renderOptions)
{
_renderOptionsStack.Push(RenderOptions);
RenderOptions = RenderOptions.MergeWith(renderOptions);
}
public void PopRenderOptions()
{
RenderOptions = _renderOptionsStack.Pop();
}
private void PopLayer()
{
var layer = _layers.Pop();

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

@ -49,7 +49,6 @@ namespace Avalonia.Win32
public Win32Platform()
{
SetDpiAwareness();
CreateMessageWindow();
_dispatcher = new Win32DispatcherImpl(_hwnd);
}
@ -80,6 +79,9 @@ namespace Avalonia.Win32
public static void Initialize(Win32PlatformOptions options)
{
s_options = options;
SetDpiAwareness();
var renderTimer = options.ShouldRenderOnUIThread ? new UiThreadRenderTimer(60) : new DefaultRenderTimer(60);
AvaloniaLocator.CurrentMutable
@ -264,12 +266,31 @@ namespace Avalonia.Win32
var user32 = LoadLibrary("user32.dll");
var method = GetProcAddress(user32, nameof(SetProcessDpiAwarenessContext));
var dpiAwareness = Options.DpiAwareness;
if (method != IntPtr.Zero)
{
if (SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
if (dpiAwareness == Win32DpiAwareness.Unaware)
{
return;
if (SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE))
{
return;
}
}
else if (dpiAwareness == Win32DpiAwareness.SystemDpiAware)
{
if (SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
{
return;
}
}
else if (dpiAwareness == Win32DpiAwareness.PerMonitorDpiAware)
{
if (SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE))
{
return;
}
}
}
@ -278,11 +299,20 @@ namespace Avalonia.Win32
if (method != IntPtr.Zero)
{
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE);
var awareness = (dpiAwareness) switch
{
Win32DpiAwareness.Unaware => PROCESS_DPI_AWARENESS.PROCESS_DPI_UNAWARE,
Win32DpiAwareness.SystemDpiAware => PROCESS_DPI_AWARENESS.PROCESS_SYSTEM_DPI_AWARE,
Win32DpiAwareness.PerMonitorDpiAware => PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE,
_ => PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE,
};
SetProcessDpiAwareness(awareness);
return;
}
SetProcessDPIAware();
if (dpiAwareness != Win32DpiAwareness.Unaware)
SetProcessDPIAware();
}
}
}

26
src/Windows/Avalonia.Win32/Win32PlatformOptions.cs

@ -25,6 +25,27 @@ public enum Win32RenderingMode
Wgl = 3
}
/// <summary>
/// Represents the DPI Awareness for the application.
/// </summary>
public enum Win32DpiAwareness
{
/// <summary>
/// The application is DPI unaware.
/// </summary>
Unaware,
/// <summary>
/// The application is system DPI aware. It will query DPI once and will not adjust to new DPI changes
/// </summary>
SystemDpiAware,
/// <summary>
/// The application is per-monitor DPI aware. It adjust its scale factor whenever DPI changes.
/// </summary>
PerMonitorDpiAware
}
/// <summary>
/// Represents the Win32 window composition mode.
/// </summary>
@ -137,4 +158,9 @@ public class Win32PlatformOptions
/// and <see cref="CompositionMode"/> only accepts null or <see cref="Win32CompositionMode.RedirectionSurface"/>.
/// </summary>
public IPlatformGraphics? CustomPlatformGraphics { get; set; }
/// <summary>
/// Gets or sets the application's DPI awareness.
/// </summary>
public Win32DpiAwareness DpiAwareness { get; set; } = Win32DpiAwareness.PerMonitorDpiAware;
}

18
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs

@ -286,6 +286,24 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.IsType(typeof(ContentPresenter), template.Build(new ContentControl()).Result);
}
[Fact]
public void ControlTemplate_With_String_TargetType()
{
var xaml = @"
<ControlTemplate xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
TargetType='ContentControl'>
<ContentPresenter Content='{TemplateBinding Content}' />
</ControlTemplate>
";
var template = AvaloniaRuntimeXamlLoader.Parse<ControlTemplate>(xaml);
Assert.Equal(typeof(ContentControl), template.TargetType);
Assert.IsType(typeof(ContentPresenter), template.Build(new ContentControl()).Result);
}
[Fact]
public void ControlTemplate_With_Panel_Children_Are_Added()
{

Loading…
Cancel
Save