diff --git a/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs b/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs index 0e3267ee38..af896b426d 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs +++ b/src/Avalonia.Base/Media/TextFormatting/ShapedBuffer.cs @@ -8,7 +8,7 @@ namespace Avalonia.Media.TextFormatting public sealed class ShapedBuffer : IList, IDisposable { private static readonly IComparer s_clusterComparer = new CompareClusters(); - private bool _rented; + private bool _bufferRented; public ShapedBuffer(CharacterBufferRange characterBufferRange, int bufferLength, IGlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) : this(characterBufferRange, @@ -17,7 +17,7 @@ namespace Avalonia.Media.TextFormatting fontRenderingEmSize, bidiLevel) { - _rented = true; + _bufferRented = true; Length = bufferLength; } @@ -272,7 +272,7 @@ namespace Avalonia.Media.TextFormatting public void Dispose() { GC.SuppressFinalize(this); - if (_rented) + if (_bufferRented) { GlyphInfos.ReturnRent(); } @@ -280,7 +280,7 @@ namespace Avalonia.Media.TextFormatting ~ShapedBuffer() { - if (_rented) + if (_bufferRented) { GlyphInfos.ReturnRent(); } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index af954eb5e9..6034e9f679 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -981,9 +981,12 @@ namespace Avalonia.Media.TextFormatting public override void Dispose() { - foreach (var run in _textRuns.OfType()) + for (int i = 0; i < _textRuns.Count; i++) { - run.Dispose(); + if (_textRuns[i] is ShapedTextRun shapedTextRun) + { + shapedTextRun.Dispose(); + } } } diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 480a8ee7a7..f599511392 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -588,6 +588,7 @@ namespace Avalonia.Controls.Presenters protected virtual void InvalidateTextLayout() { + _textLayout?.Dispose(); _textLayout = null; InvalidateMeasure(); @@ -597,6 +598,7 @@ namespace Avalonia.Controls.Presenters { _constraint = availableSize; + _textLayout?.Dispose(); _textLayout = null; InvalidateArrange(); @@ -622,6 +624,7 @@ namespace Avalonia.Controls.Presenters _constraint = new Size(Math.Ceiling(finalSize.Width), double.PositiveInfinity); + _textLayout?.Dispose(); _textLayout = null; return finalSize; diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index 7a0da1ecc5..31ddf1f985 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -173,13 +173,7 @@ namespace Avalonia.Controls /// /// Gets the used to render the text. /// - public TextLayout TextLayout - { - get - { - return _textLayout ??= CreateTextLayout(_text); - } - } + public TextLayout TextLayout => _textLayout ??= CreateTextLayout(_text); /// /// Gets or sets the padding to place around the . @@ -648,6 +642,7 @@ namespace Avalonia.Controls /// protected void InvalidateTextLayout() { + _textLayout?.Dispose(); _textLayout = null; InvalidateVisual(); @@ -663,6 +658,7 @@ namespace Avalonia.Controls _constraint = availableSize.Deflate(padding); + _textLayout?.Dispose(); _textLayout = null; var inlines = Inlines; @@ -726,6 +722,7 @@ namespace Avalonia.Controls _constraint = new Size(Math.Ceiling(finalSize.Deflate(padding).Width), double.PositiveInfinity); + _textLayout?.Dispose(); _textLayout = null; if (HasComplexContent) diff --git a/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs b/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs index 20fa268a85..bf0253e9ab 100644 --- a/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs +++ b/tests/Avalonia.Benchmarks/Text/HugeTextLayout.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Avalonia.Controls; using Avalonia.Media; using Avalonia.Media.TextFormatting; using Avalonia.UnitTests; @@ -70,6 +71,26 @@ In respect that the structure of the sufficient amount poses problems and challe [Benchmark] public TextLayout[] BuildManySmallTexts() => _manySmallStrings.Select(MakeLayout).ToArray(); + [Benchmark] + public void VirtualizeTextBlocks() + { + var blocks = new TextBlock[10]; + for (var i = 0; i < blocks.Length; i++) + { + blocks[i] = new TextBlock + { + Width = 120, + Height = 32, + }; + } + + for (int i = 0, j = 0; i < _manySmallStrings.Length; i++, j = j < blocks.Length - 1 ? j + 1 : 0) + { + blocks[j].Text = _manySmallStrings[i]; + blocks[j].Measure(new Size(200, 200)); + } + } + private static TextLayout MakeLayout(string str) { var layout = new TextLayout(str, Typeface.Default, 12d, Brushes.Black, maxWidth: 120);