internal Rect Draw(
            DrawingContext      drawingContext,
            double              x,
            double              y,
            bool                visiCodePath
            )
        {
            if (Length <= 0 || this.Ghost)
            {
                return Rect.Empty;  // nothing to draw
            }

            Brush foregroundBrush = TextRun.Properties.ForegroundBrush;

            if(visiCodePath && foregroundBrush is SolidColorBrush)
            {
                Color color = ((SolidColorBrush)foregroundBrush).Color;
                foregroundBrush = new SolidColorBrush(Color.FromArgb(
                    (byte)(color.A>>2), // * 0.25
                    color.R,
                    color.G,
                    color.B
                    ));
            }

            Rect inkBoundingBox;

            IList<double> displayGlyphAdvances;
            if (_textFormatterImp.TextFormattingMode == TextFormattingMode.Ideal)
            {
                displayGlyphAdvances = new ThousandthOfEmRealDoubles(EmSize, NominalAdvances.Length);
                for (int i = 0; i < displayGlyphAdvances.Count; i++)
                {
                    // convert ideal glyph advance width to real width for displaying.
                    displayGlyphAdvances[i] = _textFormatterImp.IdealToReal(NominalAdvances[i]);
                }
            }
            else
            {
                displayGlyphAdvances = new List<double>(NominalAdvances.Length);
                for (int i = 0; i < NominalAdvances.Length; i++)
                {
                    // convert ideal glyph advance width to real width for displaying.
                    displayGlyphAdvances.Add(_textFormatterImp.IdealToReal(NominalAdvances[i]));
                }
            }

            CharacterBufferRange charBufferRange = new CharacterBufferRange(CharBufferReference, Length);

            GlyphTypeface glyphTypeface = Typeface.TryGetGlyphTypeface();
            Invariant.Assert(glyphTypeface != null);

            GlyphRun glyphRun = glyphTypeface.ComputeUnshapedGlyphRun(
                new Point(x, y),
                charBufferRange,
                displayGlyphAdvances,
                EmSize,
                TextRun.Properties.FontHintingEmSize,
                Typeface.NullFont,
                CultureMapper.GetSpecificCulture(TextRun.Properties.CultureInfo),
                null,  // device font name
                _textFormatterImp.TextFormattingMode
              );

            if (glyphRun != null)
            {
                inkBoundingBox = glyphRun.ComputeInkBoundingBox();
            }
            else
            {
                inkBoundingBox = Rect.Empty;
            }

            if (!inkBoundingBox.IsEmpty)
            {
                // glyph run's ink bounding box is relative to its origin
                inkBoundingBox.X += glyphRun.BaselineOrigin.X;
                inkBoundingBox.Y += glyphRun.BaselineOrigin.Y;
            }

            if (drawingContext != null)
            {
                if (glyphRun != null)
                {
                    glyphRun.EmitBackground(drawingContext, TextRun.Properties.BackgroundBrush);
                    drawingContext.DrawGlyphRun(foregroundBrush, glyphRun);
                }


                // draw underline here
                if (Underline != null)
                {
                    // Determine number of characters to underline. We don't underline trailing spaces
                    // if the TrimTrailingUnderline flag is set.
                    int underlineLength = Length;
                    if (TrimTrailingUnderline)
                    {
                        while (underlineLength > 0 && IsSpace(charBufferRange[underlineLength - 1]))
                        {
                            --underlineLength;
                        }
                    }

                    // Determine the width of the underline.
                    double dxUnderline = 0;
                    for (int i = 0; i < underlineLength; ++i)
                    {
                        dxUnderline += _textFormatterImp.IdealToReal(NominalAdvances[i]);
                    }

                    // We know only TextDecoration.Underline will be handled in Simple Path.
                    double offset = -Typeface.UnderlinePosition * EmSize;
                    double penThickness = Typeface.UnderlineThickness * EmSize;

                    Point lineOrigin = new Point(x, y + offset);

                    Rect underlineRect = new Rect(
                            lineOrigin.X,
                            lineOrigin.Y - penThickness * 0.5,
                            dxUnderline,
                            penThickness
                        );

                    // Apply the pair of guidelines: one for baseline and another
                    // for top edge of undelining line. Both will be snapped to pixel grid.
                    // Guideline pairing algorithm detects the case when these two
                    // guidelines happen to be close to one another and provides
                    // synchronous snapping, so that the gap between baseline and
                    // undelining line does not depend on the position of text line.
                    drawingContext.PushGuidelineY2(y, lineOrigin.Y - penThickness * 0.5 - y);

                    try
                    {
                        drawingContext.DrawRectangle(
                            foregroundBrush,
                            null,               // pen
                            underlineRect
                            );
                    }
                    finally
                    {
                        drawingContext.Pop();
                    }

                    // underline pen thickness is always positive in fast path
                    inkBoundingBox.Union(
                        underlineRect
                        );
                }
            }

            return inkBoundingBox;
        }