diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index 43c8fbcbb4..f6f11aa9ad 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -63,10 +63,10 @@ namespace Avalonia.Controls Vector scale = Stretch.CalculateScaling(Bounds.Size, sourceSize); Size scaledSize = sourceSize * scale; Rect destRect = viewPort - .CenterIn(new Rect(scaledSize)) + .CenterRect(new Rect(scaledSize)) .Intersect(viewPort); Rect sourceRect = new Rect(sourceSize) - .CenterIn(new Rect(destRect.Size / scale)); + .CenterRect(new Rect(destRect.Size / scale)); context.DrawImage(source, 1, sourceRect, destRect); } diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 0d6aadbcaa..0132c5e8a3 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -238,7 +238,7 @@ namespace Avalonia /// /// The rectangle to center. /// The centered rectangle. - public Rect CenterIn(Rect rect) + public Rect CenterRect(Rect rect) { return new Rect( _x + ((_width - rect._width) / 2), @@ -401,6 +401,32 @@ namespace Avalonia return new Rect(Position + offset, Size); } + /// + /// Gets the union of two rectangles. + /// + /// The other rectangle. + /// The union. + public Rect Union(Rect rect) + { + if (IsEmpty) + { + return rect; + } + else if (rect.IsEmpty) + { + return this; + } + else + { + var x1 = Math.Min(this.X, rect.X); + var x2 = Math.Max(this.Right, rect.Right); + var y1 = Math.Min(this.Y, rect.Y); + var y2 = Math.Max(this.Bottom, rect.Bottom); + + return new Rect(new Point(x1, y1), new Point(x2, y2)); + } + } + /// /// Returns a new with the specified X position. /// diff --git a/src/Avalonia.Visuals/Size.cs b/src/Avalonia.Visuals/Size.cs index a11411c3ee..6ad87c6120 100644 --- a/src/Avalonia.Visuals/Size.cs +++ b/src/Avalonia.Visuals/Size.cs @@ -43,6 +43,11 @@ namespace Avalonia _height = height; } + /// + /// Gets the aspect ratio of the size. + /// + public double AspectRatio => _width / _height; + /// /// Gets the width. /// @@ -97,6 +102,17 @@ namespace Avalonia return new Size(size._width / scale.X, size._height / scale.Y); } + /// + /// Divides a size by another size to produce a scaling factor. + /// + /// The first size + /// The second size. + /// The scaled size. + public static Vector operator /(Size left, Size right) + { + return new Vector(left._width / right._width, left._height / right._height); + } + /// /// Scales a size. /// diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0000b5c0a9..f80e62ee2d 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -572,9 +572,8 @@ namespace Avalonia.Win32 if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero) { - UnmanagedMethods.RECT r; - UnmanagedMethods.GetUpdateRect(_hwnd, out r, false); var f = Scaling; + var r = ps.rcPaint; Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f, (r.bottom - r.top) / f)); UnmanagedMethods.EndPaint(_hwnd, ref ps); } diff --git a/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj b/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj index 9e7f739a1c..97b3e38e32 100644 --- a/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj +++ b/tests/Avalonia.Visuals.UnitTests/Avalonia.Visuals.UnitTests.csproj @@ -80,6 +80,8 @@ + + diff --git a/tests/Avalonia.Visuals.UnitTests/RectTests.cs b/tests/Avalonia.Visuals.UnitTests/RectTests.cs new file mode 100644 index 0000000000..6e3f654bfb --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/RectTests.cs @@ -0,0 +1,42 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Xunit; + +namespace Avalonia.Visuals.UnitTests +{ + public class RectTests + { + [Fact] + public void Union_Should_Return_Correct_Value_For_Intersecting_Rects() + { + var result = new Rect(0, 0, 100, 100).Union(new Rect(50, 50, 100, 100)); + + Assert.Equal(new Rect(0, 0, 150, 150), result); + } + + [Fact] + public void Union_Should_Return_Correct_Value_For_NonIntersecting_Rects() + { + var result = new Rect(0, 0, 100, 100).Union(new Rect(150, 150, 100, 100)); + + Assert.Equal(new Rect(0, 0, 250, 250), result); + } + + [Fact] + public void Union_Should_Ignore_Empty_This_rect() + { + var result = new Rect(0, 0, 0, 0).Union(new Rect(150, 150, 100, 100)); + + Assert.Equal(new Rect(150, 150, 100, 100), result); + } + + [Fact] + public void Union_Should_Ignore_Empty_Other_rect() + { + var result = new Rect(0, 0, 100, 100).Union(new Rect(150, 150, 0, 0)); + + Assert.Equal(new Rect(0, 0, 100, 100), result); + } + } +} diff --git a/tests/Avalonia.Visuals.UnitTests/SizeTests.cs b/tests/Avalonia.Visuals.UnitTests/SizeTests.cs new file mode 100644 index 0000000000..10a012bb7f --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/SizeTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Xunit; + +namespace Avalonia.Visuals.UnitTests +{ + public class SizeTests + { + [Fact] + public void Should_Produce_Correct_Aspect_Ratio() + { + var result = new Size(3, 2).AspectRatio; + + Assert.Equal(1.5, result); + } + + [Fact] + public void Dividing_Should_Produce_Scaling_Factor() + { + var result = new Size(15, 10) / new Size(5, 5); + + Assert.Equal(new Vector(3, 2), result); + } + } +}