private unsafe GlyphRun ComputeShapedGlyphRun(
            LSRun                   lsrun,                      // ls run
            TextFormatterImp        textFormatterImp,           // The TextFormatter Implementation
            bool                    originProvided,             // flag indicate whether the origin of the run is provided                        
            LSPOINT                 lsrunOrigin,                // physical start of the run
            int                     charCount,                  // characters count
            char                    *pwchText,                  // characters for the GlyphRun
            ushort                  *puClusterMap,              // cluster map
            int                     glyphCount,                 // glyph count
            ushort                  *puGlyphs,                  // glyph indices
            int                     *piJustifiedGlyphAdvances,  // glyph advances
            GlyphOffset             *piiGlyphOffsets,           // glyph offsets
            bool                    justify
            )
        {
            TextMetrics.FullTextLine currentLine = Draw.CurrentLine;

            Point runOrigin = new Point();
            int nominalX = 0;
            int nominalY = 0;

            if (originProvided)
            {   
                if (currentLine.RightToLeft)
                {





                    lsrunOrigin.x = -lsrunOrigin.x;
                }

                if (textFormatterImp.TextFormattingMode == TextFormattingMode.Display && justify)
                {
                    LSRun.UVToNominalXY(
                        Draw.LineOrigin,
                        Draw.VectorToLineOrigin,
                        currentLine.LSLineUToParagraphU(lsrunOrigin.x),
                        lsrunOrigin.y + lsrun.BaselineMoveOffset,
                        currentLine,
                        out nominalX,
                        out nominalY
                        );
                }
                else
                {
                    runOrigin = LSRun.UVToXY(
                        Draw.LineOrigin,
                        Draw.VectorToLineOrigin,
                        currentLine.LSLineUToParagraphU(lsrunOrigin.x),
                        lsrunOrigin.y + lsrun.BaselineMoveOffset,
                        currentLine
                        );
                }
            }





            char[] charString = new char[charCount];
            ushort[] clusterMap = new ushort[charCount];

            for (int i = 0; i < charCount; i++)
            {
                charString[i] = pwchText[i];
                clusterMap[i] = puClusterMap[i];
            }

            ushort[] glyphIndices = new ushort[glyphCount];            
            IList<double> glyphAdvances;
            IList<Point> glyphOffsets;

            bool isRightToLeft = (lsrun.BidiLevel & 1) != 0;

            if (textFormatterImp.TextFormattingMode == TextFormattingMode.Ideal)
            {
                glyphAdvances = new ThousandthOfEmRealDoubles(textFormatterImp.IdealToReal(lsrun.EmSize), glyphCount);
                glyphOffsets = new ThousandthOfEmRealPoints(textFormatterImp.IdealToReal(lsrun.EmSize), glyphCount);

                for (int i = 0; i < glyphCount; i++)
                {
                    glyphIndices[i] = puGlyphs[i];
                    glyphAdvances[i] = textFormatterImp.IdealToReal(piJustifiedGlyphAdvances[i]);
                    glyphOffsets[i] = new Point(
                        textFormatterImp.IdealToReal(piiGlyphOffsets[i].du),
                        textFormatterImp.IdealToReal(piiGlyphOffsets[i].dv)
                        );
                }
            }
            else
            {
                if (justify)
                {
                    AdjustMetricsForDisplayModeJustifiedText(
                        pwchText,
                        piJustifiedGlyphAdvances,
                        glyphCount,
                        isRightToLeft,
                        nominalX,
                        nominalY,
                        out runOrigin,
                        out glyphAdvances
                        );
                }
                else
                {
                    glyphAdvances = new List<double>(glyphCount);
                    for (int i = 0; i < glyphCount; i++)
                    {
                        glyphAdvances.Add(textFormatterImp.IdealToReal(piJustifiedGlyphAdvances[i]));
                    }
                }
                glyphOffsets  = new List<Point>(glyphCount);
                for (int i = 0; i < glyphCount; i++)
                {
                    glyphIndices[i] = puGlyphs[i];
                    glyphOffsets.Add(new Point(
                            textFormatterImp.IdealToReal(piiGlyphOffsets[i].du),
                            textFormatterImp.IdealToReal(piiGlyphOffsets[i].dv)
                            ));
                }
            }

#if CHECK_GLYPHS
            if (   lsrun._glyphs != null
                && glyphCount <= lsrun._glyphs.Length)
            {
                for (int i = 0; i < glyphCount; i++)
                {
                    Debug.Assert(glyphIndices[i] == lsrun._glyphs[i], "Corrupted glyphs");
                }
            }
#endif            

            GlyphRun glyphRun = lsrun.Shapeable.ComputeShapedGlyphRun(
                runOrigin,
                charString, 
                clusterMap, 
                glyphIndices, 
                glyphAdvances, 
                glyphOffsets,
                isRightToLeft, 
                false   // no sideway support yet
                );

            return glyphRun;
        }
        private unsafe GlyphRun ComputeUnshapedGlyphRun(
            LSRun               lsrun,              // LSrun used to shape the GlyphRun            
            LsTFlow             textFlow,           // flow direction
            TextFormatterImp    textFormatterImp,   // The TextFormatter Implementation
            bool                originProvided,     // flag indicate whether the origin of the run is provided                        
            LSPOINT             lsrunOrigin,        // physical start of the run
            int                 dupRun,             // width of the run
            int                 cchText,            // character count
            char                *pwchText,          // characters for display 
            int                 *piCharAdvances,    // character advance widths,
            bool                justify
            )
        {
            GlyphRun glyphRun = null;
            if (lsrun.Type == Plsrun.Text)
            {
                Debug.Assert(lsrun.Shapeable != null);
                Point runOrigin    = new Point();
                int nominalX = 0;
                int nominalY = 0;

                if (originProvided)
                {                   
                    TextMetrics.FullTextLine currentLine = Draw.CurrentLine;
                    
                    if (textFlow == LsTFlow.lstflowWS)
                    {
                        lsrunOrigin.x -= dupRun;
                    }

                    if (currentLine.RightToLeft)
                    {
                        lsrunOrigin.x = -lsrunOrigin.x;
                    }

                    if (textFormatterImp.TextFormattingMode == TextFormattingMode.Display && justify)
                    {
                        LSRun.UVToNominalXY(
                            Draw.LineOrigin,
                            Draw.VectorToLineOrigin,
                            currentLine.LSLineUToParagraphU(lsrunOrigin.x),
                            lsrunOrigin.y + lsrun.BaselineMoveOffset,
                            currentLine,
                            out nominalX,
                            out nominalY
                            );
                    }
                    else
                    {
                        runOrigin = LSRun.UVToXY(
                            Draw.LineOrigin,
                            Draw.VectorToLineOrigin,
                            currentLine.LSLineUToParagraphU(lsrunOrigin.x),
                            lsrunOrigin.y + lsrun.BaselineMoveOffset,
                            currentLine
                            );
                    }
                }



                
                char[] charString = new char[cchText];
                IList<double> charWidths;

                bool isRightToLeft = (lsrun.BidiLevel & 1) != 0;

                if (textFormatterImp.TextFormattingMode == TextFormattingMode.Ideal)
                {
                    charWidths = new ThousandthOfEmRealDoubles(textFormatterImp.IdealToReal(lsrun.EmSize), cchText);
                    for (int i = 0; i < cchText; i++)
                    {
                        charString[i] = pwchText[i];
                        charWidths[i] = textFormatterImp.IdealToReal(piCharAdvances[i]);
                    }
                }
                else
                {
                    if (justify)
                    {
                        AdjustMetricsForDisplayModeJustifiedText(
                            pwchText,
                            piCharAdvances,
                            cchText,
                            isRightToLeft,
                            nominalX,
                            nominalY,
                            out runOrigin,
                            out charWidths
                            );
                    }
                    else
                    {
                        charWidths = new List<double>(cchText);
                        for (int i = 0; i < cchText; i++)
                        {
                            charWidths.Add(textFormatterImp.IdealToReal(piCharAdvances[i]));
                        }
                    }
                    for (int i = 0; i < cchText; i++)
                    {
                        charString[i] = pwchText[i];
                    }
                }

                

                glyphRun = lsrun.Shapeable.ComputeUnshapedGlyphRun(
                    runOrigin,
                    charString,
                    charWidths
                    );
            }            

            return glyphRun;
        } 
        /// <summary>
        /// Create simple run of text,
        /// returning null if the specified text run cannot be correctly formatted as simple run
        /// </summary>
        static internal SimpleRun CreateSimpleTextRun(
            CharacterBufferRange    charBufferRange,
            TextRun                 textRun,
            TextFormatterImp        formatter,
            int                     widthLeft,
            bool                    emergencyWrap,
            bool                    breakOnTabs
            )
        {
            Invariant.Assert(textRun is TextCharacters);

            SimpleRun run = new SimpleRun(formatter);
            run.CharBufferReference = charBufferRange.CharacterBufferReference;
            run.TextRun = textRun;

            if (!run.TextRun.Properties.Typeface.CheckFastPathNominalGlyphs(
                charBufferRange,
                run.EmSize,
                1.0,
                formatter.IdealToReal(widthLeft),
                !emergencyWrap,
                false,
                CultureMapper.GetSpecificCulture(run.TextRun.Properties.CultureInfo),
                formatter.TextFormattingMode,
                false,          //No support for isSideways
                breakOnTabs,
                out run.Length
                ))
            {
                // Getting nominal glyphs is not supported by the font,
                // or it is but it results in low typographic quality text
                // e.g. OpenType support is not utilized.
                return null;
            }

            run.TextRun.Properties.Typeface.GetCharacterNominalWidthsAndIdealWidth(
                new CharacterBufferRange(run.CharBufferReference, run.Length),
                run.EmSize,
                TextFormatterImp.ToIdeal,
                formatter.TextFormattingMode,
                false,
                out run.NominalAdvances,
                out run.IdealWidth
                );

            return run;
        }