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