From 265518859a228584d92e8de79571c54cdd47bef9 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Mon, 3 May 2021 07:34:10 +0200 Subject: [PATCH 1/3] Fix text tokenization for inherited scripts --- .../Media/TextFormatting/TextCharacters.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs index c6f524451b..86b96b9cfc 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs @@ -161,30 +161,27 @@ namespace Avalonia.Media.TextFormatting if (currentScript != script) { - if (currentScript != Script.Inherited && currentScript != Script.Common) + if (script == Script.Inherited || script == Script.Common) { - if (script == Script.Inherited || script == Script.Common) - { - script = currentScript; - } - else + script = currentScript; + } + else + { + if (currentScript != Script.Inherited && currentScript != Script.Common) { break; } } } - if (isFallback) + if (currentScript != Script.Common && currentScript != Script.Inherited) { - if (defaultFont.TryGetGlyph(grapheme.FirstCodepoint, out _)) + if (isFallback && defaultFont.TryGetGlyph(grapheme.FirstCodepoint, out _)) { break; } - } - if (!font.TryGetGlyph(grapheme.FirstCodepoint, out _)) - { - if (!grapheme.FirstCodepoint.IsWhiteSpace) + if (!font.TryGetGlyph(grapheme.FirstCodepoint, out _)) { break; } From d64a66d441ad9846065c426ddef61800af22950b Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Fri, 14 May 2021 11:17:45 +0200 Subject: [PATCH 2/3] Fix fallback selection --- .../TextFormatting/ShapedTextCharacters.cs | 6 +++-- .../Media/TextFormatting/TextCharacters.cs | 27 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs index 723d5e81ab..b304b19910 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/ShapedTextCharacters.cs @@ -109,7 +109,8 @@ namespace Avalonia.Media.TextFormatting GlyphRun.GlyphAdvances.Take(glyphCount), GlyphRun.GlyphOffsets.Take(glyphCount), GlyphRun.Characters.Take(length), - GlyphRun.GlyphClusters.Take(glyphCount)); + GlyphRun.GlyphClusters.Take(glyphCount), + GlyphRun.BiDiLevel); var firstTextRun = new ShapedTextCharacters(firstGlyphRun, Properties); @@ -120,7 +121,8 @@ namespace Avalonia.Media.TextFormatting GlyphRun.GlyphAdvances.Skip(glyphCount), GlyphRun.GlyphOffsets.Skip(glyphCount), GlyphRun.Characters.Skip(length), - GlyphRun.GlyphClusters.Skip(glyphCount)); + GlyphRun.GlyphClusters.Skip(glyphCount), + GlyphRun.BiDiLevel); var secondTextRun = new ShapedTextCharacters(secondGlyphRun, Properties); diff --git a/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs b/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs index 86b96b9cfc..0779716ec8 100644 --- a/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs +++ b/src/Avalonia.Visuals/Media/TextFormatting/TextCharacters.cs @@ -135,20 +135,20 @@ namespace Avalonia.Media.TextFormatting count = 0; var script = Script.Common; - //var direction = BiDiClass.LeftToRight; + var direction = BiDiClass.LeftToRight; var font = typeface.GlyphTypeface; var defaultFont = defaultTypeface.GlyphTypeface; - + var enumerator = new GraphemeEnumerator(text); while (enumerator.MoveNext()) { - var grapheme = enumerator.Current; + var currentGrapheme = enumerator.Current; - var currentScript = grapheme.FirstCodepoint.Script; + var currentScript = currentGrapheme.FirstCodepoint.Script; - //var currentDirection = grapheme.FirstCodepoint.BiDiClass; + var currentDirection = currentGrapheme.FirstCodepoint.BiDiClass; //// ToDo: Implement BiDi algorithm //if (currentScript.HorizontalDirection != direction) @@ -176,18 +176,29 @@ namespace Avalonia.Media.TextFormatting if (currentScript != Script.Common && currentScript != Script.Inherited) { - if (isFallback && defaultFont.TryGetGlyph(grapheme.FirstCodepoint, out _)) + if (isFallback && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } - if (!font.TryGetGlyph(grapheme.FirstCodepoint, out _)) + if (!font.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } } - count += grapheme.Text.Length; + if (!currentGrapheme.FirstCodepoint.IsWhiteSpace && !font.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) + { + break; + } + + if (direction == BiDiClass.RightToLeft && currentDirection == BiDiClass.CommonSeparator) + { + break; + } + + count += currentGrapheme.Text.Length; + direction = currentDirection; } return count > 0; From 43beabc9b49f92eafd75b00659f83ef75957532d Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Tue, 18 May 2021 16:50:22 +0200 Subject: [PATCH 3/3] Add a unit test --- .../TextFormatting/TextFormatterTests.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 97af874238..9c2a1953f1 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs @@ -125,6 +125,27 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } } + [Fact] + public void Should_Produce_A_Single_Fallback_Run() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + + const string text = "👍 👍 👍 👍"; + + var textSource = new SingleBufferTextSource(text, defaultProperties); + + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + Assert.Equal(1, textLine.TextRuns.Count); + } + } + [Fact] public void Should_Split_Run_On_Script() {