|
|
|
@ -1,6 +1,5 @@ |
|
|
|
using System; |
|
|
|
using System.Globalization; |
|
|
|
using Avalonia.Media; |
|
|
|
using Avalonia.Media.TextFormatting; |
|
|
|
using Avalonia.Media.TextFormatting.Unicode; |
|
|
|
using Avalonia.Platform; |
|
|
|
@ -11,8 +10,7 @@ using GlyphInfo = HarfBuzzSharp.GlyphInfo; |
|
|
|
|
|
|
|
namespace Avalonia.Direct2D1.Media |
|
|
|
{ |
|
|
|
|
|
|
|
internal class TextShaperImpl : ITextShaperImpl |
|
|
|
internal class TextShaperImpl : ITextShaperImpl |
|
|
|
{ |
|
|
|
public ShapedBuffer ShapeText(ReadOnlySlice<char> text, TextShaperOptions options) |
|
|
|
{ |
|
|
|
@ -23,25 +21,20 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
|
|
|
|
using (var buffer = new Buffer()) |
|
|
|
{ |
|
|
|
buffer.AddUtf16(text.Buffer.Span, text.Start, text.Length); |
|
|
|
buffer.AddUtf16(text.Buffer.Span, text.BufferOffset, text.Length); |
|
|
|
|
|
|
|
MergeBreakPair(buffer); |
|
|
|
|
|
|
|
|
|
|
|
buffer.GuessSegmentProperties(); |
|
|
|
|
|
|
|
buffer.Direction = (bidiLevel & 1) == 0 ? Direction.LeftToRight : Direction.RightToLeft; |
|
|
|
buffer.Direction = Direction.LeftToRight; //Always shape LeftToRight
|
|
|
|
|
|
|
|
buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture); |
|
|
|
buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture); |
|
|
|
|
|
|
|
var font = ((GlyphTypefaceImpl)typeface.PlatformImpl).Font; |
|
|
|
|
|
|
|
font.Shape(buffer); |
|
|
|
|
|
|
|
if (buffer.Direction == Direction.RightToLeft) |
|
|
|
{ |
|
|
|
buffer.Reverse(); |
|
|
|
} |
|
|
|
|
|
|
|
font.GetScale(out var scaleX, out _); |
|
|
|
|
|
|
|
var textScale = fontRenderingEmSize / scaleX; |
|
|
|
@ -60,13 +53,13 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
|
|
|
|
var glyphIndex = (ushort)sourceInfo.Codepoint; |
|
|
|
|
|
|
|
var glyphCluster = (int)sourceInfo.Cluster; |
|
|
|
var glyphCluster = (int)(sourceInfo.Cluster); |
|
|
|
|
|
|
|
var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale); |
|
|
|
|
|
|
|
var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale); |
|
|
|
|
|
|
|
if (glyphIndex == 0 && text[glyphCluster] == '\t') |
|
|
|
if (glyphIndex == 0 && text.Buffer.Span[glyphCluster] == '\t') |
|
|
|
{ |
|
|
|
glyphIndex = typeface.GetGlyph(' '); |
|
|
|
|
|
|
|
@ -75,9 +68,7 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
4 * typeface.GetGlyphAdvance(glyphIndex) * textScale; |
|
|
|
} |
|
|
|
|
|
|
|
var targetInfo = |
|
|
|
new Avalonia.Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, |
|
|
|
glyphOffset); |
|
|
|
var targetInfo = new Avalonia.Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset); |
|
|
|
|
|
|
|
shapedBuffer[i] = targetInfo; |
|
|
|
} |
|
|
|
@ -91,7 +82,7 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
var length = buffer.Length; |
|
|
|
|
|
|
|
var glyphInfos = buffer.GetGlyphInfoSpan(); |
|
|
|
|
|
|
|
|
|
|
|
var second = glyphInfos[length - 1]; |
|
|
|
|
|
|
|
if (!new Codepoint((int)second.Codepoint).IsBreakChar) |
|
|
|
@ -102,7 +93,7 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
if (length > 1 && glyphInfos[length - 2].Codepoint == '\r' && second.Codepoint == '\n') |
|
|
|
{ |
|
|
|
var first = glyphInfos[length - 2]; |
|
|
|
|
|
|
|
|
|
|
|
first.Codepoint = '\u200C'; |
|
|
|
second.Codepoint = '\u200C'; |
|
|
|
second.Cluster = first.Cluster; |
|
|
|
@ -113,7 +104,7 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
{ |
|
|
|
*p = first; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fixed (GlyphInfo* p = &glyphInfos[length - 1]) |
|
|
|
{ |
|
|
|
*p = second; |
|
|
|
@ -148,7 +139,7 @@ internal class TextShaperImpl : ITextShaperImpl |
|
|
|
private static double GetGlyphAdvance(ReadOnlySpan<GlyphPosition> glyphPositions, int index, double textScale) |
|
|
|
{ |
|
|
|
// Depends on direction of layout
|
|
|
|
// advanceBuffer[index] = buffer.GlyphPositions[index].YAdvance * textScale;
|
|
|
|
// glyphPositions[index].YAdvance * textScale;
|
|
|
|
return glyphPositions[index].XAdvance * textScale; |
|
|
|
} |
|
|
|
} |
|
|
|
|