public void DrawString(char[] text, int startAt, int len, double x, double y)
        {
            if (this.UseSubPixelRendering)
            {
                //1. clear prev drawing result
                _aggPainter.Clear(Drawing.Color.FromArgb(0, 0, 0, 0));
                //aggPainter.Clear(Drawing.Color.White);
                //aggPainter.Clear(Drawing.Color.FromArgb(0, 0, 0, 0));
                //2. print text span into Agg Canvas
                _vxsTextPrinter.DrawString(text, startAt, len, 0, 0);
                //3.copy to gl bitmap
                //byte[] buffer = PixelFarm.Agg.ActualImage.GetBuffer(_actualImage);
                //------------------------------------------------------
                GLBitmap glBmp = new GLBitmap(_actualImage);
                glBmp.IsInvert = false;
                //TODO: review font height
                if (StartDrawOnLeftTop)
                {
                    y -= _vxsTextPrinter.FontLineSpacingPx;
                }
                _glsx.DrawGlyphImageWithSubPixelRenderingTechnique(glBmp, (float)x, (float)y);
                glBmp.Dispose();
            }
            else
            {
                //1. clear prev drawing result
                _aggPainter.Clear(Drawing.Color.White);
                _aggPainter.StrokeColor = Color.Black;

                //2. print text span into Agg Canvas
                _vxsTextPrinter.StartDrawOnLeftTop = false;

                float dyOffset = _vxsTextPrinter.FontDescedingPx;
                _vxsTextPrinter.DrawString(text, startAt, len, 0, -dyOffset);
                //------------------------------------------------------
                //debug save image from agg's buffer
#if DEBUG
                //actualImage.dbugSaveToPngFile("d:\\WImageTest\\aa1.png");
#endif
                //------------------------------------------------------

                //3.copy to gl bitmap
                //byte[] buffer = PixelFarm.Agg.ActualImage.GetBuffer(_actualImage);
                //------------------------------------------------------
                //debug save image from agg's buffer

                //------------------------------------------------------
                //GLBitmap glBmp = new GLBitmap(bmpWidth, bmpHeight, buffer, true);
                GLBitmap glBmp = new GLBitmap(_actualImage);
                glBmp.IsInvert = false;
                //TODO: review font height
                //if (StartDrawOnLeftTop)
                //{
                y += _vxsTextPrinter.FontLineSpacingPx;
                //}
                _glsx.DrawGlyphImage(glBmp, (float)x, (float)y + dyOffset);
                glBmp.Dispose();
            }
        }
        public void DrawString(char[] buffer, int startAt, int len, double x, double y)
        {
            _glsx.FontFillColor = painter.FontFillColor;

            int j = buffer.Length;

            //create temp buffer span that describe the part of a whole char buffer
            TextBufferSpan textBufferSpan = new TextBufferSpan(buffer, startAt, len);

            //ask text service to parse user input char buffer and create a glyph-plan-sequence (list of glyph-plan)
            //with specific request font
            GlyphPlanSequence glyphPlanSeq = _textServices.CreateGlyphPlanSeq(ref textBufferSpan, font);

            float scale = _fontAtlas.TargetTextureScale;
            int   recommendLineSpacing = _fontAtlas.OriginalRecommendLineSpacing;

            //--------------------------
            //TODO:
            //if (x,y) is left top
            //we need to adjust y again
            y -= ((_fontAtlas.OriginalRecommendLineSpacing) * scale);

            EnsureLoadGLBmp();
            //
            float       scaleFromTexture = _finalTextureScale;
            TextureKind textureKind      = _fontAtlas.TextureKind;

            //--------------------------

            //TODO: review render steps
            //NOTE:
            // -glyphData.TextureXOffset => restore to original pos
            // -glyphData.TextureYOffset => restore to original pos
            // ideal_x = (float)(x + (glyph.x * scale - glyphData.TextureXOffset) * scaleFromTexture);
            // ideal_y = (float)(y + (glyph.y * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);
            //--------------------------

            float g_x       = 0;
            float g_y       = 0;
            int   baseY     = (int)Math.Round(y);
            int   n         = glyphPlanSeq.len;
            int   endBefore = glyphPlanSeq.startAt + n;

            for (int i = glyphPlanSeq.startAt; i < endBefore; ++i)
            {
                GlyphPlanList glyphPlanList = GlyphPlanSequence.UnsafeGetInteralGlyphPlanList(glyphPlanSeq);
                GlyphPlan     glyph         = glyphPlanList[i];

                Typography.Rendering.TextureFontGlyphData glyphData;
                if (!_fontAtlas.TryGetGlyphDataByCodePoint(glyph.glyphIndex, out glyphData))
                {
                    //if no glyph data, we should render a missing glyph ***
                    continue;
                }
                //--------------------------------------
                //TODO: review precise height in float
                //--------------------------------------
                PixelFarm.Drawing.Rectangle srcRect = ConvToRect(glyphData.Rect);
                g_x = (float)(x + (glyph.ExactX * scale - glyphData.TextureXOffset) * scaleFromTexture); //ideal x
                g_y = (float)(y + (glyph.ExactY * scale - glyphData.TextureYOffset + srcRect.Height) * scaleFromTexture);


                //for sharp glyph
                //we adjust g_x,g_y to integer value
                g_x = (float)Math.Round(g_x);
                g_y = (float)Math.Floor(g_y);

                switch (textureKind)
                {
                case TextureKind.Msdf:

                    _glsx.DrawSubImageWithMsdf(_glBmp,
                                               ref srcRect,
                                               g_x,
                                               g_y,
                                               scaleFromTexture);

                    break;

                case TextureKind.StencilGreyScale:

                    //stencil gray scale with fill-color
                    _glsx.DrawGlyphImageWithStecil(_glBmp,
                                                   ref srcRect,
                                                   g_x,
                                                   g_y,
                                                   scaleFromTexture);

                    break;

                case TextureKind.Bitmap:
                    _glsx.DrawSubImage(_glBmp,
                                       ref srcRect,
                                       g_x,
                                       g_y,
                                       scaleFromTexture);
                    break;

                case TextureKind.StencilLcdEffect:

                    _glsx.DrawGlyphImageWithSubPixelRenderingTechnique(_glBmp,
                                                                       ref srcRect,
                                                                       g_x,
                                                                       g_y,
                                                                       scaleFromTexture);

                    break;
                }
            }
        }