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);
+ }
+ }
+}