Browse Source

Fix TextBlock TextAlignment issues when a HorizontalAlignment is defined (#17402)

* Always measure TextBlock with infinite width

* Make sure the constraint is always fulfilled

* Add some tests

* Adjust tests because we no longer retain the TextLayout in the arrange pass
pull/17483/head
Benedikt Stebner 1 year ago
committed by GitHub
parent
commit
d411bd2156
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 21
      src/Avalonia.Controls/TextBlock.cs
  2. 14
      tests/Avalonia.Controls.UnitTests/TextBlockTests.cs
  3. 102
      tests/Avalonia.RenderTests/Controls/TextBlockTests.cs
  4. 9
      tests/Avalonia.RenderTests/TestSkip.cs
  5. BIN
      tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png
  6. BIN
      tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png
  7. BIN
      tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png
  8. BIN
      tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png
  9. BIN
      tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png
  10. BIN
      tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png

21
src/Avalonia.Controls/TextBlock.cs

@ -653,7 +653,7 @@ namespace Avalonia.Controls
TextDecorations,
Foreground);
var paragraphProperties = new GenericTextParagraphProperties(FlowDirection, TextAlignment, true, false,
var paragraphProperties = new GenericTextParagraphProperties(FlowDirection, IsMeasureValid ? TextAlignment : TextAlignment.Left, true, false,
defaultProperties, TextWrapping, LineHeight, 0, LetterSpacing)
{
LineSpacing = LineSpacing
@ -703,7 +703,7 @@ namespace Avalonia.Controls
var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale);
var deflatedSize = availableSize.Deflate(padding);
if(_constraint != deflatedSize)
if (_constraint != deflatedSize)
{
//Reset TextLayout when the constraint is not matching.
_textLayout?.Dispose();
@ -733,9 +733,7 @@ namespace Avalonia.Controls
var width = textLayout.OverhangLeading + textLayout.WidthIncludingTrailingWhitespace + textLayout.OverhangTrailing;
var size = LayoutHelper.RoundLayoutSizeUp(new Size(width, textLayout.Height).Inflate(padding), 1, 1);
_constraint = size;
var size = LayoutHelper.RoundLayoutSizeUp(new Size(width, textLayout.Height).Inflate(padding), 1, 1);
return size;
}
@ -747,15 +745,12 @@ namespace Avalonia.Controls
var availableSize = finalSize.Deflate(padding);
//Fixes: #11019
if (availableSize != _constraint)
{
_textLayout?.Dispose();
_textLayout = null;
_constraint = availableSize;
}
//ToDo: Introduce a text run cache to be able to reuse shaped runs etc.
_textLayout?.Dispose();
_textLayout = null;
_constraint = availableSize;
//This implicitly recreated the TextLayout with a new constraint if we previously reset it.
//This implicitly recreated the TextLayout with a new constraint.
var textLayout = TextLayout;
if (HasComplexContent)

14
tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

@ -27,7 +27,7 @@ namespace Avalonia.Controls.UnitTests
}
[Fact]
public void Calling_Measure_Should_Update_Constraint_And_TextLayout()
public void Calling_Measure_Should_Update_TextLayout()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
@ -39,8 +39,6 @@ namespace Avalonia.Controls.UnitTests
var textLayout = textBlock.TextLayout;
Assert.Equal(new Size(110, 10), textBlock.Constraint);
textBlock.Measure(new Size(50, 100));
Assert.NotEqual(textLayout, textBlock.TextLayout);
@ -60,13 +58,12 @@ namespace Avalonia.Controls.UnitTests
var constraint = LayoutHelper.RoundLayoutSizeUp(new Size(textLayout.WidthIncludingTrailingWhitespace, textLayout.Height), 1, 1);
Assert.Equal(constraint, textBlock.Constraint);
textBlock.Arrange(new Rect(constraint));
Assert.Equal(constraint, textBlock.Constraint);
//TextLayout is recreated after arrange
textLayout = textBlock.TextLayout;
Assert.Equal(textLayout, textBlock.TextLayout);
Assert.Equal(constraint, textBlock.Constraint);
textBlock.Measure(constraint);
@ -78,6 +75,7 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(constraint, textBlock.Constraint);
//TextLayout is recreated after arrange
Assert.NotEqual(textLayout, textBlock.TextLayout);
}
}
@ -93,8 +91,6 @@ namespace Avalonia.Controls.UnitTests
var textLayout = textBlock.TextLayout;
Assert.Equal(new Size(110, 10), textBlock.Constraint);
var constraint = LayoutHelper.RoundLayoutSizeUp(new Size(textLayout.WidthIncludingTrailingWhitespace, textLayout.Height), 1, 1);
Assert.Equal(constraint, textBlock.DesiredSize);

102
tests/Avalonia.RenderTests/Controls/TextBlockTests.cs

@ -5,6 +5,7 @@ using Avalonia.Controls.Documents;
using Avalonia.Layout;
using Avalonia.Media;
using Xunit;
using static System.Net.Mime.MediaTypeNames;
#if AVALONIA_SKIA
namespace Avalonia.Skia.RenderTests
@ -176,5 +177,106 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
await RenderToFile(target);
CompareImages();
}
[InlineData(150, 200, TextWrapping.NoWrap)]
[InlineData(44, 200, TextWrapping.NoWrap)]
[InlineData(44, 400, TextWrapping.Wrap)]
[Win32Theory("Has text")]
public async Task Should_Measure_Arrange_TextBlock(double width, double height, TextWrapping textWrapping)
{
var text = "Hello World";
var target = new StackPanel { Width = 200, Height = height };
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Left,
TextAlignment = TextAlignment.Left,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Left,
TextAlignment = TextAlignment.Center,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Left,
TextAlignment = TextAlignment.Right,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Center,
TextAlignment = TextAlignment.Left,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Center,
TextAlignment = TextAlignment.Center,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Center,
TextAlignment = TextAlignment.Right,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Right,
TextAlignment = TextAlignment.Left,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Right,
TextAlignment = TextAlignment.Center,
Width = width,
TextWrapping = textWrapping
});
target.Children.Add(new TextBlock
{
Text = text,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Right,
TextAlignment = TextAlignment.Right,
Width = width,
TextWrapping = textWrapping
});
var testName = $"Should_Measure_Arrange_TextBlock_{width}_{textWrapping}";
await RenderToFile(target, testName);
CompareImages(testName);
}
}
}

9
tests/Avalonia.RenderTests/TestSkip.cs

@ -17,5 +17,14 @@ namespace Avalonia.Direct2D1.RenderTests
Skip = message;
}
}
public class Win32Theory : TheoryAttribute
{
public Win32Theory(string message)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Skip = message;
}
}
}

BIN
tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Loading…
Cancel
Save