예제 #1
0
        private unsafe FamilyCollection.CachedFamilyMap *GetCachedFamilyMap(
            CharacterBufferRange unicodeString,
            CultureInfo culture,
            CultureInfo digitCulture,
            out int cchAdvance
            )
        {
            cchAdvance = 0;
            DigitMap digitMap = new DigitMap(digitCulture);

            int     lengthOfRanges;
            ushort *ranges = _cachedFamily.FamilyCollection.GetFamilyMapRanges(
                _cachedFamily.CompositeFamily,
                culture,
                out lengthOfRanges
                );

            Debug.Assert(ranges != null);

            int sizeofChar = 0;
            int ch         = 0;

            cchAdvance = Classification.AdvanceWhile(unicodeString, ItemClass.JoinerClass);
            if (cchAdvance >= unicodeString.Length)
            {
                // It is rare that the run only contains joiner characters.
                // If it really happens, just map them to the initial family map.
                return(_cachedFamily.FamilyCollection.GetFamilyMapOfChar(
                           _cachedFamily.CompositeFamily,
                           ranges,
                           lengthOfRanges,
                           Classification.UnicodeScalar(unicodeString, out sizeofChar)
                           ));
            }


            //
            // If the run starts with combining marks, we will not be able to find base characters for them
            // within the run. These combining marks will be mapped to their best fonts as normal characters.
            //
            ch = Classification.UnicodeScalar(
                new CharacterBufferRange(unicodeString, cchAdvance, unicodeString.Length - cchAdvance),
                out sizeofChar
                );

            bool hasBaseChar = !Classification.IsCombining(ch);

            ch = digitMap[ch];
            FamilyCollection.CachedFamilyMap *familyMap =
                _cachedFamily.FamilyCollection.GetFamilyMapOfChar(_cachedFamily.CompositeFamily, ranges, lengthOfRanges, ch);

            for (cchAdvance += sizeofChar; cchAdvance < unicodeString.Length; cchAdvance += sizeofChar)
            {
                ch = Classification.UnicodeScalar(
                    new CharacterBufferRange(unicodeString, cchAdvance, unicodeString.Length - cchAdvance),
                    out sizeofChar
                    );

                if (Classification.IsJoiner(ch))
                {
                    continue; // continue to advance if current char is a joiner
                }
                if (!Classification.IsCombining(ch))
                {
                    hasBaseChar = true;
                }
                else if (hasBaseChar)
                {
                    continue; // continue to advance for combining mark with base char
                }

                ch = digitMap[ch];

                if (_cachedFamily.FamilyCollection.GetFamilyMapOfChar(_cachedFamily.CompositeFamily, ranges, lengthOfRanges, ch) != familyMap)
                {
                    break;
                }
            }

            return(familyMap);
        }
예제 #2
0
        /// <summary>
        /// Map character supported by the typeface
        /// </summary>
        /// <remarks>
        /// Combining mark is considered part of the character that may be supported
        /// thru precomposed form or OpenType glyph substitution table.
        /// </remarks>
        private int MapCharacters(
            MS.Internal.Text.TextInterface.Font font,
            CharacterBufferRange unicodeString,
            CultureInfo digitCulture,
            ref int nextValid
            )
        {
            DigitMap digitMap = new DigitMap(digitCulture);

            int sizeofChar = 0;
            int advance;

            // skip all the leading joiner characters. They need to be shaped with the
            // surrounding strong characters.
            advance = Classification.AdvanceWhile(unicodeString, ItemClass.JoinerClass);
            if (advance >= unicodeString.Length)
            {
                // It is rare that the run only contains joiner characters.
                // If it really happens, just return.
                return(advance);
            }

            //
            // If the run starts with combining marks, we will not be able to find base characters for them
            // within the run. These combining marks will be mapped to their best fonts as normal characters.
            //
            bool hasBaseChar = false;

            // Determine how many characters we can advance, i.e., find the first invalid character.
            for (; advance < unicodeString.Length; advance += sizeofChar)
            {
                // Get the character and apply digit substitution, if any.
                int originalChar = Classification.UnicodeScalar(
                    new CharacterBufferRange(unicodeString, advance, unicodeString.Length - advance),
                    out sizeofChar
                    );

                if (Classification.IsJoiner(originalChar))
                {
                    continue;
                }

                if (!Classification.IsCombining(originalChar))
                {
                    hasBaseChar = true;
                }
                else if (hasBaseChar)
                {
                    // continue to advance for combining mark with base char
                    continue;
                }

                int ch = digitMap[originalChar];

                if (font.HasCharacter(checked ((uint)ch)))
                {
                    continue;
                }

                // If ch is a substituted character, can we substitute a different character instead?
                if (ch != originalChar)
                {
                    ch = DigitMap.GetFallbackCharacter(ch);
                    if (ch != 0 && font.HasCharacter(checked ((uint)ch)))
                    {
                        continue;
                    }
                }

                // If we fall through to here it's invalid.
                break;
            }

            // UnicodeScalar won't return a sizeofChar that exceeds the string length.
            Debug.Assert(advance <= unicodeString.Length);

            // Find the next valid character.
            if (advance < unicodeString.Length)
            {
                // UnicodeScalar won't return a sizeofChar that exceeds the string length.
                Debug.Assert(advance + sizeofChar <= unicodeString.Length);

                for (nextValid = advance + sizeofChar; nextValid < unicodeString.Length; nextValid += sizeofChar)
                {
                    // Get the character.
                    int originalChar = Classification.UnicodeScalar(
                        new CharacterBufferRange(unicodeString, nextValid, unicodeString.Length - nextValid),
                        out sizeofChar
                        );

                    // Apply digit substitution, if any.
                    int ch = digitMap[originalChar];

                    //
                    // Combining mark should always be shaped by the same font as the base char.
                    // If the physical font is invalid for the base char, it should also be invalid for the
                    // following combining mark so that both characters will go onto the same fallback font.
                    // - When the fallback font is physical font, the font will be valid for both characters
                    //   if and only if it is valid for the base char. Otherwise, it will be invalid for both.
                    // - When the fallback font is composite font, it maps the combining mark to the same font
                    //   as the base char such that they will eventually be resolved to the same physical font.
                    //   That means FamilyMap for the combining mark is not used when it follows a base char.
                    //
                    // The same goes for joiner. Note that "hasBaseChar" here indicates if there is an invalid base
                    // char in front.
                    if (Classification.IsJoiner(ch) ||
                        (hasBaseChar && Classification.IsCombining(ch))
                        )
                    {
                        continue;
                    }

                    // If we have a glyph it's valid.
                    if (font.HasCharacter(checked ((uint)ch)))
                    {
                        break;
                    }

                    // If ch is a substituted character, can we substitute a different character instead?
                    if (ch != originalChar)
                    {
                        ch = DigitMap.GetFallbackCharacter(ch);
                        if (ch != 0 && font.HasCharacter(checked ((uint)ch)))
                        {
                            break;
                        }
                    }
                }
            }

            return(advance);
        }
예제 #3
0
        private FontFamilyMap GetTargetFamilyMap(
            CharacterBufferRange unicodeString,
            CultureInfo culture,
            CultureInfo digitCulture,
            out int cchAdvance
            )
        {
            DigitMap digitMap = new DigitMap(digitCulture);

            ushort[] familyMaps = _fontInfo.GetFamilyMapsOfLanguage(XmlLanguage.GetLanguage(culture.IetfLanguageTag));

            int sizeofChar = 0;
            int ch         = 0;

            // skip all the leading joinder characters. They need to be shaped with the
            // surrounding strong characters.
            cchAdvance = Classification.AdvanceWhile(unicodeString, ItemClass.JoinerClass);

            if (cchAdvance >= unicodeString.Length)
            {
                // It is rare that the run only contains joiner characters.
                // If it really happens, just map them to the initial family map.
                return(_fontInfo.GetFamilyMapOfChar(
                           familyMaps,
                           Classification.UnicodeScalar(unicodeString, out sizeofChar)
                           ));
            }

            //
            // If the run starts with combining marks, we will not be able to find base characters for them
            // within the run. These combining marks will be mapped to their best fonts as normal characters.
            //
            ch = Classification.UnicodeScalar(
                new CharacterBufferRange(unicodeString, cchAdvance, unicodeString.Length - cchAdvance),
                out sizeofChar
                );

            bool hasBaseChar = !Classification.IsCombining(ch);

            ch = digitMap[ch];
            FontFamilyMap familyMap = _fontInfo.GetFamilyMapOfChar(familyMaps, ch);

            Invariant.Assert(familyMap != null);

            for (cchAdvance += sizeofChar; cchAdvance < unicodeString.Length; cchAdvance += sizeofChar)
            {
                ch = Classification.UnicodeScalar(
                    new CharacterBufferRange(unicodeString, cchAdvance, unicodeString.Length - cchAdvance),
                    out sizeofChar
                    );

                if (Classification.IsJoiner(ch))
                {
                    continue; // continue to advance if current char is a joiner
                }
                if (!Classification.IsCombining(ch))
                {
                    hasBaseChar = true;
                }
                else if (hasBaseChar)
                {
                    continue; // continue to advance for combining mark with base char
                }

                ch = digitMap[ch];

                if (_fontInfo.GetFamilyMapOfChar(familyMaps, ch) != familyMap)
                {
                    break;
                }
            }

            return(familyMap);
        }