BreakText returns incorrect number of characters if text contains cyrillic characters

ConstantinConstantin RUMember
edited November 2 in SkiaSharp

Hello, Hello!

Try execute this code:

        private void C_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)
        {
            var canvas = e.Surface.Canvas;
            var textPaint = new SKPaint() { Color = SKColors.White };
            var linePaint = new SKPaint() { Color = SKColors.Red };

            var lat = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            var cyr = "АБВГДEЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЯЭЮЯ";

            var x = 10f;
            var y = 0f;
            var xx = 120f;
            foreach (var ch in lat)
            {
                var t = ch.ToString();
                var lw = textPaint.MeasureText(t);
                float mw;
                textPaint.BreakText(t, 1000f, out mw);
                canvas.DrawText($"{ch} ({lw} = {mw})", x, y += textPaint.FontSpacing, textPaint);
            }

            y = 0f; x += xx;
            foreach (var ch in lat.ToLower())
            {
                var t = ch.ToString();
                var lw = textPaint.MeasureText(t);
                float mw;
                textPaint.BreakText(t, 1000f, out mw);
                canvas.DrawText($"{ch} ({lw} = {mw})", x, y += textPaint.FontSpacing, textPaint);
            }

            y = 0f; x += xx;
            foreach (var ch in cyr)
            {
                var t = ch.ToString();
                var lw = textPaint.MeasureText(t);
                float mw;
                textPaint.BreakText(t, 1000f, out mw);
                canvas.DrawText($"{ch} ({lw} = {mw})", x, y += textPaint.FontSpacing, textPaint);
            }

            y = 0f; x += xx;
            foreach (var ch in cyr.ToLower())
            {
                var t = ch.ToString();
                var lw = textPaint.MeasureText(t);
                float mw;
                textPaint.BreakText(t, 1000f, out mw);
                canvas.DrawText($"{ch} ({lw} = {mw})", x, y += textPaint.FontSpacing, textPaint);
            }

            y = 0f; x += xx;

            for (var maxw = 50f; maxw <= 150f; maxw += 50f)
            {
                canvas.DrawText($"maxWidth = {maxw}", x, y += textPaint.FontSpacing, textPaint);

                {
                    var t = lat;
                    float mw;
                    var l = textPaint.BreakText(t, maxw, out mw);
                    if (l < t.Length) t = t.Remove((int)l);
                    var lw = textPaint.MeasureText(t);
                    canvas.DrawText($"{t} ({lw} = {mw})", x, y += textPaint.FontSpacing, textPaint);
                }

                {
                    var t = cyr;
                    float mw;
                    var l = textPaint.BreakText(t, maxw, out mw);
                    if (l < t.Length) t = t.Remove((int)l);
                    var lw = textPaint.MeasureText(t);
                    canvas.DrawText($"{t} ({lw} = {mw})", x, y += textPaint.FontSpacing, textPaint);
                }

                canvas.DrawLine(x, y + 5, x + maxw, y +5, linePaint);
                y += textPaint.FontSpacing;
            }
        }

Posts

  • mattleibowmattleibow ZAXamarin Team Xamurai

    Moving this to the GitHub issue as this is a "bug" with both the docs and the managed perception, but still is functioning as designed: https://github.com/mono/SkiaSharp/issues/381

  • ConstantinConstantin RUMember

    Matthew, thank you!
    "The return value is actually the NUMBER OF BYTES in the string, that is why you see the larger numbers."
    This code can work and that's Ok:

        textPaint.TextEncoding = SKTextEncoding.Utf16;
        ...
        var l = textPaint.BreakText(t, maxw, out mw) >> 1;
    
Sign In or Register to comment.