Example #1
0
        /// <summary>
        /// Draw multiline text in Skia coordinates
        /// </summary>
        /// <param name="canvas">Canvas where text is drawn</param>
        /// <param name="paint">Paint for drawn</param>
        /// <param name="x">Start x coordinate</param>
        /// <param name="y">Start y coordinate</param>
        /// <param name="maxWidth">Max width</param>
        /// <param name="lineHeight">Pre measured line height</param>
        /// <param name="isMultiline">Is text wrapped to multiple lines</param>
        /// <param name="text">Actual text</param>
        public static void DrawTextArea(SKCanvas canvas, SKPaint paint, float x, float y, float maxWidth, float lineHeight, bool isMultiline, string text)
        {
            if (isMultiline)
            {
                var spaceWidth = paint.MeasureText(" ");
                var lines      = text.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                lines = lines.SelectMany(l => SplitLine(paint, maxWidth, l, spaceWidth)).ToArray();

                for (int i = 0; i < lines.Length; i++)
                {
                    var line = lines[i];
                    canvas.DrawText(line, x, y, paint);
                    y += lineHeight;
                }
            }
            else
            {
                long maxCharacters = paint.BreakText(text, maxWidth);

                string actualString = text;

                if (maxCharacters + 1 < text.Count()) // +1 quick and dirty for UWP
                {
                    float dotsWidth = paint.MeasureText("...");

                    maxCharacters = paint.BreakText(text, maxWidth - dotsWidth);

                    actualString  = text.Substring(0, (int)maxCharacters);
                    actualString  = actualString.Trim();
                    actualString += "...";
                }

                canvas.DrawText(actualString, x, y, paint);
            }
        }
Example #2
0
        public void BreakTextSucceedsForNullPointerZeroLength()
        {
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf8;

            Assert.Equal(0, paint.BreakText(IntPtr.Zero, IntPtr.Zero, 50.0f));
            Assert.Equal(0, paint.BreakText(IntPtr.Zero, 0, 50.0f));
        }
Example #3
0
        public void BreakTextThrowsForNullPointer()
        {
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf8;

            Assert.Throws <ArgumentNullException>(() => paint.BreakText(IntPtr.Zero, (IntPtr)123, 50.0f));
            Assert.Throws <ArgumentNullException>(() => paint.BreakText(IntPtr.Zero, 123, 50.0f));
        }
Example #4
0
        public static IntDimension MeasureText(this Font font, string title, float lineWidth)
        {
            using var paint = new SKPaint()
                  {
                      Typeface    = font.ToSkia(),
                      TextSize    = font.Size,
                      IsAntialias = true,
                      Style       = SKPaintStyle.Fill
                  };

            var bounds = new SKRect();

            paint.MeasureText(title, ref bounds);

            var width  = 0f;
            var height = 0f;

            while (true)
            {
                var offset = paint.BreakText(title, lineWidth, out var measuredWidth, out _);
                width   = Math.Max(width, measuredWidth);
                height += bounds.Height;
                if (offset == 0)
                {
                    break;
                }

                title = title.Substring((int)offset);
            }

            return(new IntDimension((int)Math.Ceiling(width), (int)Math.Ceiling(height)));
        }
Example #5
0
        private string[] BreakText(string text, float width)
        {
            var lines = new List <string>();

            var remainder = text;

            while (remainder.Length > 0)
            {
                var lineMax = (int)_skFillPaint.BreakText(remainder, width);
                var lineMin = lineMax * 3 / 4;

                var lineBreak = lineMax;
                if (lineBreak < remainder.Length)
                {
                    lineBreak = remainder.LastIndexOfAny(BREAK_CHARS, lineMax - 1);
                    if (lineBreak < lineMin)
                    {
                        lineBreak = lineMax;
                    }
                    else
                    {
                        lineBreak++;
                    }
                }

                var line = remainder.Substring(0, lineBreak).Trim();
                remainder = remainder.Substring(lineBreak).Trim();

                lines.Add(line);
            }

            return(lines.ToArray());
        }
Example #6
0
        string breakText(string input, SKPaint paint, Brush style)
        {
            var restOfText = input;
            var brokenText = "";

            do
            {
                var lineLength = paint.BreakText(restOfText, (float)(style.Paint.TextMaxWidth * style.Paint.TextSize));

                if (lineLength == restOfText.Length)
                {
                    // its the end
                    brokenText += restOfText.Trim();
                    break;
                }

                var lastSpaceIndex = restOfText.LastIndexOf(' ', (int)(lineLength - 1));
                if (lastSpaceIndex == -1 || lastSpaceIndex == 0)
                {
                    // no more spaces, probably ;)
                    brokenText += restOfText.Trim();
                    break;
                }

                brokenText += restOfText.Substring(0, (int)lastSpaceIndex).Trim() + "\n";

                restOfText = restOfText.Substring((int)lastSpaceIndex, restOfText.Length - (int)lastSpaceIndex);
            } while (restOfText.Length > 0);

            return(brokenText.Trim());
        }
Example #7
0
        public int GetTextPosition(string[] textLines, float x, float y, SKPaint paint)
        {
            int characterPostion = 0;

            string line = string.Empty;

            for (int i = 0; i < textLines.Length; i++)
            {
                line = textLines[i];

                float yOffset = paint.TextSize * (i + 1);

                if (y > yOffset)
                {
                    characterPostion += line.Length;
                }
                else
                {
                    characterPostion += (int)paint.BreakText(line, x);
                    break;
                }

                characterPostion++;
            }

            return(characterPostion);
        }
Example #8
0
        public static void DrawTextLines(this SKCanvas g, string title, Font font, Color brush, IntPoint textOffset, int lineWidth)
        {
            using var paint = new SKPaint()
                  {
                      Typeface    = font.ToSkia(),
                      TextSize    = font.Size,
                      Color       = new SKColor(brush.ToUint32()),
                      IsAntialias = true,
                      Style       = SKPaintStyle.Fill
                  };

            while (true)
            {
                var offset = paint.BreakText(title, lineWidth, out _, out var measuredText);
                g.DrawText(measuredText, new SKPoint(textOffset.X, textOffset.Y + paint.TextSize), paint);
                textOffset = new IntPoint(textOffset.X, textOffset.Y + (int)paint.TextSize);

                if (offset == 0)
                {
                    break;
                }

                title = title.Substring((int)offset);
            }
        }
Example #9
0
        public void BreakTextReturnsTheCorrectNumberOfBytes(SKTextEncoding encoding, string text, int extectedRead)
        {
            var paint = new SKPaint();

            paint.TextEncoding = encoding;

            // get bytes
            var bytes = encoding == SKTextEncoding.GlyphId
                                ? GetGlyphBytes(text)
                                : StringUtilities.GetEncodedText(text, encoding);

            var read = paint.BreakText(bytes, 50.0f, out var measured);

            Assert.Equal(extectedRead, read);
            Assert.True(measured > 0);

            byte[] GetGlyphBytes(string text)
            {
                var glyphs = paint.GetGlyphs(text);
                var bytes  = new byte[Buffer.ByteLength(glyphs)];

                Buffer.BlockCopy(glyphs, 0, bytes, 0, bytes.Length);
                return(bytes);
            }
        }
Example #10
0
        public void BreakTextSucceedsForEmtptyString()
        {
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf8;

            Assert.Equal(0, paint.BreakText("", 50.0f));
        }
Example #11
0
        public void BreakTextHandlesLongText(int textSize)
        {
            var font = new SKPaint();

            if (textSize >= 0)
            {
                font.TextSize = textSize;
            }

            var text = string.Concat(Enumerable.Repeat('a', 1024));

            var width = font.MeasureText(text);

            var length = font.BreakText(text, width, out var mm);

            Assert.Equal(1024, length);
            Assert.Equal(width, mm);
        }
Example #12
0
        private List <TextLine> CreateLines(float y, float bottom, float width)
        {
            var lines = new List <TextLine>();

            var index  = 0;
            var length = _value.Length;

            while (index < length)
            {
                y += _lineHeight;

                if (_textFlow == TextFlow.ClipBounds && _textAttributes.VerticalAlignment == VerticalAlignment.Top && y > bottom)
                {
                    return(lines);
                }

                var count = (int)_paint.BreakText(_value.Substring(index), width, out var textWidth);

                var found = false;
                if (WordWrap && index + count < length)
                {
                    for (var i = index + count - 1; i >= index && !found; i--)
                    {
                        if (char.IsWhiteSpace(_value[i]))
                        {
                            count = i - index + 1;
                            found = true;
                        }
                    }
                }

                var line = _value.Substring(index, count);
                if (found)
                {
                    textWidth = _paint.MeasureText(line);
                }
                lines.Add(new TextLine(line, textWidth));

                index += count;
            }

            return(lines);
        }
Example #13
0
    private static int LineBreak(string text, SKPaint paint, double width)
    {
        int idx = 0, last = 0;
        var lengthBreak = (int)paint.BreakText(text, (float)width);

        while (idx < text.Length)
        {
            var next = text.IndexOfAny(new char[] { ' ', '\n' }, idx);
            if (next == -1)
            {
                if (idx == 0)
                {
                    // Word is too long, we will have to break it
                    return(lengthBreak);
                }
                else
                {
                    // Ellipsize if it's the last line
                    if (lengthBreak == text.Length
                        // || text.IndexOfAny (new char [] { ' ', '\n' }, lengthBreak + 1) == -1
                        )
                    {
                        return(lengthBreak);
                    }
                    // Split at the last word;
                    return(last);
                }
            }
            if (text[idx] == '\n')
            {
                return(idx);
            }
            if (next > lengthBreak)
            {
                return(idx);
            }
            last = next;
            idx  = next + 1;
        }
        return(last);
    }
Example #14
0
        public void BreatTextHasCorrectLogic(int textSize)
        {
            var font = new SKPaint();

            if (textSize >= 0)
            {
                font.TextSize = textSize;
            }

            var text   = "sdfkljAKLDFJKEWkldfjlk#$%&sdfs.dsj";
            var length = text.Length;
            var width  = font.MeasureText(text);

            var mm   = 0f;
            var nn   = 0L;
            var step = Math.Max(width / 10f, 1f);

            for (float w = 0; w <= width; w += step)
            {
                var n = font.BreakText(text, w, out var m);

                Assert.True(n <= length);
                Assert.True(m <= width);

                if (n == 0)
                {
                    Assert.Equal(0, m);
                }
                else if (n == nn)
                {
                    Assert.Equal(mm, m);
                }
                else
                {
                    Assert.True(n > nn);
                    Assert.True(m > mm);
                }
                nn = n;
                mm = m;
            }
        }
Example #15
0
        public void BreakTextWidthIsEqualToMeasureTextWidth(int textSize)
        {
            var font = new SKPaint();

            if (textSize >= 0)
            {
                font.TextSize = textSize;
            }

            var text =
                "The ultimate measure of a man is not where he stands in moments of comfort " +
                "and convenience, but where he stands at times of challenge and controversy.";
            var length = text.Length;

            var width = font.MeasureText(text);

            var length2 = font.BreakText(text, width, out var mm);

            Assert.Equal(length, length2);
            Assert.Equal(width, mm);
        }
Example #16
0
        public void BreakTextReturnsTheCorrectNumberOfCharacters()
        {
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf8;
            Assert.Equal(1, paint.BreakText("ä", 50.0f));
            Assert.Equal(1, paint.BreakText("a", 50.0f));

            paint.TextEncoding = SKTextEncoding.Utf16;
            Assert.Equal(1, paint.BreakText("ä", 50.0f));
            Assert.Equal(1, paint.BreakText("a", 50.0f));

            paint.TextEncoding = SKTextEncoding.Utf32;
            Assert.Equal(1, paint.BreakText("ä", 50.0f));
            Assert.Equal(1, paint.BreakText("a", 50.0f));
        }
Example #17
0
        public void BreakTextReturnsTheCorrectNumberOfBytes()
        {
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf8;

            Assert.Equal(2, paint.BreakText(StringUtilities.GetEncodedText("ä", paint.TextEncoding), 50.0f));
            Assert.Equal(1, paint.BreakText(StringUtilities.GetEncodedText("a", paint.TextEncoding), 50.0f));

            paint.TextEncoding = SKTextEncoding.Utf16;
            Assert.Equal(2, paint.BreakText(StringUtilities.GetEncodedText("ä", paint.TextEncoding), 50.0f));
            Assert.Equal(2, paint.BreakText(StringUtilities.GetEncodedText("a", paint.TextEncoding), 50.0f));

            paint.TextEncoding = SKTextEncoding.Utf32;
            Assert.Equal(4, paint.BreakText(StringUtilities.GetEncodedText("ä", paint.TextEncoding), 50.0f));
            Assert.Equal(4, paint.BreakText(StringUtilities.GetEncodedText("a", paint.TextEncoding), 50.0f));
        }
Example #18
0
        public List <TextLine> SplitLines(SKPaint paint)
        {
            var result = new List <TextLine>();

            var lines = Text.Split(NewLines, StringSplitOptions.None);

            foreach (var line in lines)
            {
                if (_size.X <= 0)
                {
                    var width = (int)paint.MeasureText(line);
                    result.Add(new TextLine(width, line));
                    continue;
                }

                int restLineLength = line.Length;
                var restLineText   = line;
                while (restLineLength > 0)
                {
                    var measuredLength = (int)paint.BreakText(restLineText, _size.X, out float measuredWidth, out string measuredText);

                    restLineLength -= measuredLength;
                    restLineText    = restLineText.Substring(measuredLength, restLineLength);

                    if (measuredWidth > RealWidth)
                    {
                        RealWidth = (int)measuredWidth;
                    }

                    result.Add(new TextLine((int)measuredWidth, measuredText));
                }
            }

            RealHeight = (int)((result.Count * paint.FontSpacing) - paint.FontMetrics.Leading);

            return(result);
        }
Example #19
0
        internal unsafe void Run()
        {
            if (!needRun)
            {
                return;
            }

            lines.Clear();

            //设置paint参数
            var paint = new SKPaint();

            paint.TextEncoding = SKTextEncoding.Utf16;
            font.ApplyToSKPaint(paint, GraphicsUnit.Pixel, dpi); //注意目标类型为像素
            //测量FontMetric
            SKFontMetrics metrics = font.FontMetrics;

            //根据文字排版方向确认限宽及限高
            float maxWidth  = Math.Min(32767, IsVertical ? height : width); //TODO:
            float maxHeight = IsVertical ? width : height;

            //TODO:计算高度不满足一行的情况

            fixed(char *ptr = Text)
            {
                byte *textPtr      = (byte *)ptr;
                byte *startTextPtr = (byte *)ptr;

                int   totalBytes = text.Length * 2;
                int   leftBytes  = totalBytes;
                float y          = 0;

                while (true)
                {
                    //根据是否允许换行,调用不同的breakText方法
                    var measuredWidth = 0f;
                    var lineBytes     = (int)paint.BreakText(new IntPtr(startTextPtr), new IntPtr(leftBytes), maxWidth, out measuredWidth);
                    //var lineBytes = SkiaApi.sk_paint_break_text_icu(paint, new IntPtr(startTextPtr), leftBytes, maxWidth, null); //TODO:***** fix maxWidth

                    var newLine = new TextLayoutLine(this);
                    newLine.startByteIndex = (int)(startTextPtr - textPtr);
                    newLine.byteLength     = lineBytes;
                    newLine.widths         = paint.GetGlyphWidths(new IntPtr(startTextPtr), lineBytes);
                    //newLine.startCharIndex = 0; //TODO:

                    //根据对齐方式计算Line的offsetX值
                    if (stringFormat != null && stringFormat.Alignment != StringAlignment.Near)
                    {
                        //计算当前行Ink总宽度
                        float lineInkWidth = 0f;
                        for (int i = 0; i < newLine.widths.Length; i++)
                        {
                            lineInkWidth += newLine.widths[i];
                        }
                        float lineSpace = width - lineInkWidth;
                        if (lineSpace > 0f)
                        {
                            if (stringFormat.Alignment == StringAlignment.Center)
                            {
                                newLine.offsetX = lineSpace / 2f;
                            }
                            else if (stringFormat.Alignment == StringAlignment.Far)
                            {
                                newLine.offsetX = lineSpace;
                            }
                        }
                    }
                    //添加新行
                    lines.Add(newLine);

                    //判断是否允许换行,不允许直接退出循环
                    if (IsNoWrap)
                    {
                        break;
                    }

                    //计算下一行高度是否超出限高
                    y = y - metrics.Ascent + metrics.Descent + metrics.Leading;
                    if ((y - metrics.Ascent + metrics.Descent) > maxHeight)
                    {
                        break;
                    }

                    //偏移剩余部分,并判断是否全部计算完毕
                    startTextPtr += lineBytes;
                    if ((int)(startTextPtr - textPtr) >= totalBytes)
                    {
                        break;
                    }
                    leftBytes -= lineBytes;
                }
            }

            //根据对齐方式计算offsetY的值
            CalcOffsetY();

            needRun = false;
        }
Example #20
0
        void Rebuild()
        {
            var length = _text.Length;

            _lines.Clear();

            _skiaRects = new SKRect[length];
            _skiaLines = new List <AvaloniaFormattedTextLine>();

            int   curOff = 0;
            float curY   = 0;

            var metrics  = Paint.FontMetrics;
            var mTop     = metrics.Top;     // The greatest distance above the baseline for any glyph (will be <= 0).
            var mBottom  = metrics.Bottom;  // The greatest distance below the baseline for any glyph (will be >= 0).
            var mLeading = metrics.Leading; // The recommended distance to add between lines of text (will be >= 0).

            // This seems like the best measure of full vertical extent
            float lineHeight = mBottom - mTop;

            // Rendering is relative to baseline
            LineOffset = -metrics.Top;

            string subString;

            byte[]   bytes;
            GCHandle pinnedArray;
            IntPtr   pointer;

            for (int c = 0; curOff < length; c++)
            {
                float lineWidth = -1;
                int   measured;
                int   extraSkip = 0;
                if (WidthConstraint <= 0)
                {
                    measured = length;
                }
                else
                {
                    float constraint = WidthConstraint;
                    if (constraint > MAX_LINE_WIDTH)
                    {
                        constraint = MAX_LINE_WIDTH;
                    }

                    subString = _text.Substring(curOff);

                    // TODO: This method is not linking into SkiaSharp so we must use the RAW buffer version for now
                    //measured = (int)Paint.BreakText(subString, constraint, out lineWidth) / 2;
                    bytes       = Encoding.UTF8.GetBytes(subString);
                    pinnedArray = GCHandle.Alloc(bytes, GCHandleType.Pinned);
                    pointer     = pinnedArray.AddrOfPinnedObject();
                    // for some reason I have to pass nBytes * 2. I assume under the hood it expects Unicode/WChar??
                    measured = (int)Paint.BreakText(pointer, (IntPtr)(bytes.Length * 2), constraint, out lineWidth) / 2;
                    pinnedArray.Free();

                    if (measured == 0)
                    {
                        measured  = 1;
                        lineWidth = -1;
                    }

                    char nextChar = ' ';
                    if (curOff + measured < length)
                    {
                        nextChar = _text[curOff + measured];
                    }

                    if (nextChar != ' ')
                    {
                        // Perform scan for the last space and end the line there
                        for (int si = curOff + measured - 1; si > curOff; si--)
                        {
                            if (_text[si] == ' ')
                            {
                                measured  = si - curOff;
                                extraSkip = 1;
                                break;
                            }
                        }
                    }
                }

                AvaloniaFormattedTextLine line = new AvaloniaFormattedTextLine();
                line.Start  = curOff;
                line.Length = measured;
                line.Width  = lineWidth;
                line.Height = lineHeight;
                line.Top    = curY;

                if (line.Width < 0)
                {
                    line.Width = _skiaRects[line.Start + line.Length - 1].Right;
                }

                // Build character rects
                for (int i = line.Start; i < line.Start + line.Length; i++)
                {
                    float prevRight = 0;
                    if (i != line.Start)
                    {
                        prevRight = _skiaRects[i - 1].Right;
                    }

                    subString = _text.Substring(line.Start, i - line.Start + 1);
                    float w = Paint.MeasureText(subString);

                    SKRect rc;
                    rc.Left       = prevRight;
                    rc.Right      = w;
                    rc.Top        = line.Top;
                    rc.Bottom     = line.Top + line.Height;
                    _skiaRects[i] = rc;
                }

                subString  = _text.Substring(line.Start, line.Length);
                line.Width = Paint.MeasureText(subString);

                _skiaLines.Add(line);

                curY += lineHeight;

                // TODO: We may want to consider adding Leading to the vertical line spacing but for now
                // it appears to make no difference. Revisit as part of FormattedText improvements.
                //
                //curY += mLeading;

                curOff += measured + extraSkip;
            }

            // Now convert to Avalonia data formats
            _lines.Clear();
            _rects.Clear();
            float maxX = 0;

            for (var c = 0; c < _skiaLines.Count; c++)
            {
                var w = _skiaLines[c].Width;
                if (maxX < w)
                {
                    maxX = w;
                }

                _lines.Add(new FormattedTextLine(_skiaLines[c].Length, _skiaLines[c].Height));
            }

            for (var c = 0; c < _text.Length; c++)
            {
                _rects.Add(_skiaRects[c].ToAvaloniaRect());
            }

            if (_skiaLines.Count == 0)
            {
                _size = new Size();
            }
            else
            {
                var lastLine = _skiaLines[_skiaLines.Count - 1];
                _size = new Size(maxX, lastLine.Top + lastLine.Height);
            }
        }
Example #21
0
        private SkiaHelper CreateSkiaHelper()
        {
            return(new SkiaHelper()
            {
                Size = new Components.RawSize
                {
                    Width = this.Width,
                    Height = this.Height
                },
                PostChain = new SkiaHelper.CanvasDelegate((SKCanvas canvas) =>
                {
                    using (var rectPaint = new SKPaint
                    {
                        StrokeWidth = 0,
                        StrokeMiter = 0,
                        StrokeJoin = SKStrokeJoin.Round,
                        StrokeCap = SKStrokeCap.Round,
                        Style = SKPaintStyle.Stroke,
                        Color = SKColor.Parse("666"),
                        TextSize = 32,
                        IsAntialias = true
                    })

                        using (var bgPaint = new SKPaint
                        {
                            StrokeWidth = 0,
                            StrokeMiter = 0,
                            StrokeJoin = SKStrokeJoin.Round,
                            StrokeCap = SKStrokeCap.Round,
                            Style = SKPaintStyle.Fill,
                            Color = SKColor.Parse("33fff9a3"),
                            TextSize = 32,
                            IsAntialias = true
                        })

                            using (var textPaint = new SKPaint
                            {
                                Typeface = SKFontManager.Default.MatchCharacter('가'),
                                StrokeWidth = 0,
                                StrokeMiter = 0,
                                StrokeJoin = SKStrokeJoin.Round,
                                StrokeCap = SKStrokeCap.Round,
                                Style = SKPaintStyle.StrokeAndFill,
                                Color = SKColor.Parse("FFFFFFFF"),
                                TextSize = 32,
                                IsAntialias = true
                            })
                                using (var outlinePaint = new SKPaint
                                {
                                    Style = textPaint.Style,
                                    Typeface = textPaint.Typeface,
                                    TextSize = textPaint.TextSize,
                                    StrokeCap = textPaint.StrokeCap,
                                    StrokeJoin = textPaint.StrokeJoin,
                                    StrokeMiter = textPaint.StrokeMiter,
                                    IsAntialias = textPaint.IsAntialias,

                                    StrokeWidth = 3,
                                    Color = SKColor.Parse("FF4374D9"),
                                })
                                    using (var outline2Paint = new SKPaint
                                    {
                                        Style = textPaint.Style,
                                        Typeface = textPaint.Typeface,
                                        TextSize = textPaint.TextSize,
                                        StrokeCap = textPaint.StrokeCap,
                                        StrokeJoin = textPaint.StrokeJoin,
                                        StrokeMiter = textPaint.StrokeMiter,
                                        IsAntialias = textPaint.IsAntialias,

                                        StrokeWidth = 6,
                                        Color = SKColor.Parse("FF5CD1E5")
                                    })
                                        using (SKPaint preventPaint = new SKPaint
                                        {
                                            IsAntialias = true,
                                            StrokeWidth = 10,
                                            Style = SKPaintStyle.StrokeAndFill,
                                            Color = SKColors.Black
                                        })
                                            using (SKPath frameTextPath = new SKPath())
                                            {
                                                SKHelper.Skia_Canvas.Clear(SKColors.Transparent);

                                                float x = 10.0f;
                                                float y = 5.0f;
                                                float measuredWidth = 0;

                                                string str = SKHelper.ContentText;
                                                while (str != null && str.Length != 0)
                                                {
                                                    SKRect bounds = new SKRect();

                                                    int textLength = (int)textPaint.BreakText(str, Size.Width - 24, out measuredWidth);
                                                    outline2Paint.MeasureText(str, ref bounds);

                                                    var b = Encoding.UTF8.GetBytes(str);
                                                    var s = Encoding.UTF8.GetString(b, 0, textLength);
                                                    if (bounds.Width > this.Width)
                                                    {
                                                        textLength -= Encoding.UTF8.GetByteCount($"{s[s.Length - 1]}");
                                                    }

                                                    s = Encoding.UTF8.GetString(b, textLength, b.Length - textLength);

                                                    // 띄어쓰기가 짤리면 줄 위로 올린다
                                                    for (int i = 0; i < s.Length; i++)
                                                    {
                                                        if (s[i] == ' ')
                                                        {
                                                            textLength++;
                                                        }
                                                        else
                                                        {
                                                            break;
                                                        }
                                                    }

                                                    y += (int)bounds.Height + 2;

                                                    using (SKPath textPath = textPaint.GetTextPath(Encoding.UTF8.GetString(b, 0, textLength), x, y))
                                                        using (SKPath outlinePath = new SKPath())
                                                        {
                                                            using (SKPaint tempPaint = new SKPaint
                                                            {
                                                                IsAntialias = true,
                                                                Color = SKColors.Black
                                                            })
                                                            {
                                                                tempPaint.GetFillPath(textPath, outlinePath);
                                                                frameTextPath.AddPath(textPath, SKPathAddMode.Append);
                                                            }
                                                        }
                                                    str = Encoding.UTF8.GetString(b, (int)textLength, b.Length - (int)textLength);
                                                }

                                                SKHelper.Skia_Canvas.DrawRect(new SKRect(0, 0, Size.Width, Size.Height), bgPaint);
                                                SKHelper.Skia_Canvas.DrawRect(new SKRect(0, 0, Size.Width, Size.Height), rectPaint);

                                                SKHelper.Skia_Canvas.DrawPath(frameTextPath, outline2Paint);
                                                SKHelper.Skia_Canvas.DrawPath(frameTextPath, outlinePaint);
                                                SKHelper.Skia_Canvas.DrawPath(frameTextPath, textPaint);
                                            }
                })
            });
        }
Example #22
0
        private static int LineBreak(string textInput, int textIndex, int stop,
                                     SKPaint paint, float maxWidth,
                                     out int trailingCount)
        {
            int lengthBreak;

            if (maxWidth == -1)
            {
                lengthBreak = stop - textIndex;
            }
            else
            {
                float  measuredWidth;
                string subText = textInput.Substring(textIndex, stop - textIndex);
                lengthBreak = (int)paint.BreakText(subText, maxWidth, out measuredWidth);
            }

            //Check for white space or line breakers before the lengthBreak
            int  startIndex = textIndex;
            int  index      = textIndex;
            int  word_start = textIndex;
            bool prevBreak  = true;

            trailingCount = 0;

            while (index < stop)
            {
                int  prevText  = index;
                char currChar  = textInput[index++];
                bool currBreak = IsBreakChar(currChar);

                if (!currBreak && prevBreak)
                {
                    word_start = prevText;
                }

                prevBreak = currBreak;

                if (index > startIndex + lengthBreak)
                {
                    if (currBreak)
                    {
                        // eat the rest of the whitespace
                        while (index < stop && IsBreakChar(textInput[index]))
                        {
                            index++;
                        }

                        trailingCount = index - prevText;
                    }
                    else
                    {
                        // backup until a whitespace (or 1 char)
                        if (word_start == startIndex)
                        {
                            if (prevText > startIndex)
                            {
                                index = prevText;
                            }
                        }
                        else
                        {
                            index = word_start;
                        }
                    }
                    break;
                }

                if ('\n' == currChar)
                {
                    int ret           = index - startIndex;
                    int lineBreakSize = 1;
                    if (index < stop)
                    {
                        currChar = textInput[index++];
                        if ('\r' == currChar)
                        {
                            ret = index - startIndex;
                            ++lineBreakSize;
                        }
                    }

                    trailingCount = lineBreakSize;

                    return(ret);
                }

                if ('\r' == currChar)
                {
                    int ret           = index - startIndex;
                    int lineBreakSize = 1;
                    if (index < stop)
                    {
                        currChar = textInput[index++];
                        if ('\n' == currChar)
                        {
                            ret = index - startIndex;
                            ++lineBreakSize;
                        }
                    }

                    trailingCount = lineBreakSize;

                    return(ret);
                }
            }

            return(index - startIndex);
        }