diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props
index e10de93530..85e7a1f34d 100644
--- a/build/HarfBuzzSharp.props
+++ b/build/HarfBuzzSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index a217a8272d..1ee4aa56a2 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm
index d43a8beee4..d96fe717ab 100644
--- a/native/Avalonia.Native/src/OSX/WindowImpl.mm
+++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm
@@ -523,7 +523,7 @@ bool WindowImpl::IsDialog() {
}
NSWindowStyleMask WindowImpl::GetStyle() {
- unsigned long s = this->_isDialog ? NSWindowStyleMaskUtilityWindow : NSWindowStyleMaskBorderless;
+ unsigned long s = this->_isDialog ? NSWindowStyleMaskDocModalWindow : NSWindowStyleMaskBorderless;
switch (_decorations) {
case SystemDecorationsNone:
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index e5f07c90c3..bce924a3f2 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -1,7 +1,8 @@
netstandard2.0
- true
+ true
+ enable
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
index 3cadc7243a..fd908a33b6 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
@@ -8,7 +8,6 @@ using Avalonia.Dialogs;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
#pragma warning disable 4014
-
namespace ControlCatalog.Pages
{
public class DialogsPage : UserControl
@@ -22,7 +21,7 @@ namespace ControlCatalog.Pages
string lastSelectedDirectory = null;
- List GetFilters()
+ List? GetFilters()
{
if (this.FindControl("UseFilters").IsChecked != true)
return null;
diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
index 5e97635c9a..4727ea1bfb 100644
--- a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
+++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
@@ -31,6 +31,7 @@ namespace Avalonia.Animation.Animators
InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops),
s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity),
oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null,
+ s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
oldValue.SpreadMethod,
s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center),
s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin),
@@ -41,6 +42,7 @@ namespace Avalonia.Animation.Animators
InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops),
s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity),
oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null,
+ s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
oldValue.SpreadMethod,
s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center),
s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle));
@@ -50,6 +52,7 @@ namespace Avalonia.Animation.Animators
InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops),
s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity),
oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null,
+ s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
oldValue.SpreadMethod,
s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint),
s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint));
@@ -102,18 +105,21 @@ namespace Avalonia.Animation.Animators
return new ImmutableRadialGradientBrush(
CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity,
oldRadial.Transform is { } ? new ImmutableTransform(oldRadial.Transform.Value) : null,
+ oldRadial.TransformOrigin,
oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius);
case IConicGradientBrush oldConic:
return new ImmutableConicGradientBrush(
CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity,
oldConic.Transform is { } ? new ImmutableTransform(oldConic.Transform.Value) : null,
+ oldConic.TransformOrigin,
oldConic.SpreadMethod, oldConic.Center, oldConic.Angle);
case ILinearGradientBrush oldLinear:
return new ImmutableLinearGradientBrush(
CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity,
oldLinear.Transform is { } ? new ImmutableTransform(oldLinear.Transform.Value) : null,
+ oldLinear.TransformOrigin,
oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint);
default:
diff --git a/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
index 60c7a97ced..239f3aea08 100644
--- a/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
+++ b/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs
@@ -14,6 +14,7 @@ public class Rotate3DTransition: PageSlide
///
/// How long the rotation should take place
/// The orientation of the rotation
+ /// Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height of the common parent of the visual being rotated
public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal, double? depth = null)
: base(duration, orientation)
{
diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
index 445f35aad2..45c67b9f48 100644
--- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
@@ -55,7 +55,7 @@ namespace Avalonia
///
///
/// This will usually be true, except in
- ///
+ ///
/// which receives notifications for all changes to property values, whether a value with a higher
/// priority is present or not. When this property is false, the change that is being signaled
/// has not resulted in a change to the property value on the object.
diff --git a/src/Avalonia.Base/Media/Brush.cs b/src/Avalonia.Base/Media/Brush.cs
index 9d989979a7..8d531e9394 100644
--- a/src/Avalonia.Base/Media/Brush.cs
+++ b/src/Avalonia.Base/Media/Brush.cs
@@ -24,6 +24,12 @@ namespace Avalonia.Media
public static readonly StyledProperty TransformProperty =
AvaloniaProperty.Register(nameof(Transform));
+ ///
+ /// Defines the property
+ ///
+ public static readonly StyledProperty TransformOriginProperty =
+ AvaloniaProperty.Register(nameof(TransformOrigin));
+
///
public event EventHandler? Invalidated;
@@ -51,6 +57,15 @@ namespace Avalonia.Media
set { SetValue(TransformProperty, value); }
}
+ ///
+ /// Gets or sets the origin of the brush
+ ///
+ public RelativePoint TransformOrigin
+ {
+ get => GetValue(TransformOriginProperty);
+ set => SetValue(TransformOriginProperty, value);
+ }
+
///
/// Parses a brush string.
///
diff --git a/src/Avalonia.Base/Media/IBrush.cs b/src/Avalonia.Base/Media/IBrush.cs
index 10700492d1..e32894f67c 100644
--- a/src/Avalonia.Base/Media/IBrush.cs
+++ b/src/Avalonia.Base/Media/IBrush.cs
@@ -19,5 +19,10 @@ namespace Avalonia.Media
/// Gets the transform of the brush.
///
ITransform? Transform { get; }
+
+ ///
+ /// Gets the origin of the brushes
+ ///
+ RelativePoint TransformOrigin { get; }
}
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs
index 4b97615c4c..70232f0a63 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs
@@ -13,6 +13,7 @@ namespace Avalonia.Media.Immutable
/// The gradient stops.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The spread method.
/// The center point for the gradient.
/// The starting angle for the gradient.
@@ -20,10 +21,11 @@ namespace Avalonia.Media.Immutable
IReadOnlyList gradientStops,
double opacity = 1,
ImmutableTransform? transform = null,
+ RelativePoint? transformOrigin = null,
GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad,
RelativePoint? center = null,
double angle = 0)
- : base(gradientStops, opacity, transform, spreadMethod)
+ : base(gradientStops, opacity, transform, transformOrigin, spreadMethod)
{
Center = center ?? RelativePoint.Center;
Angle = angle;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
index f1e51687d0..1e95acbf22 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
@@ -13,16 +13,19 @@ namespace Avalonia.Media.Immutable
/// The gradient stops.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The spread method.
protected ImmutableGradientBrush(
IReadOnlyList gradientStops,
double opacity,
ImmutableTransform? transform,
+ RelativePoint? transformOrigin,
GradientSpreadMethod spreadMethod)
{
GradientStops = gradientStops;
Opacity = opacity;
Transform = transform;
+ TransformOrigin = transformOrigin.HasValue ? transformOrigin.Value : RelativePoint.TopLeft;
SpreadMethod = spreadMethod;
}
@@ -31,7 +34,8 @@ namespace Avalonia.Media.Immutable
///
/// The brush from which this brush's properties should be copied.
protected ImmutableGradientBrush(GradientBrush source)
- : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform?.ToImmutable(), source.SpreadMethod)
+ : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform?.ToImmutable(),
+ source.TransformOrigin, source.SpreadMethod)
{
}
@@ -47,6 +51,11 @@ namespace Avalonia.Media.Immutable
///
public ITransform? Transform { get; }
+ ///
+ /// Gets the transform origin of the brush
+ ///
+ public RelativePoint TransformOrigin { get; }
+
///
public GradientSpreadMethod SpreadMethod { get; }
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
index c36e82eacb..f9892bf60c 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
@@ -16,6 +16,7 @@ namespace Avalonia.Media.Immutable
/// The rectangle on the destination in which to paint a tile.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The rectangle of the source image that will be displayed.
///
/// How the source rectangle will be stretched to fill the destination rect.
@@ -29,6 +30,7 @@ namespace Avalonia.Media.Immutable
RelativeRect? destinationRect = null,
double opacity = 1,
ImmutableTransform? transform = null,
+ RelativePoint transformOrigin = new RelativePoint(),
RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform,
TileMode tileMode = TileMode.None,
@@ -39,6 +41,7 @@ namespace Avalonia.Media.Immutable
destinationRect ?? RelativeRect.Fill,
opacity,
transform,
+ transformOrigin,
sourceRect ?? RelativeRect.Fill,
stretch,
tileMode,
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs
index 64c0f9b44e..3c26b5c009 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs
@@ -13,6 +13,7 @@ namespace Avalonia.Media.Immutable
/// The gradient stops.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The spread method.
/// The start point for the gradient.
/// The end point for the gradient.
@@ -20,10 +21,11 @@ namespace Avalonia.Media.Immutable
IReadOnlyList gradientStops,
double opacity = 1,
ImmutableTransform? transform = null,
+ RelativePoint? transformOrigin = null,
GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad,
RelativePoint? startPoint = null,
RelativePoint? endPoint = null)
- : base(gradientStops, opacity, transform, spreadMethod)
+ : base(gradientStops, opacity, transform, transformOrigin, spreadMethod)
{
StartPoint = startPoint ?? RelativePoint.TopLeft;
EndPoint = endPoint ?? RelativePoint.BottomRight;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs
index 3da4bdd8e9..e08d2810f8 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs
@@ -13,6 +13,7 @@ namespace Avalonia.Media.Immutable
/// The gradient stops.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The spread method.
/// The start point for the gradient.
///
@@ -25,11 +26,12 @@ namespace Avalonia.Media.Immutable
IReadOnlyList gradientStops,
double opacity = 1,
ImmutableTransform? transform = null,
+ RelativePoint? transformOrigin = null,
GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad,
RelativePoint? center = null,
RelativePoint? gradientOrigin = null,
double radius = 0.5)
- : base(gradientStops, opacity, transform, spreadMethod)
+ : base(gradientStops, opacity, transform, transformOrigin, spreadMethod)
{
Center = center ?? RelativePoint.Center;
GradientOrigin = gradientOrigin ?? RelativePoint.Center;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
index 9b1b2500ef..6755dfd236 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
@@ -53,6 +53,11 @@ namespace Avalonia.Media.Immutable
///
public ITransform? Transform { get; }
+ ///
+ /// Gets the transform origin of the brush
+ ///
+ public RelativePoint TransformOrigin { get; }
+
public bool Equals(ImmutableSolidColorBrush? other)
{
if (ReferenceEquals(null, other)) return false;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
index 2c1844a2c2..6df27872fc 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
@@ -15,6 +15,7 @@ namespace Avalonia.Media.Immutable
/// The rectangle on the destination in which to paint a tile.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The rectangle of the source image that will be displayed.
///
/// How the source rectangle will be stretched to fill the destination rect.
@@ -27,6 +28,7 @@ namespace Avalonia.Media.Immutable
RelativeRect destinationRect,
double opacity,
ImmutableTransform? transform,
+ RelativePoint transformOrigin,
RelativeRect sourceRect,
Stretch stretch,
TileMode tileMode,
@@ -37,6 +39,7 @@ namespace Avalonia.Media.Immutable
DestinationRect = destinationRect;
Opacity = opacity;
Transform = transform;
+ TransformOrigin = transformOrigin;
SourceRect = sourceRect;
Stretch = stretch;
TileMode = tileMode;
@@ -54,6 +57,7 @@ namespace Avalonia.Media.Immutable
source.DestinationRect,
source.Opacity,
source.Transform?.ToImmutable(),
+ source.TransformOrigin,
source.SourceRect,
source.Stretch,
source.TileMode,
@@ -78,6 +82,11 @@ namespace Avalonia.Media.Immutable
///
public ITransform? Transform { get; }
+ ///
+ /// Gets the transform origin of the brush
+ ///
+ public RelativePoint TransformOrigin { get; }
+
///
public RelativeRect SourceRect { get; }
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
index 8ecef63237..b436dcdb5e 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs
@@ -17,6 +17,7 @@ namespace Avalonia.Media.Immutable
/// The rectangle on the destination in which to paint a tile.
/// The opacity of the brush.
/// The transform of the brush.
+ /// The transform origin of the brush
/// The rectangle of the source image that will be displayed.
///
/// How the source rectangle will be stretched to fill the destination rect.
@@ -30,6 +31,7 @@ namespace Avalonia.Media.Immutable
RelativeRect? destinationRect = null,
double opacity = 1,
ImmutableTransform? transform = null,
+ RelativePoint transformOrigin = new RelativePoint(),
RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform,
TileMode tileMode = TileMode.None,
@@ -40,6 +42,7 @@ namespace Avalonia.Media.Immutable
destinationRect ?? RelativeRect.Fill,
opacity,
transform,
+ transformOrigin,
sourceRect ?? RelativeRect.Fill,
stretch,
tileMode,
diff --git a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
index a3095ad214..ae52e5f970 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
@@ -193,8 +193,11 @@ namespace Avalonia.Controls
}
}
+ /// Try get number of DataSource itmes.
/// When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.
/// If "getAny" is true, method can use Linq.Any() method to speedup.
+ /// number of DataSource itmes.
+ /// true if able to retrieve number of DataSource itmes; otherwise, false.
internal bool TryGetCount(bool allowSlow, bool getAny, out int count)
{
bool result;
diff --git a/src/Avalonia.Controls/SystemDialog.cs b/src/Avalonia.Controls/SystemDialog.cs
index 4a9e745e30..093f10be51 100644
--- a/src/Avalonia.Controls/SystemDialog.cs
+++ b/src/Avalonia.Controls/SystemDialog.cs
@@ -15,7 +15,7 @@ namespace Avalonia.Controls
/// Gets or sets a collection of filters which determine the types of files displayed in an
/// or an .
///
- public List Filters { get; set; } = new List();
+ public List? Filters { get; set; } = new List();
///
/// Gets or sets initial file name that is displayed when the dialog is opened.
diff --git a/src/Avalonia.Native/SystemDialogs.cs b/src/Avalonia.Native/SystemDialogs.cs
index 4372829df1..d1d9c17ae3 100644
--- a/src/Avalonia.Native/SystemDialogs.cs
+++ b/src/Avalonia.Native/SystemDialogs.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Native
ofd.Title ?? "",
ofd.Directory ?? "",
ofd.InitialFileName ?? "",
- string.Join(";", dialog.Filters.SelectMany(f => f.Extensions)));
+ string.Join(";", dialog.Filters?.SelectMany(f => f.Extensions) ?? Array.Empty()));
}
else
{
@@ -39,7 +39,7 @@ namespace Avalonia.Native
dialog.Title ?? "",
dialog.Directory ?? "",
dialog.InitialFileName ?? "",
- string.Join(";", dialog.Filters.SelectMany(f => f.Extensions)));
+ string.Join(";", dialog.Filters?.SelectMany(f => f.Extensions) ?? Array.Empty()));
}
return events.Task.ContinueWith(t => { events.Dispose(); return t.Result; });
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index b45968ec27..8293769138 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -181,7 +181,8 @@ namespace Avalonia.Skia
var size = geometry.Bounds.Size;
using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default(PaintWrapper))
- using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, size) : default(PaintWrapper))
+ using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen,
+ size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))) : default(PaintWrapper))
{
if (fill.Paint != null)
{
@@ -398,7 +399,7 @@ namespace Avalonia.Skia
if (pen?.Brush != null)
{
- using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size))
+ using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))))
{
if (paint.Paint is object)
{
@@ -433,7 +434,7 @@ namespace Avalonia.Skia
if (pen?.Brush != null)
{
- using (var paint = CreatePaint(_strokePaint, pen, rect.Size))
+ using (var paint = CreatePaint(_strokePaint, pen, rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))))
{
if (paint.Paint is object)
{
@@ -625,8 +626,12 @@ namespace Avalonia.Skia
}
else
{
+ var transformOrigin = linearGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * linearGradient.Transform.Value * (offset);
+
using (var shader =
- SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, linearGradient.Transform.Value.ToSKMatrix()))
+ SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, transform.ToSKMatrix()))
{
paintWrapper.Paint.Shader = shader;
}
@@ -654,8 +659,12 @@ namespace Avalonia.Skia
}
else
{
+ var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * radialGradient.Transform.Value * (offset);
+
using (var shader =
- SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, radialGradient.Transform.Value.ToSKMatrix()))
+ SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, transform.ToSKMatrix()))
{
paintWrapper.Paint.Shader = shader;
}
@@ -694,9 +703,14 @@ namespace Avalonia.Skia
}
else
{
+
+ var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * radialGradient.Transform.Value * (offset);
+
using (var shader = SKShader.CreateCompose(
SKShader.CreateColor(reversedColors[0]),
- SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, radialGradient.Transform.Value.ToSKMatrix())
+ SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, transform.ToSKMatrix())
))
{
paintWrapper.Paint.Shader = shader;
@@ -717,7 +731,12 @@ namespace Avalonia.Skia
if (conicGradient.Transform is { })
{
- rotation = rotation.PreConcat(conicGradient.Transform.Value.ToSKMatrix());
+
+ var transformOrigin = conicGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * conicGradient.Transform.Value * (offset);
+
+ rotation = rotation.PreConcat(transform.ToSKMatrix());
}
using (var shader =
@@ -794,7 +813,11 @@ namespace Avalonia.Skia
if (tileBrush.Transform is { })
{
- paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix());
+ var origin = tileBrush.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(origin);
+ var transform = (-offset) * tileBrush.Transform.Value * (offset);
+
+ paintTransform = paintTransform.PreConcat(transform.ToSKMatrix());
}
using (var shader = image.ToShader(tileX, tileY, paintTransform))
diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
index 9ff6f76ac4..3adefd965f 100644
--- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
+++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
@@ -37,6 +37,24 @@ namespace Avalonia.Win32.Input
IsComposing = false;
}
+ public void ClearLanguageAndWindow()
+ {
+ if (HWND != IntPtr.Zero && _defaultImc != IntPtr.Zero)
+ {
+ ImmReleaseContext(HWND, _defaultImc);
+ }
+
+ _defaultImc = IntPtr.Zero;
+ HWND = IntPtr.Zero;
+ _parent = null;
+ _active = false;
+ _langId = 0;
+ _showCompositionWindow = false;
+ _showCandidateList = false;
+
+ IsComposing = false;
+ }
+
//Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers -
//every Dispatcher should have their own InputMethod.
public static Imm32InputMethod Current { get; } = new Imm32InputMethod();
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
index 64ab15bc30..cae8834550 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
@@ -82,6 +82,12 @@ namespace Avalonia.Win32
case WindowsMessage.WM_DESTROY:
{
UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, IntPtr.Zero, IntPtr.Zero, null);
+
+ // We need to release IMM context and state to avoid leaks.
+ if (Imm32InputMethod.Current.HWND == _hwnd)
+ {
+ Imm32InputMethod.Current.ClearLanguageAndWindow();
+ }
//Window doesn't exist anymore
_hwnd = IntPtr.Zero;