Browse Source

Merge branch 'master' into fixes/DevTools/WithoutApplicationLifetime

pull/10510/head
Max Katz 3 years ago
committed by GitHub
parent
commit
5aed9479be
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      src/Avalonia.Base/Layout/LayoutManager.cs
  2. 8
      src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs
  3. 11
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  4. 31
      src/Skia/Avalonia.Skia/RenderTargetBitmapImpl.cs
  5. 2
      src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs
  6. 33
      tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs

27
src/Avalonia.Base/Layout/LayoutManager.cs

@ -21,6 +21,7 @@ namespace Avalonia.Layout
private readonly Layoutable _owner;
private readonly LayoutQueue<Layoutable> _toMeasure = new LayoutQueue<Layoutable>(v => !v.IsMeasureValid);
private readonly LayoutQueue<Layoutable> _toArrange = new LayoutQueue<Layoutable>(v => !v.IsArrangeValid);
private readonly List<Layoutable> _toArrangeAfterMeasure = new();
private readonly Action _executeLayoutPass;
private List<EffectiveViewportChangedListener>? _effectiveViewportChangedListeners;
private bool _disposed;
@ -266,9 +267,14 @@ namespace Avalonia.Layout
if (!control.IsArrangeValid)
{
Arrange(control);
if (Arrange(control) == ArrangeResult.AncestorMeasureInvalid)
_toArrangeAfterMeasure.Add(control);
}
}
foreach (var i in _toArrangeAfterMeasure)
InvalidateArrange(i);
_toArrangeAfterMeasure.Clear();
}
private bool Measure(Layoutable control)
@ -304,19 +310,19 @@ namespace Avalonia.Layout
return true;
}
private bool Arrange(Layoutable control)
private ArrangeResult Arrange(Layoutable control)
{
if (!control.IsVisible || !control.IsAttachedToVisualTree)
return false;
return ArrangeResult.NotVisible;
if (control.VisualParent is Layoutable parent)
{
if (!Arrange(parent))
return false;
if (Arrange(parent) is var parentResult && parentResult != ArrangeResult.Arranged)
return parentResult;
}
if (!control.IsMeasureValid)
return false;
return ArrangeResult.AncestorMeasureInvalid;
if (!control.IsArrangeValid)
{
@ -332,7 +338,7 @@ namespace Avalonia.Layout
}
}
return true;
return ArrangeResult.Arranged;
}
private void QueueLayoutPass()
@ -435,5 +441,12 @@ namespace Avalonia.Layout
public Layoutable Listener { get; }
public Rect Viewport { get; set; }
}
private enum ArrangeResult
{
Arranged,
NotVisible,
AncestorMeasureInvalid,
}
}
}

8
src/Avalonia.Base/Media/Imaging/RenderTargetBitmap.cs

@ -9,7 +9,7 @@ namespace Avalonia.Media.Imaging
/// <summary>
/// A bitmap that holds the rendering of a <see cref="Visual"/>.
/// </summary>
public class RenderTargetBitmap : Bitmap, IDisposable
public class RenderTargetBitmap : Bitmap
{
/// <summary>
/// Initializes a new instance of the <see cref="RenderTargetBitmap"/> class.
@ -68,5 +68,11 @@ namespace Avalonia.Media.Imaging
platform.Clear(Colors.Transparent);
return new PlatformDrawingContext(platform);
}
public override void Dispose()
{
PlatformImpl.Dispose();
base.Dispose();
}
}
}

11
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -191,16 +191,7 @@ namespace Avalonia.Skia
throw new ArgumentException("Height can't be less than 1", nameof(size));
}
var createInfo = new SurfaceRenderTarget.CreateInfo
{
Width = size.Width,
Height = size.Height,
Dpi = dpi,
DisableTextLcdRendering = false,
DisableManualFbo = true,
};
return new SurfaceRenderTarget(createInfo);
return new RenderTargetBitmapImpl(size, dpi);
}
/// <inheritdoc />

31
src/Skia/Avalonia.Skia/RenderTargetBitmapImpl.cs

@ -0,0 +1,31 @@
using System.IO;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using SkiaSharp;
namespace Avalonia.Skia;
internal class RenderTargetBitmapImpl : WriteableBitmapImpl,
IRenderTargetBitmapImpl,
IFramebufferPlatformSurface
{
private readonly FramebufferRenderTarget _renderTarget;
public RenderTargetBitmapImpl(PixelSize size, Vector dpi) : base(size, dpi,
SKImageInfo.PlatformColorType == SKColorType.Rgba8888 ? PixelFormats.Rgba8888 : PixelFormat.Bgra8888,
AlphaFormat.Premul)
{
_renderTarget = new FramebufferRenderTarget(this);
}
public IDrawingContextImpl CreateDrawingContext() => _renderTarget.CreateDrawingContext();
public bool IsCorrupted => false;
public override void Dispose()
{
_renderTarget.Dispose();
base.Dispose();
}
}

2
src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs

@ -131,7 +131,7 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void Dispose()
public virtual void Dispose()
{
_bitmap.Dispose();
}

33
tests/Avalonia.Base.UnitTests/Layout/LayoutManagerTests.cs

@ -547,5 +547,38 @@ namespace Avalonia.Base.UnitTests.Layout
Assert.True(root.IsMeasureValid);
Assert.True(root.IsArrangeValid);
}
[Fact]
public void GreatGrandparent_Can_Invalidate_Grandparent_Measure_During_Arrange()
{
// Issue #7706 (second part: scrollbar gets stuck)
var child = new LayoutTestControl();
var parent = new LayoutTestControl { Child = child };
var grandparent = new LayoutTestControl { Child = parent };
var greatGrandparent = new LayoutTestControl { Child = grandparent };
var root = new LayoutTestRoot { Child = greatGrandparent };
root.LayoutManager.ExecuteInitialLayoutPass();
greatGrandparent.DoArrangeOverride = (_, s) =>
{
grandparent.InvalidateMeasure();
return s;
};
child.InvalidateArrange();
greatGrandparent.InvalidateArrange();
root.LayoutManager.ExecuteLayoutPass();
Assert.True(child.IsMeasureValid);
Assert.True(child.IsArrangeValid);
Assert.True(parent.IsMeasureValid);
Assert.True(parent.IsArrangeValid);
Assert.True(greatGrandparent.IsMeasureValid);
Assert.True(greatGrandparent.IsArrangeValid);
Assert.True(root.IsMeasureValid);
Assert.True(root.IsArrangeValid);
}
}
}

Loading…
Cancel
Save