Skip to content

Commit da52b72

Browse files
authored
Do not treat combining marks as whitespace (#19498)
* Do not treat spacing combining marks as whitespace * Do not treat combining marks as whitespace Try to find a matching typeface on a grapheme boundary * Add embedded font for testing * Remove using * Fix naming and remove redundant code * Apply default until we reach the next base character
1 parent f56babb commit da52b72

File tree

4 files changed

+32
-15
lines changed

4 files changed

+32
-15
lines changed

src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,21 +115,13 @@ private static UnshapedTextRun CreateShapeableRun(ReadOnlyMemory<char> text,
115115

116116
var codepoint = Codepoint.ReplacementCodepoint;
117117

118-
var codepointEnumerator = new CodepointEnumerator(text.Slice(count).Span);
118+
var graphemeEnumerator = new GraphemeEnumerator(text.Slice(count).Span);
119119

120-
while (codepointEnumerator.MoveNext(out var cp))
120+
if (graphemeEnumerator.MoveNext(out var grapheme))
121121
{
122-
if (cp.IsWhiteSpace)
123-
{
124-
continue;
125-
}
126-
127-
codepoint = cp;
128-
129-
break;
122+
codepoint = grapheme.FirstCodepoint;
130123
}
131124

132-
//ToDo: Fix FontFamily fallback
133125
var matchFound =
134126
fontManager.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight,
135127
defaultTypeface.Stretch, defaultTypeface.FontFamily, defaultProperties.CultureInfo,
@@ -151,7 +143,8 @@ private static UnshapedTextRun CreateShapeableRun(ReadOnlyMemory<char> text,
151143
// no fallback found
152144
var enumerator = new GraphemeEnumerator(textSpan);
153145

154-
while (enumerator.MoveNext(out var grapheme))
146+
//Move forward until we reach the next base character
147+
while (enumerator.MoveNext(out grapheme))
155148
{
156149
if (!grapheme.FirstCodepoint.IsWhiteSpace && defaultGlyphTypeface.TryGetGlyph(grapheme.FirstCodepoint, out _))
157150
{

src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,8 @@ public bool IsWhiteSpace
128128
{
129129
const ulong whiteSpaceMask =
130130
(1UL << (int)GeneralCategory.Control) |
131-
(1UL << (int)GeneralCategory.NonspacingMark) |
132131
(1UL << (int)GeneralCategory.Format) |
133-
(1UL << (int)GeneralCategory.SpaceSeparator) |
134-
(1UL << (int)GeneralCategory.SpacingMark);
132+
(1UL << (int)GeneralCategory.SpaceSeparator);
135133

136134
return ((1UL << (int)GeneralCategory) & whiteSpaceMask) != 0UL;
137135
}
97.5 KB
Binary file not shown.

tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,32 @@ public void Should_Wrap_Chinese()
10881088
}
10891089
}
10901090

1091+
[Fact]
1092+
public void Should_MatchCharacter_For_Spacing_CombiningMark()
1093+
{
1094+
using (Start())
1095+
{
1096+
var text = "𖾇";
1097+
1098+
var typeface = new Typeface(new FontFamily(new Uri("resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests"), "Noto Mono"));
1099+
var defaultRunProperties = new GenericTextRunProperties(typeface);
1100+
var paragraphProperties = new GenericTextParagraphProperties(defaultRunProperties, textWrapping: TextWrapping.Wrap);
1101+
var textLine = TextFormatter.Current.FormatLine(new SimpleTextSource(text, defaultRunProperties), 0, 120, paragraphProperties);
1102+
1103+
Assert.NotNull(textLine);
1104+
1105+
var textRuns = textLine.TextRuns;
1106+
1107+
Assert.NotEmpty(textRuns);
1108+
1109+
var firstRun = textRuns[0];
1110+
1111+
Assert.NotNull(firstRun.Properties);
1112+
1113+
Assert.Equal("Noto Sans Miao", firstRun.Properties.Typeface.GlyphTypeface.FamilyName);
1114+
}
1115+
}
1116+
10911117
protected readonly record struct SimpleTextSource : ITextSource
10921118
{
10931119
private readonly string _text;

0 commit comments

Comments
 (0)