Browse Source

Remove unnecessary allocations from the layout loop.

pull/3203/head
Dariusz Komosinski 7 years ago
parent
commit
2b05319b6b
  1. 8
      src/Avalonia.Layout/LayoutManager.cs
  2. 25
      src/Avalonia.Layout/LayoutQueue.cs
  3. 28
      src/Avalonia.Layout/Layoutable.cs

8
src/Avalonia.Layout/LayoutManager.cs

@ -15,9 +15,15 @@ namespace Avalonia.Layout
{
private readonly LayoutQueue<ILayoutable> _toMeasure = new LayoutQueue<ILayoutable>(v => !v.IsMeasureValid);
private readonly LayoutQueue<ILayoutable> _toArrange = new LayoutQueue<ILayoutable>(v => !v.IsArrangeValid);
private readonly Action _executeLayoutPass;
private bool _queued;
private bool _running;
public LayoutManager()
{
_executeLayoutPass = QueueLayoutPass;
}
/// <inheritdoc/>
public void InvalidateMeasure(ILayoutable control)
{
@ -215,7 +221,7 @@ namespace Avalonia.Layout
{
if (!_queued && !_running)
{
Dispatcher.UIThread.Post(ExecuteLayoutPass, DispatcherPriority.Layout);
Dispatcher.UIThread.Post(_executeLayoutPass, DispatcherPriority.Layout);
_queued = true;
}
}

25
src/Avalonia.Layout/LayoutQueue.cs

@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Avalonia.Layout
{
@ -18,9 +17,11 @@ namespace Avalonia.Layout
_shouldEnqueue = shouldEnqueue;
}
private Func<T, bool> _shouldEnqueue;
private Queue<T> _inner = new Queue<T>();
private Dictionary<T, Info> _loopQueueInfo = new Dictionary<T, Info>();
private readonly Func<T, bool> _shouldEnqueue;
private readonly Queue<T> _inner = new Queue<T>();
private readonly Dictionary<T, Info> _loopQueueInfo = new Dictionary<T, Info>();
private readonly List<KeyValuePair<T, Info>> _notFinalizedBuffer = new List<KeyValuePair<T, Info>>();
private int _maxEnqueueCountPerLoop = 1;
public int Count => _inner.Count;
@ -60,13 +61,19 @@ namespace Avalonia.Layout
public void EndLoop()
{
var notfinalized = _loopQueueInfo.Where(v => v.Value.Count >= _maxEnqueueCountPerLoop).ToArray();
foreach (KeyValuePair<T, Info> info in _loopQueueInfo)
{
if (info.Value.Count >= _maxEnqueueCountPerLoop)
{
_notFinalizedBuffer.Add(info);
}
}
_loopQueueInfo.Clear();
//prevent layout cycle but add to next layout the non arranged/measured items that might have caused cycle
//one more time as a final attempt
foreach (var item in notfinalized)
// Prevent layout cycle but add to next layout the non arranged/measured items that might have caused cycle
// one more time as a final attempt.
foreach (var item in _notFinalizedBuffer)
{
if (_shouldEnqueue(item.Key))
{
@ -74,6 +81,8 @@ namespace Avalonia.Layout
_inner.Enqueue(item.Key);
}
}
_notFinalizedBuffer.Clear();
}
}
}

28
src/Avalonia.Layout/Layoutable.cs

@ -562,11 +562,18 @@ namespace Avalonia.Layout
double width = 0;
double height = 0;
foreach (ILayoutable child in this.GetVisualChildren())
var visualCount = VisualChildren.Count;
for (var i = 0; i < visualCount; i++)
{
child.Measure(availableSize);
width = Math.Max(width, child.DesiredSize.Width);
height = Math.Max(height, child.DesiredSize.Height);
IVisual visual = VisualChildren[i];
if (visual is ILayoutable layoutable)
{
layoutable.Measure(availableSize);
width = Math.Max(width, layoutable.DesiredSize.Width);
height = Math.Max(height, layoutable.DesiredSize.Height);
}
}
return new Size(width, height);
@ -658,9 +665,18 @@ namespace Avalonia.Layout
/// <returns>The actual size used.</returns>
protected virtual Size ArrangeOverride(Size finalSize)
{
foreach (ILayoutable child in this.GetVisualChildren().OfType<ILayoutable>())
var arrangeRect = new Rect(finalSize);
var visualCount = VisualChildren.Count;
for (var i = 0; i < visualCount; i++)
{
child.Arrange(new Rect(finalSize));
IVisual visual = VisualChildren[i];
if (visual is ILayoutable layoutable)
{
layoutable.Arrange(arrangeRect);
}
}
return finalSize;

Loading…
Cancel
Save