diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index 77407f9996..04e8a3ad4f 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,6 +1,6 @@
-
+
diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs
index 1f484fd6cb..fbdf64b14a 100644
--- a/src/Avalonia.Controls/WindowBase.cs
+++ b/src/Avalonia.Controls/WindowBase.cs
@@ -29,6 +29,7 @@ namespace Avalonia.Controls
public static readonly DirectProperty IsActiveProperty =
AvaloniaProperty.RegisterDirect(nameof(IsActive), o => o.IsActive);
+ private bool _hasExecutedInitialLayoutPass;
private bool _isActive;
private bool _ignoreVisibilityChange;
@@ -136,7 +137,13 @@ namespace Avalonia.Controls
{
EnsureInitialized();
IsVisible = true;
- LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+
+ if (!_hasExecutedInitialLayoutPass)
+ {
+ LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+ _hasExecutedInitialLayoutPass = true;
+ }
+
PlatformImpl?.Show();
}
finally
diff --git a/src/Avalonia.Layout/LayoutManager.cs b/src/Avalonia.Layout/LayoutManager.cs
index 108922b5b9..3244f5e7dc 100644
--- a/src/Avalonia.Layout/LayoutManager.cs
+++ b/src/Avalonia.Layout/LayoutManager.cs
@@ -190,8 +190,12 @@ namespace Avalonia.Layout
control.Arrange(new Rect(embeddedRoot.AllocatedSize));
else if (control is ILayoutRoot root)
control.Arrange(new Rect(root.DesiredSize));
- else
+ else if (control.PreviousArrange != null)
+ {
+ // Has been observed that PreviousArrange sometimes is null, probably a bug somewhere else.
+ // Condition observed: control.VisualParent is Scrollbar, control is Border.
control.Arrange(control.PreviousArrange.Value);
+ }
}
}
diff --git a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
index 9f38861b07..fb1a9955e3 100644
--- a/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
+++ b/src/Gtk/Avalonia.Gtk3/Interop/Native.cs
@@ -500,6 +500,24 @@ namespace Avalonia.Gtk3.Interop
public gdouble delta_y;
}
+ [StructLayout(LayoutKind.Sequential)]
+ unsafe struct GdkEventCrossing
+ {
+ public GdkEventType type;
+ public IntPtr window;
+ public gint8 send_event;
+ public IntPtr subwindow;
+ public guint32 time;
+ public gdouble x;
+ public gdouble y;
+ public gdouble x_root;
+ public gdouble y_root;
+ public int mode;
+ public int detail;
+ public bool focus;
+ public GdkModifierType state;
+ };
+
[StructLayout(LayoutKind.Sequential)]
unsafe struct GdkEventWindowState
{
diff --git a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
index 00130346e8..39304940d2 100644
--- a/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
+++ b/src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
@@ -45,6 +45,7 @@ namespace Avalonia.Gtk3
ConnectEvent("window-state-event", OnStateChanged);
ConnectEvent("key-press-event", OnKeyEvent);
ConnectEvent("key-release-event", OnKeyEvent);
+ ConnectEvent("leave-notify-event", OnLeaveNotifyEvent);
Connect("destroy", OnDestroy);
Native.GtkWidgetRealize(gtkWidget);
_lastSize = ClientSize;
@@ -194,6 +195,18 @@ namespace Avalonia.Gtk3
return true;
}
+ private unsafe bool OnLeaveNotifyEvent(IntPtr w, IntPtr pev, IntPtr userData)
+ {
+ var evnt = (GdkEventCrossing*) pev;
+ var position = new Point(evnt->x, evnt->y);
+ Input(new RawMouseEventArgs(Gtk3Platform.Mouse,
+ evnt->time,
+ _inputRoot,
+ RawMouseEventType.Move,
+ position, GetModifierKeys(evnt->state)));
+ return true;
+ }
+
private unsafe bool OnCommit(IntPtr gtkwidget, IntPtr utf8string, IntPtr userdata)
{
Input(new RawTextInputEventArgs(Gtk3Platform.Keyboard, _lastKbdEvent, Utf8Buffer.StringFromPtr(utf8string)));
diff --git a/src/Skia/Avalonia.Skia.Desktop.NetStandard/Avalonia.Skia.Desktop.NetStandard.csproj b/src/Skia/Avalonia.Skia.Desktop.NetStandard/Avalonia.Skia.Desktop.NetStandard.csproj
index ca9f6c76e1..311abce88f 100644
--- a/src/Skia/Avalonia.Skia.Desktop.NetStandard/Avalonia.Skia.Desktop.NetStandard.csproj
+++ b/src/Skia/Avalonia.Skia.Desktop.NetStandard/Avalonia.Skia.Desktop.NetStandard.csproj
@@ -5,6 +5,7 @@
false
Avalonia.Skia.Desktop
Avalonia.Skia.Desktop
+ true
true
@@ -42,4 +43,4 @@
-
\ No newline at end of file
+
diff --git a/src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj b/src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj
index b8dd79eca9..e2a2ac6146 100644
--- a/src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj
+++ b/src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj
@@ -54,6 +54,9 @@
prompt
MinimumRecommendedRules.ruleset
+
+ true
+
@@ -107,4 +110,4 @@
-
\ No newline at end of file
+
diff --git a/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs b/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs
index cbf11504c1..f4e44a81f0 100644
--- a/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs
+++ b/tests/Avalonia.RenderTests/Media/ImageBrushTests.cs
@@ -28,6 +28,82 @@ namespace Avalonia.Direct2D1.RenderTests.Media
get { return System.IO.Path.Combine(OutputPath, "github_icon.png"); }
}
+ private string SmallBitmapPath
+ {
+ get { return System.IO.Path.Combine(OutputPath, "github_icon_small.png"); }
+ }
+
+ [Fact]
+ public void ImageBrush_Tile_Fill()
+ {
+ Decorator target = new Decorator
+ {
+ Width = 200,
+ Height = 200,
+ Child = new Rectangle
+ {
+ Margin = new Thickness(8),
+ Fill = new ImageBrush
+ {
+ Stretch = Stretch.Fill,
+ TileMode = TileMode.Tile,
+ DestinationRect = new RelativeRect(0, 0, 25, 30, RelativeUnit.Absolute),
+ Source = new Bitmap(BitmapPath),
+ }
+ }
+ };
+
+ RenderToFile(target);
+ CompareImages();
+ }
+
+ [Fact]
+ public void ImageBrush_Tile_UniformToFill()
+ {
+ Decorator target = new Decorator
+ {
+ Width = 200,
+ Height = 200,
+ Child = new Rectangle
+ {
+ Margin = new Thickness(8),
+ Fill = new ImageBrush
+ {
+ Stretch = Stretch.Uniform,
+ TileMode = TileMode.Tile,
+ DestinationRect = new RelativeRect(0, 0, 25, 30, RelativeUnit.Absolute),
+ Source = new Bitmap(BitmapPath),
+ }
+ }
+ };
+
+ RenderToFile(target);
+ CompareImages();
+ }
+
+ [Fact]
+ public void ImageBrush_Tile_Small_Image()
+ {
+ Decorator target = new Decorator
+ {
+ Width = 200,
+ Height = 200,
+ Child = new Rectangle
+ {
+ Margin = new Thickness(8),
+ Fill = new ImageBrush
+ {
+ Stretch = Stretch.None,
+ TileMode = TileMode.Tile,
+ Source = new Bitmap(SmallBitmapPath),
+ }
+ }
+ };
+
+ RenderToFile(target);
+ CompareImages();
+ }
+
[Fact]
public void ImageBrush_NoStretch_NoTile_Alignment_TopLeft()
{
diff --git a/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png b/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png
new file mode 100644
index 0000000000..c38dcfbcfd
Binary files /dev/null and b/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png differ
diff --git a/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png b/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png
new file mode 100644
index 0000000000..669da6ca1a
Binary files /dev/null and b/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png differ
diff --git a/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png b/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png
new file mode 100644
index 0000000000..59e9aea5df
Binary files /dev/null and b/tests/TestFiles/Cairo/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png differ
diff --git a/tests/TestFiles/Cairo/Media/ImageBrush/github_icon_small.png b/tests/TestFiles/Cairo/Media/ImageBrush/github_icon_small.png
new file mode 100644
index 0000000000..5799bdfdce
Binary files /dev/null and b/tests/TestFiles/Cairo/Media/ImageBrush/github_icon_small.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png b/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png
new file mode 100644
index 0000000000..c38dcfbcfd
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png b/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png
new file mode 100644
index 0000000000..669da6ca1a
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png b/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png
new file mode 100644
index 0000000000..23fc402cd8
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/ImageBrush/github_icon_small.png b/tests/TestFiles/Direct2D1/Media/ImageBrush/github_icon_small.png
new file mode 100644
index 0000000000..5799bdfdce
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/ImageBrush/github_icon_small.png differ
diff --git a/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png b/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png
new file mode 100644
index 0000000000..53e51f0424
Binary files /dev/null and b/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_Fill.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png b/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png
new file mode 100644
index 0000000000..669da6ca1a
Binary files /dev/null and b/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_Small_Image.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png b/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png
new file mode 100644
index 0000000000..32bdfd44d2
Binary files /dev/null and b/tests/TestFiles/Skia/Media/ImageBrush/ImageBrush_Tile_UniformToFill.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/ImageBrush/github_icon_small.png b/tests/TestFiles/Skia/Media/ImageBrush/github_icon_small.png
new file mode 100644
index 0000000000..5799bdfdce
Binary files /dev/null and b/tests/TestFiles/Skia/Media/ImageBrush/github_icon_small.png differ