diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml index 998198cc1c..0c4f8249ce 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml @@ -163,6 +163,10 @@ + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs index 300d61f81d..6533c34ba0 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextFormatterImpl.cs @@ -422,7 +422,7 @@ namespace Avalonia.Media.TextFormatting } else { - currentPosition = currentLength + lineBreaker.Current.PositionWrap; + currentPosition = currentLength + measuredLength; } breakFound = true; diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs index 31724bfee9..5cf72e2ce8 100644 --- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs +++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs @@ -87,7 +87,7 @@ namespace Avalonia.Skia { var nextCodepoint = Codepoint.ReadAt(text, i + 1, out _); - if (nextCodepoint == '\r' && codepoint == '\n' || nextCodepoint == '\n' && codepoint == '\r') + if (nextCodepoint == '\n' && codepoint == '\r') { count++; diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 05dd32b84d..97af874238 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs @@ -401,6 +401,24 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting Assert.Equal(expectedOffset, textLine.Start); } } + + [Fact] + public void Should_FormatLine_With_Emergency_Breaks() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + var paragraphProperties = new GenericTextParagraphProperties(defaultProperties, textWrap: TextWrapping.Wrap); + + var textSource = new SingleBufferTextSource("0123456789_0123456789_0123456789_0123456789", defaultProperties); + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, 33, paragraphProperties); + + Assert.NotNull(textLine.TextLineBreak?.RemainingCharacters); + } + } public static IDisposable Start() { diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs new file mode 100644 index 0000000000..62d2c54ffe --- /dev/null +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextShaperTests.cs @@ -0,0 +1,43 @@ +using System; +using System.Globalization; +using Avalonia.Media; +using Avalonia.Media.TextFormatting; +using Avalonia.UnitTests; +using Xunit; + +namespace Avalonia.Skia.UnitTests.Media.TextFormatting +{ + public class TextShaperTests + { + [Fact] + public void Should_Form_Clusters_For_BreakPairs() + { + using (Start()) + { + var text = "\n\r\n".AsMemory(); + + var glyphRun = TextShaper.Current.ShapeText( + text, + Typeface.Default, + 12, + CultureInfo.CurrentCulture); + + Assert.Equal(glyphRun.Characters.Length, text.Length); + Assert.Equal(glyphRun.GlyphClusters.Length, text.Length); + Assert.Equal(0, glyphRun.GlyphClusters[0]); + Assert.Equal(1, glyphRun.GlyphClusters[1]); + Assert.Equal(1, glyphRun.GlyphClusters[2]); + } + } + + private static IDisposable Start() + { + var disposable = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface + .With(renderInterface: new PlatformRenderInterface(null), + textShaperImpl: new TextShaperImpl(), + fontManagerImpl: new CustomFontManagerImpl())); + + return disposable; + } + } +}