Browse Source

Reuse single HarfBuzz buffer in TextShaperImpl (#18892)

release/11.3.1
Compunet 8 months ago
committed by Julien Lebosquain
parent
commit
d05393d3aa
  1. 80
      src/Skia/Avalonia.Skia/TextShaperImpl.cs

80
src/Skia/Avalonia.Skia/TextShaperImpl.cs

@ -14,6 +14,9 @@ namespace Avalonia.Skia
{
internal class TextShaperImpl : ITextShaperImpl
{
[ThreadStatic]
private static Buffer? s_buffer;
private static readonly ConcurrentDictionary<int, Language> s_cachedLanguage = new();
public ShapedBuffer ShapeText(ReadOnlyMemory<char> text, TextShaperOptions options)
@ -24,69 +27,70 @@ namespace Avalonia.Skia
var bidiLevel = options.BidiLevel;
var culture = options.Culture;
using (var buffer = new Buffer())
{
// HarfBuzz needs the surrounding characters to correctly shape the text
var containingText = GetContainingMemory(text, out var start, out var length).Span;
buffer.AddUtf16(containingText, start, length);
var buffer = s_buffer ??= new Buffer();
MergeBreakPair(buffer);
buffer.Reset();
buffer.GuessSegmentProperties();
// HarfBuzz needs the surrounding characters to correctly shape the text
var containingText = GetContainingMemory(text, out var start, out var length).Span;
buffer.AddUtf16(containingText, start, length);
buffer.Direction = (bidiLevel & 1) == 0 ? Direction.LeftToRight : Direction.RightToLeft;
MergeBreakPair(buffer);
var usedCulture = culture ?? CultureInfo.CurrentCulture;
buffer.GuessSegmentProperties();
buffer.Language = s_cachedLanguage.GetOrAdd(usedCulture.LCID, _ => new Language(usedCulture));
buffer.Direction = (bidiLevel & 1) == 0 ? Direction.LeftToRight : Direction.RightToLeft;
var font = ((GlyphTypefaceImpl)typeface).Font;
var usedCulture = culture ?? CultureInfo.CurrentCulture;
font.Shape(buffer, GetFeatures(options));
buffer.Language = s_cachedLanguage.GetOrAdd(usedCulture.LCID, _ => new Language(usedCulture));
if (buffer.Direction == Direction.RightToLeft)
{
buffer.Reverse();
}
var font = ((GlyphTypefaceImpl)typeface).Font;
font.GetScale(out var scaleX, out _);
font.Shape(buffer, GetFeatures(options));
var textScale = fontRenderingEmSize / scaleX;
if (buffer.Direction == Direction.RightToLeft)
{
buffer.Reverse();
}
var bufferLength = buffer.Length;
font.GetScale(out var scaleX, out _);
var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);
var textScale = fontRenderingEmSize / scaleX;
var glyphInfos = buffer.GetGlyphInfoSpan();
var bufferLength = buffer.Length;
var glyphPositions = buffer.GetGlyphPositionSpan();
var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);
for (var i = 0; i < bufferLength; i++)
{
var sourceInfo = glyphInfos[i];
var glyphInfos = buffer.GetGlyphInfoSpan();
var glyphIndex = (ushort)sourceInfo.Codepoint;
var glyphPositions = buffer.GetGlyphPositionSpan();
var glyphCluster = (int)sourceInfo.Cluster;
for (var i = 0; i < bufferLength; i++)
{
var sourceInfo = glyphInfos[i];
var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale) + options.LetterSpacing;
var glyphIndex = (ushort)sourceInfo.Codepoint;
var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale);
var glyphCluster = (int)sourceInfo.Cluster;
if (glyphCluster < containingText.Length && containingText[glyphCluster] == '\t')
{
glyphIndex = typeface.GetGlyph(' ');
var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale) + options.LetterSpacing;
glyphAdvance = options.IncrementalTabWidth > 0 ?
options.IncrementalTabWidth :
4 * typeface.GetGlyphAdvance(glyphIndex) * textScale;
}
var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale);
shapedBuffer[i] = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);
if (glyphCluster < containingText.Length && containingText[glyphCluster] == '\t')
{
glyphIndex = typeface.GetGlyph(' ');
glyphAdvance = options.IncrementalTabWidth > 0 ?
options.IncrementalTabWidth :
4 * typeface.GetGlyphAdvance(glyphIndex) * textScale;
}
return shapedBuffer;
shapedBuffer[i] = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);
}
return shapedBuffer;
}
private static void MergeBreakPair(Buffer buffer)

Loading…
Cancel
Save