From d411bd2156762bcf37c183b41fbd9573655de56b Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Sun, 10 Nov 2024 14:06:32 +0100 Subject: [PATCH] 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 --- src/Avalonia.Controls/TextBlock.cs | 21 ++-- .../TextBlockTests.cs | 14 +-- .../Controls/TextBlockTests.cs | 102 ++++++++++++++++++ tests/Avalonia.RenderTests/TestSkip.cs | 9 ++ ..._Arrange_TextBlock_150_NoWrap.expected.png | Bin 0 -> 3526 bytes ...e_Arrange_TextBlock_44_NoWrap.expected.png | Bin 0 -> 1169 bytes ...ure_Arrange_TextBlock_44_Wrap.expected.png | Bin 0 -> 3914 bytes ..._Arrange_TextBlock_150_NoWrap.expected.png | Bin 0 -> 2830 bytes ...e_Arrange_TextBlock_44_NoWrap.expected.png | Bin 0 -> 1077 bytes ...ure_Arrange_TextBlock_44_Wrap.expected.png | Bin 0 -> 2880 bytes 10 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png create mode 100644 tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png create mode 100644 tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png create mode 100644 tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png create mode 100644 tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png create mode 100644 tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index afa7d3542a..0afafe44b8 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/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) diff --git a/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs b/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs index 8f9baed8d1..3d7c6e6c1b 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBlockTests.cs +++ b/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); diff --git a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs index 14c56299e3..473461dcb4 100644 --- a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs +++ b/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); + } } } diff --git a/tests/Avalonia.RenderTests/TestSkip.cs b/tests/Avalonia.RenderTests/TestSkip.cs index 75407332e3..c09a25b4c1 100644 --- a/tests/Avalonia.RenderTests/TestSkip.cs +++ b/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; + } + } } diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..5b83d6404d5c80292d03ffec4b1c69195f319e8c GIT binary patch literal 3526 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 F`)`col>q<% literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5f1e5bc5127d2743d35fd9c041ff4d3e21942d GIT binary patch literal 1169 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl|b_H=O!sfc@f+qOt1RHE%-{vMIXp#d&@Df$fz9UU>PNnIxtCw5D$y1@{~ zRJ7p0(x3;n2f|zq|HRGSAgzPe;f8)%h{*M}EJGc&n!rC;zi*mH5-|y|Sy4%b!+mXbU~BkgxQp z?n?zna?P84HvHE%WGTeE9eMlWW39`d0NLHT=bKG^_@0#R{A1~IWcRPx?lJxI>R;VY z-QU$Q`{LvK%8!n}y5U%k+ZJAPDt`B7WcY3lMhv1GmBo!LF_?Oy@i>BIHp`X@HK^2@eA zR_^)O{(N6=hy82y-WXZV7gt~WQ+8X=>2396gVG$cmpn{+g*a4Lm^d39oWKG4#!+G8 zE6F2rEo-Aq1*!$MQ}}X1jz#F3!h{($ouTY0{7(F8tV#S%>mejihar{CiCJee z(fhKUMKjb?<&GiN*KrMPd-XWAKH%e-OnP4UJv zYxqv|Ez@P1IZ@X4H;a+7^{j7mf6pvz;@AFmP?AN6sj`T6?iwXNA@{LrSNZ(X*_dAZb>fFPM|&eIG;FuJ%018<2P3Y z0l@N?bcbf)jJr%0XaP)#@kw|@j~zN zHyJEW=JPf!7UY<{WvXniLxig~P+~(@72AfZK<Ab~q&0a(4s!!faqPuK@X*sXqW1)l99n94c=dUre** zc+-I#c0kQy>HJL6KqZ{j0%eEgTGjy#S@h3hw=IW_6EM6uM1Up%4UGP#utAxL5m-PF d3wC|ww@z#_YWe&eSe!60c)I$ztaD0e0sw3q-EIH? literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png b/tests/TestFiles/Direct2D1/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..db493fa9e7dd9c47e80815f631306a23c59558a1 GIT binary patch literal 3914 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 b@`rQ|59R5@>9skjUsAaQH_|QDb_o9$03GyT literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_150_NoWrap.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..bcda7c59ee3e8cd31a23dab75d52a5fe6fac599c GIT binary patch literal 2830 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 literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_NoWrap.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..0d407ba1ee55da903313c2855ac7faddd09b060e GIT binary patch literal 1077 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yu@pObhHwBu4M$1`0|WCLPZ!6K ziaBp@pAEbnAi{RxwNDp^^;E~Q5(e)eFRcQr#$2le@lz-Gb`^+Cax}c;dgI0O$meG= zCLHZvl=$at^`yVKWrDjkPN*dre>dGA7yoP@Lxd4yV@rd>BX5@@wVSuvx*u83sJnd{|%M4 zO^y@XBPBE8_=@@K^A^Q@s!92y_G^0FcEOJq-u%yvlb2iF7N=6PX?nw-j{o;Bh_7|* z58R(vezr_H|9#}6gg@V}{aD`od28s}Vq25-t5-A&o_)V=R;_%4!Oqwt@7CQcTl-cs zX?yOs_i^`M>)-xYe*Nr?Z~uTY=MVneCVTu_^p<~rA8!16{_oc_Kb9x8?&FiK5dV6{ zuq}7b+==UEC%?0wad|=Y1g%%9Hv&Shc(2*}e8v2*ueP157V$Y-H~dbGxw_|{SpNKq zgE!b%pBTN8TvFRVsaCJh;-Av1-xKV@1MN@k&5~Vh)tCCb!7!&LQt;Q=f0i6NGaDS7 z92684CI|?4aB!%6aa35y&(wKydc-dUotbuEfyMkxe<9+WwE`Y5njMn9op($)$-*MU z#KZ{>b)X4AT_D*r`;J^+%)2x_+G;C*Oa-2BvCF7Kug8HS!jeJ!muMKwaA1VZjq;;Au()yC& zrLLfSX|d+~-`kacZhC}d5{C-ZVU~?{Cw>Y~V0zi?a~tl7uYrDHuQMNFR6KVzi$apE)5*M zKD&KZZCScf5*~I2J113{FdfR0xx83VAnfU4TPeoGiPJ6tIcW>snPt6RUwqNL!NdFI z#fYSh7NI)J-IWz|&H=T&bDl9pU;B`xAlO)hBMmHT1tJt`1uEL@IMN;ETS70hHv--D zf%A*w0(ViM$GzoSu3lnqG*&|MU}DiPg$)ism3*}V=bG#|Rxjgc0*257VPMqtYXNmn o2Z}A_XG(W*0A^@nLBrKw?DcQkzqqD8=mF{RboFyt=akR{0P~W#ssI20 literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png b/tests/TestFiles/Skia/Controls/TextBlock/Should_Measure_Arrange_TextBlock_44_Wrap.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..39f21bd8077ee561340f0ddacc8794267e048881 GIT binary patch literal 2880 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 literal 0 HcmV?d00001