Exemplo n.º 1
0
        public ShapedBuffer ShapeText(ReadOnlySlice <char> text, TextShaperOptions options)
        {
            var typeface            = options.Typeface;
            var fontRenderingEmSize = options.FontRenderingEmSize;
            var bidiLevel           = options.BidLevel;
            var culture             = options.Culture;

            using (var buffer = new Buffer())
            {
                buffer.AddUtf16(text.Buffer.Span, text.Start, text.Length);

                MergeBreakPair(buffer);

                buffer.GuessSegmentProperties();

                buffer.Direction = (bidiLevel & 1) == 0 ? Direction.LeftToRight : Direction.RightToLeft;

                buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);

                var font = ((HarfBuzzGlyphTypefaceImpl)typeface.PlatformImpl).Font;

                font.Shape(buffer);

                if (buffer.Direction == Direction.RightToLeft)
                {
                    buffer.Reverse();
                }

                font.GetScale(out var scaleX, out _);

                var textScale = fontRenderingEmSize / scaleX;

                var bufferLength = buffer.Length;

                var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);

                var glyphInfos = buffer.GetGlyphInfoSpan();

                var glyphPositions = buffer.GetGlyphPositionSpan();

                for (var i = 0; i < bufferLength; i++)
                {
                    var sourceInfo = glyphInfos[i];

                    var glyphIndex = (ushort)sourceInfo.Codepoint;

                    var glyphCluster = (int)sourceInfo.Cluster;

                    var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale);

                    var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale);

                    var targetInfo = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);

                    shapedBuffer[i] = targetInfo;
                }

                return(shapedBuffer);
            }
        }
Exemplo n.º 2
0
        public new Result Shape(string text, float xOffset, float yOffset, SKPaint paint)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(new Result());
            }

            using var buffer = new Buffer();
            switch (paint.TextEncoding)
            {
            case SKTextEncoding.Utf8:
                buffer.AddUtf8(text);
                break;

            case SKTextEncoding.Utf16:
                buffer.AddUtf16(text);
                break;

            case SKTextEncoding.Utf32:
                buffer.AddUtf32(text);
                break;

            default:
                throw new NotSupportedException("TextEncoding of type GlyphId is not supported.");
            }

            buffer.GuessSegmentProperties();
            return(Shape(buffer, xOffset, yOffset, paint));
        }
Exemplo n.º 3
0
        public void ShouldNormalize()
        {
            using (var typeface = SKTypeface.FromFile(Path.Combine(PathToFonts, "content-font.ttf")))
                using (var blob = typeface.OpenStream(out var index).ToHarfBuzzBlob())
                    using (var face = new Face(blob, index))
                        using (var font = new Font(face))
                            using (var buffer = new Buffer())
                            {
                                buffer.AddUtf16("Â̶");

                                font.Shape(buffer);

                                buffer.NormalizeGlyphs();

                                Assert.Equal(1027, buffer.GlyphPositions[1].YOffset);
                            }
        }
Exemplo n.º 4
0
        public void ShouldSerializeGlyphs()
        {
            using (var typeface = SKTypeface.FromFile(Path.Combine(PathToFonts, "content-font.ttf")))
                using (var blob = typeface.OpenStream(out var index).ToHarfBuzzBlob())
                    using (var face = new Face(blob, index))
                        using (var font = new Font(face))
                            using (var buffer = new Buffer())
                            {
                                buffer.AddUtf16(SimpleText);

                                buffer.GuessSegmentProperties();

                                font.Shape(buffer);

                                var serializedGlyphs = buffer.SerializeGlyphs();

                                Assert.Equal(SerializedSimpleText, serializedGlyphs);
                            }
        }
Exemplo n.º 5
0
        public void ShouldAddUtfBySpan()
        {
            using (var buffer = new Buffer())
            {
                var utf8 = Encoding.UTF8.GetBytes("A").AsSpan();

                buffer.AddUtf8(utf8);

                Assert.Equal(1, buffer.Length);

                var utf16 = "B".AsSpan();

                buffer.AddUtf16(utf16);

                Assert.Equal(2, buffer.Length);

                var utf32 = new[] { char.ConvertToUtf32("C", 0) };

                buffer.AddUtf32(utf32);

                Assert.Equal(3, buffer.Length);
            }
        }
Exemplo n.º 6
0
        public GlyphRun ShapeText(ReadOnlySlice <char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture)
        {
            using (var buffer = new Buffer())
            {
                buffer.ContentType = ContentType.Unicode;

                var breakCharPosition = text.Length - 1;

                var codepoint = Codepoint.ReadAt(text, breakCharPosition, out var count);

                if (codepoint.IsBreakChar)
                {
                    var breakCharCount = 1;

                    if (text.Length > 1)
                    {
                        var previousCodepoint = Codepoint.ReadAt(text, breakCharPosition - count, out _);

                        if (codepoint == '\r' && previousCodepoint == '\n' ||
                            codepoint == '\n' && previousCodepoint == '\r')
                        {
                            breakCharCount = 2;
                        }
                    }

                    if (breakCharPosition != text.Start)
                    {
                        buffer.AddUtf16(text.Buffer.Span.Slice(0, text.Length - breakCharCount));
                    }

                    var cluster = buffer.GlyphInfos.Length > 0 ?
                                  buffer.GlyphInfos[buffer.Length - 1].Cluster + 1 :
                                  (uint)text.Start;

                    switch (breakCharCount)
                    {
                    case 1:
                        buffer.Add('\u200C', cluster);
                        break;

                    case 2:
                        buffer.Add('\u200C', cluster);
                        buffer.Add('\u200D', cluster);
                        break;
                    }
                }
                else
                {
                    buffer.AddUtf16(text.Buffer.Span);
                }

                buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);

                buffer.GuessSegmentProperties();

                var glyphTypeface = typeface.GlyphTypeface;

                var font = ((GlyphTypefaceImpl)glyphTypeface.PlatformImpl).Font;

                font.Shape(buffer);

                font.GetScale(out var scaleX, out _);

                var textScale = fontRenderingEmSize / scaleX;

                var bufferLength = buffer.Length;

                var glyphInfos = buffer.GetGlyphInfoSpan();

                var glyphPositions = buffer.GetGlyphPositionSpan();

                var glyphIndices = new ushort[bufferLength];

                var clusters = new ushort[bufferLength];

                double[] glyphAdvances = null;

                Vector[] glyphOffsets = null;

                for (var i = 0; i < bufferLength; i++)
                {
                    glyphIndices[i] = (ushort)glyphInfos[i].Codepoint;

                    clusters[i] = (ushort)(text.Start + glyphInfos[i].Cluster);

                    if (!glyphTypeface.IsFixedPitch)
                    {
                        SetAdvance(glyphPositions, i, textScale, ref glyphAdvances);
                    }

                    SetOffset(glyphPositions, i, textScale, ref glyphOffsets);
                }

                return(new GlyphRun(glyphTypeface, fontRenderingEmSize,
                                    new ReadOnlySlice <ushort>(glyphIndices),
                                    new ReadOnlySlice <double>(glyphAdvances),
                                    new ReadOnlySlice <Vector>(glyphOffsets),
                                    text,
                                    new ReadOnlySlice <ushort>(clusters)));
            }
        }
Exemplo n.º 7
0
        public ShapedBuffer ShapeText(ReadOnlySlice <char> text, TextShaperOptions options)
        {
            var typeface            = options.Typeface;
            var fontRenderingEmSize = options.FontRenderingEmSize;
            var bidiLevel           = options.BidLevel;
            var culture             = options.Culture;

            using (var buffer = new Buffer())
            {
                buffer.AddUtf16(text.Buffer.Span, text.BufferOffset, text.Length);

                MergeBreakPair(buffer);

                buffer.GuessSegmentProperties();

                buffer.Direction = Direction.LeftToRight; //Always shape LeftToRight

                buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);

                var font = ((GlyphTypefaceImpl)typeface.PlatformImpl).Font;

                font.Shape(buffer);

                font.GetScale(out var scaleX, out _);

                var textScale = fontRenderingEmSize / scaleX;

                var bufferLength = buffer.Length;

                var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel);

                var glyphInfos = buffer.GetGlyphInfoSpan();

                var glyphPositions = buffer.GetGlyphPositionSpan();

                for (var i = 0; i < bufferLength; i++)
                {
                    var sourceInfo = glyphInfos[i];

                    var glyphIndex = (ushort)sourceInfo.Codepoint;

                    var glyphCluster = (int)(sourceInfo.Cluster);

                    var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale);

                    var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale);

                    if (glyphIndex == 0 && text.Buffer.Span[glyphCluster] == '\t')
                    {
                        glyphIndex = typeface.GetGlyph(' ');

                        glyphAdvance = options.IncrementalTabWidth > 0 ?
                                       options.IncrementalTabWidth :
                                       4 * typeface.GetGlyphAdvance(glyphIndex) * textScale;
                    }

                    var targetInfo = new Avalonia.Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset);

                    shapedBuffer[i] = targetInfo;
                }

                return(shapedBuffer);
            }
        }
Exemplo n.º 8
0
        public GlyphRun ShapeText(ReadOnlySlice <char> text, TextFormat textFormat)
        {
            using (var buffer = new Buffer())
            {
                buffer.ContentType = ContentType.Unicode;

                var breakCharPosition = text.Length - 1;

                var codepoint = Codepoint.ReadAt(text, breakCharPosition, out var count);

                if (codepoint.IsBreakChar)
                {
                    var breakCharCount = 1;

                    if (text.Length > 1)
                    {
                        var previousCodepoint = Codepoint.ReadAt(text, breakCharPosition - count, out _);

                        if (codepoint == '\r' && previousCodepoint == '\n' ||
                            codepoint == '\n' && previousCodepoint == '\r')
                        {
                            breakCharCount = 2;
                        }
                    }

                    if (breakCharPosition != text.Start)
                    {
                        buffer.AddUtf16(text.Buffer.Span.Slice(0, text.Length - breakCharCount));
                    }

                    var cluster = buffer.GlyphInfos.Length > 0 ?
                                  buffer.GlyphInfos[buffer.Length - 1].Cluster + 1 :
                                  (uint)text.Start;

                    switch (breakCharCount)
                    {
                    case 1:
                        buffer.Add('\u200C', cluster);
                        break;

                    case 2:
                        buffer.Add('\u200C', cluster);
                        buffer.Add('\u200D', cluster);
                        break;
                    }
                }
                else
                {
                    buffer.AddUtf16(text.Buffer.Span);
                }

                buffer.GuessSegmentProperties();

                var glyphTypeface = textFormat.Typeface.GlyphTypeface;

                var font = ((GlyphTypefaceImpl)glyphTypeface.PlatformImpl).Font;

                font.Shape(buffer);

                font.GetScale(out var scaleX, out _);

                var textScale = textFormat.FontRenderingEmSize / scaleX;

                var len = buffer.Length;

                var info = buffer.GetGlyphInfoSpan();

                var pos = buffer.GetGlyphPositionSpan();

                var glyphIndices = new ushort[len];

                var clusters = new ushort[len];

                var glyphAdvances = new double[len];

                var glyphOffsets = new Vector[len];

                for (var i = 0; i < len; i++)
                {
                    glyphIndices[i] = (ushort)info[i].Codepoint;

                    clusters[i] = (ushort)(text.Start + info[i].Cluster);

                    var advanceX = pos[i].XAdvance * textScale;
                    // Depends on direction of layout
                    //var advanceY = pos[i].YAdvance * textScale;

                    glyphAdvances[i] = advanceX;

                    var offsetX = pos[i].XOffset * textScale;
                    var offsetY = pos[i].YOffset * textScale;

                    glyphOffsets[i] = new Vector(offsetX, offsetY);
                }

                return(new GlyphRun(glyphTypeface, textFormat.FontRenderingEmSize,
                                    new ReadOnlySlice <ushort>(glyphIndices),
                                    new ReadOnlySlice <double>(glyphAdvances),
                                    new ReadOnlySlice <Vector>(glyphOffsets),
                                    text,
                                    new ReadOnlySlice <ushort>(clusters)));
            }
        }