@@ -14,6 +14,9 @@ namespace Avalonia.Skia
14
14
{
15
15
internal class TextShaperImpl : ITextShaperImpl
16
16
{
17
+ [ ThreadStatic ]
18
+ private static Buffer ? s_buffer ;
19
+
17
20
private static readonly ConcurrentDictionary < int , Language > s_cachedLanguage = new ( ) ;
18
21
19
22
public ShapedBuffer ShapeText ( ReadOnlyMemory < char > text , TextShaperOptions options )
@@ -24,69 +27,70 @@ public ShapedBuffer ShapeText(ReadOnlyMemory<char> text, TextShaperOptions optio
24
27
var bidiLevel = options . BidiLevel ;
25
28
var culture = options . Culture ;
26
29
27
- using ( var buffer = new Buffer ( ) )
28
- {
29
- // HarfBuzz needs the surrounding characters to correctly shape the text
30
- var containingText = GetContainingMemory ( text , out var start , out var length ) . Span ;
31
- buffer . AddUtf16 ( containingText , start , length ) ;
30
+ var buffer = s_buffer ??= new Buffer ( ) ;
32
31
33
- MergeBreakPair ( buffer ) ;
32
+ buffer . Reset ( ) ;
34
33
35
- buffer . GuessSegmentProperties ( ) ;
34
+ // HarfBuzz needs the surrounding characters to correctly shape the text
35
+ var containingText = GetContainingMemory ( text , out var start , out var length ) . Span ;
36
+ buffer . AddUtf16 ( containingText , start , length ) ;
36
37
37
- buffer . Direction = ( bidiLevel & 1 ) == 0 ? Direction . LeftToRight : Direction . RightToLeft ;
38
+ MergeBreakPair ( buffer ) ;
38
39
39
- var usedCulture = culture ?? CultureInfo . CurrentCulture ;
40
+ buffer . GuessSegmentProperties ( ) ;
40
41
41
- buffer . Language = s_cachedLanguage . GetOrAdd ( usedCulture . LCID , _ => new Language ( usedCulture ) ) ;
42
+ buffer . Direction = ( bidiLevel & 1 ) == 0 ? Direction . LeftToRight : Direction . RightToLeft ;
42
43
43
- var font = ( ( GlyphTypefaceImpl ) typeface ) . Font ;
44
+ var usedCulture = culture ?? CultureInfo . CurrentCulture ;
44
45
45
- font . Shape ( buffer , GetFeatures ( options ) ) ;
46
+ buffer . Language = s_cachedLanguage . GetOrAdd ( usedCulture . LCID , _ => new Language ( usedCulture ) ) ;
46
47
47
- if ( buffer . Direction == Direction . RightToLeft )
48
- {
49
- buffer . Reverse ( ) ;
50
- }
48
+ var font = ( ( GlyphTypefaceImpl ) typeface ) . Font ;
51
49
52
- font . GetScale ( out var scaleX , out _ ) ;
50
+ font . Shape ( buffer , GetFeatures ( options ) ) ;
53
51
54
- var textScale = fontRenderingEmSize / scaleX ;
52
+ if ( buffer . Direction == Direction . RightToLeft )
53
+ {
54
+ buffer . Reverse ( ) ;
55
+ }
55
56
56
- var bufferLength = buffer . Length ;
57
+ font . GetScale ( out var scaleX , out _ ) ;
57
58
58
- var shapedBuffer = new ShapedBuffer ( text , bufferLength , typeface , fontRenderingEmSize , bidiLevel ) ;
59
+ var textScale = fontRenderingEmSize / scaleX ;
59
60
60
- var glyphInfos = buffer . GetGlyphInfoSpan ( ) ;
61
+ var bufferLength = buffer . Length ;
61
62
62
- var glyphPositions = buffer . GetGlyphPositionSpan ( ) ;
63
+ var shapedBuffer = new ShapedBuffer ( text , bufferLength , typeface , fontRenderingEmSize , bidiLevel ) ;
63
64
64
- for ( var i = 0 ; i < bufferLength ; i ++ )
65
- {
66
- var sourceInfo = glyphInfos [ i ] ;
65
+ var glyphInfos = buffer . GetGlyphInfoSpan ( ) ;
67
66
68
- var glyphIndex = ( ushort ) sourceInfo . Codepoint ;
67
+ var glyphPositions = buffer . GetGlyphPositionSpan ( ) ;
69
68
70
- var glyphCluster = ( int ) sourceInfo . Cluster ;
69
+ for ( var i = 0 ; i < bufferLength ; i ++ )
70
+ {
71
+ var sourceInfo = glyphInfos [ i ] ;
71
72
72
- var glyphAdvance = GetGlyphAdvance ( glyphPositions , i , textScale ) + options . LetterSpacing ;
73
+ var glyphIndex = ( ushort ) sourceInfo . Codepoint ;
73
74
74
- var glyphOffset = GetGlyphOffset ( glyphPositions , i , textScale ) ;
75
+ var glyphCluster = ( int ) sourceInfo . Cluster ;
75
76
76
- if ( glyphCluster < containingText . Length && containingText [ glyphCluster ] == '\t ' )
77
- {
78
- glyphIndex = typeface . GetGlyph ( ' ' ) ;
77
+ var glyphAdvance = GetGlyphAdvance ( glyphPositions , i , textScale ) + options . LetterSpacing ;
79
78
80
- glyphAdvance = options . IncrementalTabWidth > 0 ?
81
- options . IncrementalTabWidth :
82
- 4 * typeface . GetGlyphAdvance ( glyphIndex ) * textScale ;
83
- }
79
+ var glyphOffset = GetGlyphOffset ( glyphPositions , i , textScale ) ;
84
80
85
- shapedBuffer [ i ] = new Media . TextFormatting . GlyphInfo ( glyphIndex , glyphCluster , glyphAdvance , glyphOffset ) ;
81
+ if ( glyphCluster < containingText . Length && containingText [ glyphCluster ] == '\t ' )
82
+ {
83
+ glyphIndex = typeface . GetGlyph ( ' ' ) ;
84
+
85
+ glyphAdvance = options . IncrementalTabWidth > 0 ?
86
+ options . IncrementalTabWidth :
87
+ 4 * typeface . GetGlyphAdvance ( glyphIndex ) * textScale ;
86
88
}
87
89
88
- return shapedBuffer ;
90
+ shapedBuffer [ i ] = new Media . TextFormatting . GlyphInfo ( glyphIndex , glyphCluster , glyphAdvance , glyphOffset ) ;
89
91
}
92
+
93
+ return shapedBuffer ;
90
94
}
91
95
92
96
private static void MergeBreakPair ( Buffer buffer )
0 commit comments