/// <summary>
        /// Scan through specified character string checking for valid character
        /// nominal glyph.
        /// </summary>
        /// <param name="charBufferRange">character buffer range</param>
        /// <param name="emSize">height of Em</param>
        /// <param name="scalingFactor">This is the factor by which we will scale up
        /// the metrics. Typically this value to used to convert metrics from the real
        /// space to the ideal space</param>
        /// <param name="widthMax">maximum width allowed</param>
        /// <param name="keepAWord">do not stop arbitrarily in the middle of a word</param>
        /// <param name="numberSubstitution">digits require complex shaping</param>
        /// <param name="cultureInfo">CultureInfo of the text</param>
        /// <param name="textFormattingMode">The TextFormattingMode used (Ideal vs. Display)</param>
        /// <param name="isSideways">Indicates whether to rotate glyphs.</param>
        /// <param name="breakOnTabs">Determines whether to stop checking at a tab and
        /// break the run there</param>
        /// <param name="stringLengthFit">number of character fit in given width</param>
        /// <returns>whether the specified string can be optimized by nominal glyph lookup</returns>
        internal bool CheckFastPathNominalGlyphs(
            CharacterBufferRange charBufferRange,
            double emSize,
            double scalingFactor,
            double widthMax,
            bool keepAWord,
            bool numberSubstitution,
            CultureInfo cultureInfo,
            TextFormattingMode textFormattingMode,
            bool isSideways,
            bool breakOnTabs,
            out int stringLengthFit
            )
        {
            stringLengthFit = 0;

            if (CachedTypeface.NullFont)
            {
                return(false);
            }

            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();

            if (glyphTypeface == null)
            {
                return(false);
            }

            double totalWidth = 0;
            int    i          = 0;

            ushort blankGlyph = glyphTypeface.BlankGlyphIndex;
            ushort glyph      = blankGlyph;

            ushort charFlagsMask = numberSubstitution ?
                                   (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) :
                                   (ushort)CharacterAttributeFlags.CharacterComplex;
            ushort charFlags         = 0;
            ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo);

            bool symbolTypeface = glyphTypeface.Symbol;

            if (symbolTypeface)
            {
                // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings;
                // the code points don't have any standardized meanings, and we always want to bypass shaping
                charFlagsMask = 0;
            }

            bool ignoreWidths = widthMax == double.MaxValue;

            ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length);
            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length);

            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange,
                                                   emSize,
                                                   glyphIndices,
                                                   glyphMetrics,
                                                   textFormattingMode,
                                                   isSideways
                                                   );

            double designToEm = emSize / glyphTypeface.DesignEmHeight;

            //
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached
            // 2. The charFlags have some of the charFlagsMask values
            // 3. The glyph is BlankGlyph (space)
            // 4. Glyph index is 0 (unless symbol font)
            //
            // At this point totalWidth includes all of the widths including the stop character (which fits above)
            // i indexes the next character (not included in the width)
            //
            if (keepAWord)
            {
                do
                {
                    char ch = charBufferRange[i++];
                    if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn || (breakOnTabs && ch == TextStore.CharTab))
                    {
                        --i;
                        break;
                    }
                    else
                    {
                        int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                        charFlags          = Classification.CharAttributeOf(charClass).Flags;
                        charFastTextCheck &= charFlags;

                        glyph = glyphIndices[i - 1];
                        if (!ignoreWidths)
                        {
                            totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor;
                        }
                    }
                } while(
                    i < charBufferRange.Length &&
                    ((charFlags & charFlagsMask) == 0) &&
                    (glyph != 0 || symbolTypeface) &&
                    glyph != blankGlyph
                    );

                // i is now at a character immediately following a leading blank
            }

            //
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached
            // 2. The charFlags have some of the charFlagsMask values
            // 3. Glyph index is 0 (unless symbol font)
            // 4. totalWidth > widthMax
            //

            while (
                i < charBufferRange.Length &&
                (ignoreWidths || totalWidth <= widthMax) &&
                ((charFlags & charFlagsMask) == 0) &&
                (glyph != 0 || symbolTypeface)
                )
            {
                char ch = charBufferRange[i++];
                if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn || (breakOnTabs && ch == TextStore.CharTab))
                {
                    --i;
                    break;
                }
                else
                {
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                    charFlags          = Classification.CharAttributeOf(charClass).Flags;
                    charFastTextCheck &= charFlags;

                    glyph = glyphIndices[i - 1];
                    if (!ignoreWidths)
                    {
                        totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor;
                    }
                }
            }

            BufferCache.ReleaseUShorts(glyphIndices);
            glyphIndices = null;
            BufferCache.ReleaseGlyphMetrics(glyphMetrics);
            glyphMetrics = null;

            if (symbolTypeface)
            {
                // always optimize for non-Unicode font as we don't support shaping or typographic features;
                // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs
                stringLengthFit = i;
                return(true);
            }

            if (glyph == 0)
            {
                // character is not supported by the font
                return(false);
            }

            if ((charFlags & charFlagsMask) != 0)
            {
                // complex character encountered, exclude it
                Debug.Assert(i > 0);

                if (--i <= 0)
                {
                    // first char is complex, fail the call
                    return(false);
                }
            }

            stringLengthFit = i;
            TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities;

            if ((charFastTextCheck & (byte)CharacterAttributeFlags.CharacterFastText) != 0)
            {
                // all input code points are Fast Text
                if ((typography &
                     (TypographyAvailabilities.FastTextTypographyAvailable
                      | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable
                     )
                     ) != 0
                    )
                {
                    // Considered too risky to optimize. It is either because the font
                    // has required features or the font has 'locl' lookup for major languages.
                    return(false);
                }
                else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0)
                {
                    // The font has 'locl' lookup for FastText code points for non major languages.
                    // Check whether the input is major langauge. If it is, we are still good to optimize.
                    return(MajorLanguages.Contains(cultureInfo));
                }
                else
                {
                    // No FastText flags are present, safe to optimize
                    return(true);
                }
            }
            else if ((charFastTextCheck & (byte)CharacterAttributeFlags.CharacterIdeo) != 0)
            {
                // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if
                // the bit is not set.
                return((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0);
            }
            else
            {
                // for all the rest of the cases, just check whether there is any required typography
                // present at all. If none exists, it is optimizable. We might under-optimize here but
                // it will be non-major languages.
                return((typography & TypographyAvailabilities.Available) == 0);
            }
        }