Browse Source
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
pull/19511/head
Benedikt Stebner
6 months ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with
32 additions and
15 deletions
src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs
BIN
tests/Avalonia.RenderTests/Assets/NotoSansMiao-Regular.ttf
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs
@ -115,21 +115,13 @@ namespace Avalonia.Media.TextFormatting
var codepoint = Codepoint . ReplacementCodepoint ;
var codepointEnumerator = new Codepoint Enumerator( text . Slice ( count ) . Span ) ;
var graphemeEnumerator = new Grapheme Enumerator( text . Slice ( count ) . Span ) ;
while ( codepoint Enumerator. MoveNext ( out var cp ) )
if ( grapheme Enumerator. MoveNext ( out var grapheme ) )
{
if ( cp . IsWhiteSpace )
{
continue ;
}
codepoint = cp ;
break ;
codepoint = grapheme . FirstCodepoint ;
}
//ToDo: Fix FontFamily fallback
var matchFound =
fontManager . TryMatchCharacter ( codepoint , defaultTypeface . Style , defaultTypeface . Weight ,
defaultTypeface . Stretch , defaultTypeface . FontFamily , defaultProperties . CultureInfo ,
@ -151,7 +143,8 @@ namespace Avalonia.Media.TextFormatting
// no fallback found
var enumerator = new GraphemeEnumerator ( textSpan ) ;
while ( enumerator . MoveNext ( out var grapheme ) )
//Move forward until we reach the next base character
while ( enumerator . MoveNext ( out grapheme ) )
{
if ( ! grapheme . FirstCodepoint . IsWhiteSpace & & defaultGlyphTypeface . TryGetGlyph ( grapheme . FirstCodepoint , out _ ) )
{
@ -128,10 +128,8 @@ namespace Avalonia.Media.TextFormatting.Unicode
{
const ulong whiteSpaceMask =
( 1 UL < < ( int ) GeneralCategory . Control ) |
( 1 UL < < ( int ) GeneralCategory . NonspacingMark ) |
( 1 UL < < ( int ) GeneralCategory . Format ) |
( 1 UL < < ( int ) GeneralCategory . SpaceSeparator ) |
( 1 UL < < ( int ) GeneralCategory . SpacingMark ) ;
( 1 UL < < ( int ) GeneralCategory . SpaceSeparator ) ;
return ( ( 1 UL < < ( int ) GeneralCategory ) & whiteSpaceMask ) ! = 0 UL ;
}
@ -1088,6 +1088,32 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
}
}
[Fact]
public void Should_MatchCharacter_For_Spacing_CombiningMark ( )
{
using ( Start ( ) )
{
var text = "𖾇" ;
var typeface = new Typeface ( new FontFamily ( new Uri ( "resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests" ) , "Noto Mono" ) ) ;
var defaultRunProperties = new GenericTextRunProperties ( typeface ) ;
var paragraphProperties = new GenericTextParagraphProperties ( defaultRunProperties , textWrapping : TextWrapping . Wrap ) ;
var textLine = TextFormatter . Current . FormatLine ( new SimpleTextSource ( text , defaultRunProperties ) , 0 , 1 2 0 , paragraphProperties ) ;
Assert . NotNull ( textLine ) ;
var textRuns = textLine . TextRuns ;
Assert . NotEmpty ( textRuns ) ;
var firstRun = textRuns [ 0 ] ;
Assert . NotNull ( firstRun . Properties ) ;
Assert . Equal ( "Noto Sans Miao" , firstRun . Properties . Typeface . GlyphTypeface . FamilyName ) ;
}
}
protected readonly record struct SimpleTextSource : ITextSource
{
private readonly string _ text ;