public static int GetGlyphShapeT2(
            FontInfo info, int glyphIndex, out Vertex[]?pvertices)
        {
            var output_ctx = new CharStringContext();
            var count_ctx  = new CharStringContext();

            count_ctx.bounds = 1;

            if (RunCharString(info, glyphIndex, ref count_ctx) != 0)
            {
                pvertices            = new Vertex[count_ctx.num_vertices];
                output_ctx.pvertices = pvertices;

                if (RunCharString(info, glyphIndex, ref output_ctx) != 0)
                {
                    return(output_ctx.num_vertices);
                }
            }

            pvertices = null;
            return(0);
        }
        public static int RunCharString(
            FontInfo info, int glyphIndex, ref CharStringContext c)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }

            int   in_header         = 1;
            int   maskbits          = 0;
            int   subr_stack_height = 0;
            int   sp          = 0;
            int   v           = 0;
            int   i           = 0;
            int   b0          = 0;
            int   has_subrs   = 0;
            int   clear_stack = 0;
            float f           = 0;
            var   subrs       = info.subrs;

            Span <float> s          = stackalloc float[48];
            var          subr_stack = new Buffer[10];

            var b = CffIndexGet(info.charstrings, glyphIndex);

            while (b.Cursor < b.Size)
            {
                i           = 0;
                clear_stack = 1;
                b0          = b.GetByte();
                switch (b0)
                {
                case 0x13:
                case 0x14:
                    if (in_header != 0)
                    {
                        maskbits += sp / 2;
                    }
                    in_header = 0;
                    b.Skip((maskbits + 7) / 8);
                    break;

                case 0x01:
                case 0x03:
                case 0x12:
                case 0x17:
                    maskbits += sp / 2;
                    break;

                case 0x15:
                    in_header = 0;
                    if (sp < 2)
                    {
                        return(0);
                    }
                    c.RMoveTo(s[sp - 2], s[sp - 1]);
                    break;

                case 0x04:
                    in_header = 0;
                    if (sp < 1)
                    {
                        return(0);
                    }
                    c.RMoveTo(0f, s[sp - 1]);
                    break;

                case 0x16:
                    in_header = 0;
                    if (sp < 1)
                    {
                        return(0);
                    }
                    c.RMoveTo(s[sp - 1], 0f);
                    break;

                case 0x05:
                    if (sp < 2)
                    {
                        return(0);
                    }
                    for (; (i + 1) < sp; i += 2)
                    {
                        c.RLineTo(s[i], s[i + 1]);
                    }
                    break;

                case 0x07:
                case 0x06:
                    if (sp < 1)
                    {
                        return(0);
                    }

                    int goto_vlineto = b0 == 0x07 ? 1 : 0;
                    for (; ;)
                    {
                        if (goto_vlineto == 0)
                        {
                            if (i >= sp)
                            {
                                break;
                            }
                            c.RLineTo(s[i], 0);
                            i++;
                        }
                        goto_vlineto = 0;

                        if (i >= sp)
                        {
                            break;
                        }
                        c.RLineTo(0f, s[i]);
                        i++;
                    }
                    break;

                case 0x1F:
                case 0x1E:
                    if (sp < 4)
                    {
                        return(0);
                    }

                    int goto_hvcurveto = b0 == 0x1F ? 1 : 0;
                    for (; ;)
                    {
                        if (goto_hvcurveto == 0)
                        {
                            if ((i + 3) >= sp)
                            {
                                break;
                            }

                            c.RCCurveTo(
                                0f, s[i],
                                s[i + 1], s[i + 2],
                                s[i + 3], ((sp - i) == 5) ? s[i + 4] : 0f);
                            i += 4;
                        }

                        goto_hvcurveto = 0;
                        if ((i + 3) >= sp)
                        {
                            break;
                        }
                        c.RCCurveTo(
                            s[i], 0f,
                            s[i + 1], s[i + 2],
                            ((sp - i) == 5) ? s[i + 4] : 0f, s[i + 3]);
                        i += 4;
                    }
                    break;

                case 0x08:
                    if (sp < 6)
                    {
                        return(0);
                    }

                    for (; (i + 5) < sp; i += 6)
                    {
                        c.RCCurveTo(
                            s[i], s[i + 1],
                            s[i + 2], s[i + 3],
                            s[i + 4], s[i + 5]);
                    }
                    break;

                case 0x18:
                    if (sp < 8)
                    {
                        return(0);
                    }

                    for (; (i + 5) < (sp - 2); i += 6)
                    {
                        c.RCCurveTo(
                            s[i], s[i + 1],
                            s[i + 2], s[i + 3],
                            s[i + 4], s[i + 5]);
                    }
                    if ((i + 1) >= sp)
                    {
                        return(0);
                    }
                    c.RLineTo(s[i], s[i + 1]);
                    break;

                case 0x19:
                    if (sp < 8)
                    {
                        return(0);
                    }

                    for (; (i + 1) < (sp - 6); i += 2)
                    {
                        c.RLineTo(s[i], s[i + 1]);
                    }

                    if ((i + 5) >= sp)
                    {
                        return(0);
                    }

                    c.RCCurveTo(
                        s[i], s[i + 1],
                        s[i + 2], s[i + 3],
                        s[i + 4], s[i + 5]);
                    break;

                case 0x1A:
                case 0x1B:
                    if (sp < 4)
                    {
                        return(0);
                    }

                    f = 0f;
                    if ((sp & 1) != 0)
                    {
                        f = s[i];
                        i++;
                    }

                    for (; (i + 3) < sp; i += 4)
                    {
                        if (b0 == 0x1B)
                        {
                            c.RCCurveTo(
                                s[i], f,
                                s[i + 1], s[i + 2],
                                s[i + 3], 0);
                        }
                        else
                        {
                            c.RCCurveTo(
                                f, s[i],
                                s[i + 1], s[i + 2],
                                0, s[i + 3]);
                        }
                        f = 0;
                    }
                    break;

                case 0x0A:
                case 0x1D:
                    if (b0 == 0x0A)
                    {
                        if (has_subrs == 0)
                        {
                            if (info.fdselect.Size != 0)
                            {
                                subrs = CidGetGlyphSubRs(info, glyphIndex);
                            }
                            has_subrs = 1;
                        }
                    }

                    if (sp < 1)
                    {
                        return(0);
                    }
                    v = (int)s[--sp];

                    if (subr_stack_height >= 10)
                    {
                        return(0);
                    }

                    subr_stack[subr_stack_height++] = b;
                    b = GetSubr(b0 == 0x0A ? subrs : info.gsubrs, v);
                    if (b.Size == 0)
                    {
                        return(0);
                    }
                    b.Cursor    = 0;
                    clear_stack = 0;
                    break;

                case 0x0B:
                    if (subr_stack_height <= 0)
                    {
                        return(0);
                    }
                    b           = subr_stack[--subr_stack_height];
                    clear_stack = 0;
                    break;

                case 0x0E:
                    c.CloseShape();
                    return(1);

                case 0x0C:
                {
                    float dx1 = 0;
                    float dx2 = 0;
                    float dx3 = 0;
                    float dx4 = 0;
                    float dx5 = 0;
                    float dx6 = 0;
                    float dy1 = 0;
                    float dy2 = 0;
                    float dy3 = 0;
                    float dy4 = 0;
                    float dy5 = 0;
                    float dy6 = 0;
                    float dx  = 0;
                    float dy  = 0;

                    int b1 = b.GetByte();
                    switch (b1)
                    {
                    case 0x22:
                        if (sp < 7)
                        {
                            return(0);
                        }
                        dx1 = s[0];
                        dx2 = s[1];
                        dy2 = s[2];
                        dx3 = s[3];
                        dx4 = s[4];
                        dx5 = s[5];
                        dx6 = s[6];
                        c.RCCurveTo(dx1, 0f, dx2, dy2, dx3, 0f);
                        c.RCCurveTo(dx4, 0f, dx5, -dy2, dx6, 0f);
                        break;

                    case 0x23:
                        if (sp < 13)
                        {
                            return(0);
                        }
                        dx1 = s[0];
                        dy1 = s[1];
                        dx2 = s[2];
                        dy2 = s[3];
                        dx3 = s[4];
                        dy3 = s[5];
                        dx4 = s[6];
                        dy4 = s[7];
                        dx5 = s[8];
                        dy5 = s[9];
                        dx6 = s[10];
                        dy6 = s[11];
                        c.RCCurveTo(dx1, dy1, dx2, dy2, dx3, dy3);
                        c.RCCurveTo(dx4, dy4, dx5, dy5, dx6, dy6);
                        break;

                    case 0x24:
                        if (sp < 9)
                        {
                            return(0);
                        }
                        dx1 = s[0];
                        dy1 = s[1];
                        dx2 = s[2];
                        dy2 = s[3];
                        dx3 = s[4];
                        dx4 = s[5];
                        dx5 = s[6];
                        dy5 = s[7];
                        dx6 = s[8];
                        c.RCCurveTo(dx1, dy1, dx2, dy2, dx3, 0f);
                        c.RCCurveTo(dx4, 0f, dx5, dy5, dx6, -(dy1 + dy2 + dy5));
                        break;

                    case 0x25:
                        if (sp < 11)
                        {
                            return(0);
                        }
                        dx1 = s[0];
                        dy1 = s[1];
                        dx2 = s[2];
                        dy2 = s[3];
                        dx3 = s[4];
                        dy3 = s[5];
                        dx4 = s[6];
                        dy4 = s[7];
                        dx5 = s[8];
                        dy5 = s[9];
                        dx6 = dy6 = s[10];
                        dx  = dx1 + dx2 + dx3 + dx4 + dx5;
                        dy  = dy1 + dy2 + dy3 + dy4 + dy5;
                        if (Math.Abs(dx) > Math.Abs(dy))
                        {
                            dy6 = -dy;
                        }
                        else
                        {
                            dx6 = -dx;
                        }
                        c.RCCurveTo(dx1, dy1, dx2, dy2, dx3, dy3);
                        c.RCCurveTo(dx4, dy4, dx5, dy5, dx6, dy6);
                        break;

                    default:
                        return(0);
                    }
                }
                break;

                default:
                    if ((b0 != 255) && (b0 != 28) && ((b0 < 32) || (b0 > 254)))
                    {
                        return(0);
                    }

                    if (b0 == 255)
                    {
                        f = (float)(int)b.Get(4) / 0x10000;
                    }
                    else
                    {
                        b.Skip(-1);
                        f = (short)CffInt(ref b);
                    }

                    if (sp >= 48)
                    {
                        return(0);
                    }

                    s[sp++]     = f;
                    clear_stack = 0;
                    break;
                }

                if (clear_stack != 0)
                {
                    sp = 0;
                }
            }

            return(0);
        }