Exemplo n.º 1
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;
        }
Exemplo n.º 2
0
        /// <summary> 
        /// Cache index to the list of scaled shapeable typeface 
        /// </summary>
        private void CacheScaledTypefaceMap( 
            CharacterBufferRange        unicodeString,
            CultureInfo                 culture,
            CultureInfo                 digitCulture,
            SpanVector                  scaledTypefaceSpans, 
            ref SpanVector<int>         cachedScaledTypefaceIndexSpans,
            int                         ichItem 
            ) 
        {
 
            IntMap map;
            if (!_intMaps.TryGetValue(culture, out map))
            {
                map = new IntMap(); 
                _intMaps.Add(culture, map);
            } 
 
            DigitMap digitMap = new DigitMap(digitCulture);
 
            SpanRider typefaceSpanRider = new SpanRider(scaledTypefaceSpans);

            int ich = 0;
            while(ich < unicodeString.Length) 
            {
                typefaceSpanRider.At(ich); 
 
                int cch = Math.Min(unicodeString.Length - ich, typefaceSpanRider.Length);
 
                int index = IndexOfScaledTypeface((ScaledShapeTypeface)typefaceSpanRider.CurrentElement);
                Debug.Assert(index >= 0, "Invalid scaled shapeable typeface index spans");

                cachedScaledTypefaceIndexSpans.Set(ichItem + ich, cch, index); 

                // we keep index + 1 in the map, so that we leave map entry zero 
                // to indicate uninitialized entry. 
                index++;
 
                int sizeofChar;
                for (int c = 0; c < cch; c += sizeofChar)
                {
                    int ch = digitMap[ 
                        Classification.UnicodeScalar(
                            new CharacterBufferRange(unicodeString, ich + c, unicodeString.Length - ich - c), 
                            out sizeofChar 
                        )
                    ]; 

                    // only cache typeface map index for base characters
                    if(!Classification.IsCombining(ch) && !Classification.IsJoiner(ch))
                    { 
                        // Dump values of local variables when the condition fails for better debuggability.
                        // We use "if" to avoid the expensive string.Format() in normal case. 
                        if (map[ch] != 0 && map[ch] != index) 
                        {
                            Invariant.Assert( 
                                false,
                                string.Format(
                                    CultureInfo.InvariantCulture,
                                    "shapeable cache stores conflicting info, ch = {0}, map[ch] = {1}, index = {2}", 
                                    ch, map[ch], index
                                ) 
                            ); 
                        }
 
                        map[ch] = (ushort)index;
                    }
                }
 
                ich += cch;
            } 
        } 
Exemplo n.º 3
0
        /// <summary>
        /// Map characters by font family 
        /// </summary>
        /// <remarks>
        /// Advance:
        ///     number of characters not mapped to missing glyph 
        ///
        /// NextValid: 
        ///     Offset to the nearest first character not mapped to missing glyph 
        ///
        /// [Number of invalid characters following valid ones] = NextValid - Advance 
        ///
        ///         A B C D E F G H x x x x x F G H I J
        ///         --------------->
        ///             Advance 
        ///
        ///         -------------------------> 
        ///                NextValid 
        ///
        /// </remarks> 
        private int MapByFontFamily(
            CharacterBufferRange            unicodeString,
            CultureInfo                     culture,
            CultureInfo                     digitCulture, 
            IFontFamily                     fontFamily,
            CanonicalFontFamilyReference    canonicalFamilyReference, 
            FontStyle                       canonicalStyle, 
            FontWeight                      canonicalWeight,
            FontStretch                     canonicalStretch, 
            ref PhysicalFontFamily          firstValidFamily,
            ref int                         firstValidLength,
            IDeviceFont                     deviceFont,
            double                          scaleInEm, 
            int                             recursionDepth,
            SpanVector                      scaledTypefaceSpans, 
            int                             firstCharIndex, 
            out int                         nextValid
            ) 
        {
            // This is the *one* place where we check for the font mapping depths of the font linking
            // process. This protects the linking process against extremely long chain of linking or
            // circular dependencies in the composite fonts. 
            if (recursionDepth >= MaxTypefaceMapDepths)
            { 
                // Stop the recursion. In effect, this FontFamily does not map any of the input. 
                // Higher-level code must map the input text to some other FontFamily, or to the
                // "null font" if there is no valid FontFamily. 
                nextValid = 0;
                return 0;
            }
 
            // If a device font is not already specified higher up the stack, look for a device font
            // for this font family that matches the typeface style, weight, and stretch. 
            if (deviceFont == null) 
            {
                deviceFont = fontFamily.GetDeviceFont(_canonicalStyle, _canonicalWeight, _canonicalStretch); 
            }

            DigitMap digitMap = new DigitMap(digitCulture);
 
            int advance = 0;
            int cchAdvance; 
            int cchNextValid; 
            int ich = 0;
 
            nextValid = 0;

            bool terminated = false;
 
            while (ich < unicodeString.Length  &&  !terminated)
            { 
                // Determine length of run with consistent mapping. Start by assuming we'll be able to 
                // use the whole string, then reduce to the length that can be mapped consistently.
                int cchMap = unicodeString.Length - ich; 

                // Determine whether the run is using a device font, and limit the run to the
                // first boundary between device/non-device font usage.
                bool useDeviceFont = false; 
                if (deviceFont != null)
                { 
                    // Determine whether the first run uses a device font by inspecting the first character. 
                    // We do not support device fonts for codepoints >= U+10000 (aka surrogates), so we
                    // don't need to call Classification.UnicodeScalar. 
                    useDeviceFont = deviceFont.ContainsCharacter(digitMap[unicodeString[ich]]);

                    // Advance as long as 'useDeviceFont' remains unchanged.
                    int i = ich + 1; 
                    while (    (i < unicodeString.Length)
                           &&  (useDeviceFont == deviceFont.ContainsCharacter(digitMap[unicodeString[i]]))) 
                    { 
                        i++;
                    } 

                    cchMap = i - ich;
                }
 

                // Map as many characters to a family as we can up to the limit (cchMap) just determined. 
                string targetFamilyName; 
                double mapSizeInEm;
 
                bool isCompositeFontFamily = fontFamily.GetMapTargetFamilyNameAndScale(
                    new CharacterBufferRange(
                        unicodeString,
                        ich, 
                        cchMap
                        ), 
                    culture, 
                    digitCulture,
                    scaleInEm, 
                    out cchMap,
                    out targetFamilyName,
                    out mapSizeInEm
                    ); 

                Debug.Assert(cchMap <= unicodeString.Length - ich); 
 
                CharacterBufferRange mappedString = new CharacterBufferRange(
                    unicodeString, 
                    ich,
                    cchMap
                    );
 

                if (!isCompositeFontFamily) 
                { 
                    // not a composite font family
                    cchAdvance = MapByFontFaceFamily( 
                        mappedString,
                        culture,
                        digitCulture,
                        fontFamily, 
                        canonicalStyle,
                        canonicalWeight, 
                        canonicalStretch, 
                        ref firstValidFamily,
                        ref firstValidLength, 
                        useDeviceFont ? deviceFont : null,
                        false, // nullFont
                        mapSizeInEm,
                        scaledTypefaceSpans, 
                        firstCharIndex + ich,
                        false, // ignoreMissing 
                        out cchNextValid 
                        );
                } 
                else if (!string.IsNullOrEmpty(targetFamilyName))
                {
                    // The base Uri used for resolving target family names is the Uri of the composite font.
                    Uri baseUri = (canonicalFamilyReference != null) ? canonicalFamilyReference.LocationUri : null; 

                    // map to the target of the family map 
                    cchAdvance = MapByFontFamilyName( 
                        mappedString,
                        culture, 
                        digitCulture,
                        targetFamilyName,
                        baseUri,
                        ref firstValidFamily, 
                        ref firstValidLength,
                        useDeviceFont ? deviceFont : null, 
                        mapSizeInEm, 
                        recursionDepth + 1, // increment the depth
                        scaledTypefaceSpans, 
                        firstCharIndex + ich,
                        out cchNextValid
                        );
                } 
                else
                { 
                    // family map lookup returned no target family 
                    cchAdvance = 0;
                    cchNextValid = cchMap; 
                }

                int cchValid = cchMap;
                int cchInvalid = 0; 

                cchValid = cchAdvance; 
                cchInvalid = cchNextValid; 

                if(cchValid < cchMap) 
                {
                    terminated = true;
                }
 
                advance += cchValid;
                nextValid = ich + cchInvalid; 
 
                ich += cchValid;
            } 

            return advance;
        }
Exemplo n.º 4
0
        /// <summary>
        /// Get spans of index to the list of scaled shapeable typeface of the specified
        /// character string from the map table
        /// </summary> 
        private bool GetCachedScaledTypefaceMap(
            CharacterBufferRange        unicodeString, 
            CultureInfo                 culture, 
            CultureInfo                 digitCulture,
            ref SpanVector<int>         cachedScaledTypefaceIndexSpans, 
            int                         ichItem
            )
        {
            IntMap map; 
            if (!_intMaps.TryGetValue(culture, out map))
            { 
                return false; 
            }
 
            DigitMap digitMap = new DigitMap(digitCulture);

            int ich = 0;
            while (ich < unicodeString.Length) 
            {
                // Get map entry for first character. 
                int sizeofChar; 
                int ch = digitMap[
                    Classification.UnicodeScalar( 
                        new CharacterBufferRange(unicodeString, ich, unicodeString.Length - ich),
                        out sizeofChar
                    )
                ]; 

                ushort firstIndex = map[ch]; 
                if (firstIndex == 0) 
                    return false;
 
                // Advance past subsequent characters with the same mapping.
                int cchSpan = sizeofChar;
                for (; ich + cchSpan < unicodeString.Length; cchSpan += sizeofChar)
                { 
                    ch = digitMap[
                        Classification.UnicodeScalar( 
                            new CharacterBufferRange(unicodeString, ich + cchSpan, unicodeString.Length - ich - cchSpan), 
                            out sizeofChar
                        ) 
                    ];

                    if (map[ch] != firstIndex && !Classification.IsCombining(ch) && !Classification.IsJoiner(ch))
                        break; 
                }
 
                // map entry is stored in index+1, since 0 indicates uninitialized entry 
                cachedScaledTypefaceIndexSpans.Set(ichItem + ich, cchSpan, firstIndex - 1);
                ich += cchSpan; 
            }
            return true;
        }