CachedCompositeFamily.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / MS / Internal / FontFace / CachedCompositeFamily.cs / 1 / CachedCompositeFamily.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: The CachedCompositeFamily class 
//
// History: 
//  08/01/2003 : mleonov - Created
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections; 
using System.Collections.Generic; 
using System.Diagnostics;
using System.Globalization; 
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Windows; 
using System.Windows.Markup;    // for XmlLanguage
using System.Windows.Media; 
using System.Windows.Media.TextFormatting; 
 // External Team
 

using MS.Utility;
using MS.Internal;
using MS.Internal.FontCache; 
using MS.Internal.Shaping;
using MS.Internal.TextFormatting; 
 
namespace MS.Internal.FontFace
{ 
    /// 
    /// CachedCompositeFamily class represents a composite font family obtained from .CompositeFont file.
    /// 
    internal class CachedCompositeFamily : IFontFamily 
    {
        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
 
        /// 
        /// Critical - takes in canonical name and unsafe struct of CachedFontFamily 
        ///  
        [SecurityCritical]
        internal unsafe CachedCompositeFamily(CachedFontFamily cachedFamily) 
        {
            Debug.Assert(!cachedFamily.IsNull);
            _cachedFamily = cachedFamily;
        } 

        #endregion Constructors 
 
        //------------------------------------------------------
        // 
        //  Internal Methods
        //
        //-----------------------------------------------------
 
        #region Internal Methods
 
 
        /// 
        /// Get typeface metrics of the specified style 
        /// 
        /// 
        ///    Critical: This accesses a pointer uses unsafe code. The risk here is in derefrencing pointers.
        ///    TreatAsSafe: This information is ok to return also the call to the pointers to get CompositeFace has 
        ///    checking to ensure that you are not dereferencing a null pointer
        ///  
        [SecurityCritical,SecurityTreatAsSafe] 
        ITypefaceMetrics IFontFamily.GetTypefaceMetrics(
            FontStyle       style, 
            FontWeight      weight,
            FontStretch     stretch
            )
        { 
            CachedFontFace bestFace = FindNearestTypeface(style, weight, stretch);
            if (!bestFace.IsNull) 
            { 
                unsafe
                { 
                    return new CompositeTypefaceMetrics(
                        bestFace.CompositeFace->underlinePosition,
                        bestFace.CompositeFace->underlineThickness,
                        bestFace.CompositeFace->strikeThroughPosition, 
                        bestFace.CompositeFace->strikeThroughThickness,
                        bestFace.CompositeFace->capsHeight, 
                        bestFace.CompositeFace->xHeight, 
                        bestFace.CompositeFace->fontStyle,
                        bestFace.CompositeFace->fontWeight, 
                        bestFace.CompositeFace->fontStretch
                        );
                }
            } 
            else
            { 
                return new CompositeTypefaceMetrics(); 
            }
        } 


        /// 
        /// Look up device font for the typeface. 
        /// 
        ///  
        /// Critical - as it contains unsafe code 
        /// TreatAsSafe - because it only returns an IDeviceFont which is safe
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        IDeviceFont IFontFamily.GetDeviceFont(FontStyle style, FontWeight weight, FontStretch stretch)
        {
            CachedFontFace bestFace = FindExactTypeface(style, weight, stretch); 
            if (!bestFace.IsNull)
            { 
                unsafe 
                {
                    int offsetToDeviceFont = bestFace.CompositeFace->offsetToDeviceFont; 
                    if (offsetToDeviceFont != 0)
                    {
                        return new DeviceFont(
                            _cachedFamily, 
                            bestFace.CheckedPointer + offsetToDeviceFont
                            ); 
                    } 
                }
            } 
            return null;
        }

 
        /// 
        /// Find the face exactly matching the specified style, weight and stretch. 
        /// Returns CachedFontFace.Null if there is no matching face. 
        /// 
        private CachedFontFace FindExactTypeface(FontStyle style, FontWeight weight, FontStretch stretch) 
        {
            MatchingStyle target = new MatchingStyle(style, weight, stretch);

            for (int i = 0; i < _cachedFamily.NumberOfFaces; i++) 
            {
                CachedFontFace currentFace = _cachedFamily.FamilyCollection.GetCachedFace(_cachedFamily, i); 
                if (currentFace.MatchingStyle == target) 
                {
                    return currentFace; 
                }
            }

            return CachedFontFace.Null; 
        }
 
 
        /// 
        /// Find the face most closely matching the specified style, weight and stretch. 
        /// Returns CachedFontFace.Null if there is no available face.
        /// 
        private CachedFontFace FindNearestTypeface(FontStyle style, FontWeight weight, FontStretch stretch)
        { 
            if (_cachedFamily.NumberOfFaces == 0)
            { 
                return CachedFontFace.Null; 
            }
 
            MatchingStyle target = new MatchingStyle(style, weight, stretch);
            CachedFontFace bestFace = _cachedFamily.FamilyCollection.GetCachedFace(_cachedFamily, 0);
            MatchingStyle bestMatch = bestFace.MatchingStyle;
 
            for (int i = 1; i < _cachedFamily.NumberOfFaces; i++)
            { 
                CachedFontFace currentFace = _cachedFamily.FamilyCollection.GetCachedFace(_cachedFamily, i); 
                MatchingStyle currentMatch = currentFace.MatchingStyle;
                if (MatchingStyle.IsBetterMatch(target, bestMatch, ref currentMatch)) 
                {
                    bestMatch = currentMatch;
                    bestFace = currentFace;
                } 
            }
 
            return bestFace; 
        }
 

        /// 
        /// Get family name correspondent to the first n-characters of the specified character string
        ///  
        /// character string
        /// text culture info 
        /// culture used for digit subsitution or null 
        /// default size relative to em
        /// number of characters advanced 
        /// target family name
        /// size relative to em
        /// number of character sharing the same family name and size
        ///  
        ///
        /// Null target family name returned indicates that the font family cannot find target 
        /// name of the character range being advanced. 
        ///
        /// Return value false indicates that the font family has no character map. 
        /// It is a font face family.
        ///
        /// 
        ///  
        ///     Critical: This code calls into GetCachedFamilyMap which returns a pointer
        ///     TreatAsSafe: It does not expose the pointer and this information is ok to expose 
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        unsafe bool IFontFamily.GetMapTargetFamilyNameAndScale( 
            CharacterBufferRange    unicodeString,
            CultureInfo             culture,
            CultureInfo             digitCulture,
            double                  defaultSizeInEm, 
            out int                 cchAdvance,
            out string              targetFamilyName, 
            out double              scaleInEm 
            )
        { 
            Invariant.Assert(unicodeString.CharacterBuffer != null && unicodeString.Length > 0);
            Invariant.Assert(culture != null);

            // Get the family map. This will find the first family map that matches 
            // the specified culture, an ancestor neutral culture, or "any" culture.
            FamilyCollection.CachedFamilyMap * familyMap = GetCachedFamilyMap( 
                unicodeString, 
                culture,
                digitCulture, 
                out cchAdvance
                );

            if (familyMap == null) 
            {
                targetFamilyName = null; 
                scaleInEm = 1; 
            }
            else 
            {
                int* sizePrefix = (int*)((byte*)familyMap + familyMap->targetFamilyNameOffset);
                targetFamilyName = Util.StringCopyFromUncheckedPointer(sizePrefix + 1, *sizePrefix);
                scaleInEm = familyMap->scaleInEm; 
            }
 
            return true; 
        }
 
        /// 
        ///     Critical: This code calls utilizes unsafe code blocks to extract the CachedFamilyMap.
        ///     The pointer checking for the unicode string is done in the UnicodeScalar. At the same time
        ///     GetFamilyMapRange takes _cachedFamily which cannot be instantiated with a null value.And its value 
        ///     cannot be set outside of the constructor. It is critical because it exposes a pointer
        ///  
        [SecurityCritical] 
        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; 
        }
 
 

        #endregion Internal Methods 

        //------------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region IFontFamily Properties
 
        /// 
        /// Font family name table indexed by culture
        /// 
        IDictionary IFontFamily.Names 
        {
            get 
            { 
                return _cachedFamily.Names;
            } 
        }


        ///  
        /// Distance from character cell top to English baseline relative to em size.
        ///  
        double IFontFamily.Baseline 
        {
            get 
            {
                if (_cachedFamily.Baseline != 0)
                    return _cachedFamily.Baseline;
                return GetFirstFontFamily().Baseline; 
            }
        } 
 

        ///  
        /// Recommended baseline-to-baseline distance for text in this font
        /// 
        double IFontFamily.LineSpacing
        { 
            get
            { 
                if (_cachedFamily.LineSpacing != 0) 
                    return _cachedFamily.LineSpacing;
                return GetFirstFontFamily().LineSpacing; 
            }
        }

        ICollection IFontFamily.GetTypefaces(FontFamilyIdentifier familyIdentifier) 
        {
            return new TypefaceCollection(new FontFamily(familyIdentifier), _cachedFamily); 
        } 

        #endregion Internal Properties 

        //-----------------------------------------------------
        //
        //  Private Methods 
        //
        //------------------------------------------------------ 
 
        #region Private Methods
 
        /// 
        /// Get the first font family of the first target family name
        /// 
        private IFontFamily GetFirstFontFamily() 
        {
            if(_firstFontFamily == null) 
            { 
                _firstFontFamily = FontFamily.FindFontFamilyFromFriendlyNameList(GetFirstTargetFamilyName());
                Debug.Assert(_firstFontFamily != null); 
            }
            return _firstFontFamily;
        }
 
        /// 
        ///     Critical: This code calls into CompositeFamily which returns a pointer 
        ///     TreatAsSafe: This returns a string with the target family name 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private string GetFirstTargetFamilyName()
        {
            unsafe
            { 
                return Util.StringAndLengthCopyFromCheckedPointer(
                    _cachedFamily.CheckedPointer + _cachedFamily.CompositeFamily->OffsetToTargetFamilyNameStrings 
                    ); 
            }
        } 

        #endregion Private Methods

        #region Private Classes 

        private class DeviceFont : IDeviceFont 
        { 
            /// 
            /// Critical - as we assume the caller is giving us a valid pointer 
            /// 
            [SecurityCritical]
            internal DeviceFont(CachedFontFamily cachedFamily, CheckedPointer deviceFont)
            { 
                unsafe
                { 
                    _cachedFamily = cachedFamily; 
                    _deviceFont = (FamilyCollection.CachedDeviceFont*)deviceFont.Probe(0, sizeof(FamilyCollection.CachedDeviceFont));
                    _sizeInBytes = deviceFont.Size; 
                }
            }

            string IDeviceFont.Name 
            {
                get 
                { 
                    return Util.StringAndLengthCopyFromCheckedPointer(
                        CheckedPointer + FamilyCollection.CachedDeviceFont.OffsetToLengthPrefixedName 
                        );
                }
            }
 
            /// 
            /// Critical - as it calls a critical method that returns a pointer 
            /// TreatAsSafe - because it does not expose the pointer 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            bool IDeviceFont.ContainsCharacter(int unicodeScalar)
            {
                unsafe
                { 
                    return LookupMetrics(unicodeScalar) != null;
                } 
            } 

            ///  
            /// Critical - As it uses raw pointers.
            /// 
            [SecurityCritical]
            unsafe void IDeviceFont.GetAdvanceWidths( 
                char*   characterString,
                int     characterLength, 
                double  emSize, 
                int*    pAdvances
            ) 
            {
                unsafe
                {
                    for (int i = 0; i < characterLength; ++i) 
                    {
                        FamilyCollection.CachedCharacterMetrics* metrics = LookupMetrics(characterString[i]); 
                        if (metrics != null) 
                        {
                            // Side bearings are included in the advance width but are not used as offsets for glyph positioning. 
                            pAdvances[i] = Math.Max(0, (int)((metrics->blackBoxWidth + metrics->leftSideBearing + metrics->rightSideBearing) * emSize));
                        }
                        else
                        { 
                            pAdvances[i] = 0;
                        } 
                    } 
                }
            } 

            /// 
            /// Critical - as it accesses a critical field, performs pointer arithmetic, and returns a pointer.
            ///  
            [SecurityCritical]
            private unsafe FamilyCollection.CachedCharacterMetrics* LookupMetrics(int unicodeScalar) 
            { 
                if (unicodeScalar >= 0 && unicodeScalar <= FontFamilyMap.LastUnicodeScalar)
                { 
                    int pageTableOffset = _deviceFont->OffsetToCharacterMap;

                    int* pageTable = (int*)CheckedPointer.Probe(
                        pageTableOffset, 
                        CharacterMetricsDictionary.PageCount * sizeof(int)
                        ); 
 
                    int i = pageTable[unicodeScalar >> CharacterMetricsDictionary.PageShift];
                    if (i != 0) 
                    {
                        int* page = (int*)CheckedPointer.Probe(
                            pageTableOffset + (i * sizeof(int)),
                            CharacterMetricsDictionary.PageSize * sizeof(int) 
                            );
 
                        int offset = page[unicodeScalar & CharacterMetricsDictionary.PageMask]; 
                        if (offset != 0)
                        { 
                            return (FamilyCollection.CachedCharacterMetrics*)CheckedPointer.Probe(
                                offset,
                                sizeof(FamilyCollection.CachedCharacterMetrics)
                                ); 
                        }
                    } 
                } 
                return null;
            } 

            /// 
            /// Critical - constructs a CheckedPointer which is a critical operation
            /// TreatAsSafe - the pointer and size fields used to construct the CheckedPointer are tracked and 
            ///               the CheckedPointer itself is safe to use
            ///  
            private CheckedPointer CheckedPointer 
            {
                [SecurityCritical,SecurityTreatAsSafe] 
                get
                {
                    unsafe
                    { 
                        return new CheckedPointer(_deviceFont, _sizeInBytes);
                    } 
                } 
            }
 
            private CachedFontFamily _cachedFamily;

            /// 
            /// Critical - as this field is a pointer and therefore unsafe. 
            /// 
            [SecurityCritical] 
            private unsafe FamilyCollection.CachedDeviceFont* _deviceFont; 

            ///  
            /// Critical - used for bounds checking via CheckedPointer
            /// 
            [SecurityCritical]
            private int _sizeInBytes; 
        }
 
        #endregion 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //----------------------------------------------------- 

        #region Private Fields 
 
        private CachedFontFamily    _cachedFamily;
 
        private IFontFamily         _firstFontFamily;

        #endregion Private Fields
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: The CachedCompositeFamily class 
//
// History: 
//  08/01/2003 : mleonov - Created
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections; 
using System.Collections.Generic; 
using System.Diagnostics;
using System.Globalization; 
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Windows; 
using System.Windows.Markup;    // for XmlLanguage
using System.Windows.Media; 
using System.Windows.Media.TextFormatting; 
 // External Team
 

using MS.Utility;
using MS.Internal;
using MS.Internal.FontCache; 
using MS.Internal.Shaping;
using MS.Internal.TextFormatting; 
 
namespace MS.Internal.FontFace
{ 
    /// 
    /// CachedCompositeFamily class represents a composite font family obtained from .CompositeFont file.
    /// 
    internal class CachedCompositeFamily : IFontFamily 
    {
        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
 
        /// 
        /// Critical - takes in canonical name and unsafe struct of CachedFontFamily 
        ///  
        [SecurityCritical]
        internal unsafe CachedCompositeFamily(CachedFontFamily cachedFamily) 
        {
            Debug.Assert(!cachedFamily.IsNull);
            _cachedFamily = cachedFamily;
        } 

        #endregion Constructors 
 
        //------------------------------------------------------
        // 
        //  Internal Methods
        //
        //-----------------------------------------------------
 
        #region Internal Methods
 
 
        /// 
        /// Get typeface metrics of the specified style 
        /// 
        /// 
        ///    Critical: This accesses a pointer uses unsafe code. The risk here is in derefrencing pointers.
        ///    TreatAsSafe: This information is ok to return also the call to the pointers to get CompositeFace has 
        ///    checking to ensure that you are not dereferencing a null pointer
        ///  
        [SecurityCritical,SecurityTreatAsSafe] 
        ITypefaceMetrics IFontFamily.GetTypefaceMetrics(
            FontStyle       style, 
            FontWeight      weight,
            FontStretch     stretch
            )
        { 
            CachedFontFace bestFace = FindNearestTypeface(style, weight, stretch);
            if (!bestFace.IsNull) 
            { 
                unsafe
                { 
                    return new CompositeTypefaceMetrics(
                        bestFace.CompositeFace->underlinePosition,
                        bestFace.CompositeFace->underlineThickness,
                        bestFace.CompositeFace->strikeThroughPosition, 
                        bestFace.CompositeFace->strikeThroughThickness,
                        bestFace.CompositeFace->capsHeight, 
                        bestFace.CompositeFace->xHeight, 
                        bestFace.CompositeFace->fontStyle,
                        bestFace.CompositeFace->fontWeight, 
                        bestFace.CompositeFace->fontStretch
                        );
                }
            } 
            else
            { 
                return new CompositeTypefaceMetrics(); 
            }
        } 


        /// 
        /// Look up device font for the typeface. 
        /// 
        ///  
        /// Critical - as it contains unsafe code 
        /// TreatAsSafe - because it only returns an IDeviceFont which is safe
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        IDeviceFont IFontFamily.GetDeviceFont(FontStyle style, FontWeight weight, FontStretch stretch)
        {
            CachedFontFace bestFace = FindExactTypeface(style, weight, stretch); 
            if (!bestFace.IsNull)
            { 
                unsafe 
                {
                    int offsetToDeviceFont = bestFace.CompositeFace->offsetToDeviceFont; 
                    if (offsetToDeviceFont != 0)
                    {
                        return new DeviceFont(
                            _cachedFamily, 
                            bestFace.CheckedPointer + offsetToDeviceFont
                            ); 
                    } 
                }
            } 
            return null;
        }

 
        /// 
        /// Find the face exactly matching the specified style, weight and stretch. 
        /// Returns CachedFontFace.Null if there is no matching face. 
        /// 
        private CachedFontFace FindExactTypeface(FontStyle style, FontWeight weight, FontStretch stretch) 
        {
            MatchingStyle target = new MatchingStyle(style, weight, stretch);

            for (int i = 0; i < _cachedFamily.NumberOfFaces; i++) 
            {
                CachedFontFace currentFace = _cachedFamily.FamilyCollection.GetCachedFace(_cachedFamily, i); 
                if (currentFace.MatchingStyle == target) 
                {
                    return currentFace; 
                }
            }

            return CachedFontFace.Null; 
        }
 
 
        /// 
        /// Find the face most closely matching the specified style, weight and stretch. 
        /// Returns CachedFontFace.Null if there is no available face.
        /// 
        private CachedFontFace FindNearestTypeface(FontStyle style, FontWeight weight, FontStretch stretch)
        { 
            if (_cachedFamily.NumberOfFaces == 0)
            { 
                return CachedFontFace.Null; 
            }
 
            MatchingStyle target = new MatchingStyle(style, weight, stretch);
            CachedFontFace bestFace = _cachedFamily.FamilyCollection.GetCachedFace(_cachedFamily, 0);
            MatchingStyle bestMatch = bestFace.MatchingStyle;
 
            for (int i = 1; i < _cachedFamily.NumberOfFaces; i++)
            { 
                CachedFontFace currentFace = _cachedFamily.FamilyCollection.GetCachedFace(_cachedFamily, i); 
                MatchingStyle currentMatch = currentFace.MatchingStyle;
                if (MatchingStyle.IsBetterMatch(target, bestMatch, ref currentMatch)) 
                {
                    bestMatch = currentMatch;
                    bestFace = currentFace;
                } 
            }
 
            return bestFace; 
        }
 

        /// 
        /// Get family name correspondent to the first n-characters of the specified character string
        ///  
        /// character string
        /// text culture info 
        /// culture used for digit subsitution or null 
        /// default size relative to em
        /// number of characters advanced 
        /// target family name
        /// size relative to em
        /// number of character sharing the same family name and size
        ///  
        ///
        /// Null target family name returned indicates that the font family cannot find target 
        /// name of the character range being advanced. 
        ///
        /// Return value false indicates that the font family has no character map. 
        /// It is a font face family.
        ///
        /// 
        ///  
        ///     Critical: This code calls into GetCachedFamilyMap which returns a pointer
        ///     TreatAsSafe: It does not expose the pointer and this information is ok to expose 
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        unsafe bool IFontFamily.GetMapTargetFamilyNameAndScale( 
            CharacterBufferRange    unicodeString,
            CultureInfo             culture,
            CultureInfo             digitCulture,
            double                  defaultSizeInEm, 
            out int                 cchAdvance,
            out string              targetFamilyName, 
            out double              scaleInEm 
            )
        { 
            Invariant.Assert(unicodeString.CharacterBuffer != null && unicodeString.Length > 0);
            Invariant.Assert(culture != null);

            // Get the family map. This will find the first family map that matches 
            // the specified culture, an ancestor neutral culture, or "any" culture.
            FamilyCollection.CachedFamilyMap * familyMap = GetCachedFamilyMap( 
                unicodeString, 
                culture,
                digitCulture, 
                out cchAdvance
                );

            if (familyMap == null) 
            {
                targetFamilyName = null; 
                scaleInEm = 1; 
            }
            else 
            {
                int* sizePrefix = (int*)((byte*)familyMap + familyMap->targetFamilyNameOffset);
                targetFamilyName = Util.StringCopyFromUncheckedPointer(sizePrefix + 1, *sizePrefix);
                scaleInEm = familyMap->scaleInEm; 
            }
 
            return true; 
        }
 
        /// 
        ///     Critical: This code calls utilizes unsafe code blocks to extract the CachedFamilyMap.
        ///     The pointer checking for the unicode string is done in the UnicodeScalar. At the same time
        ///     GetFamilyMapRange takes _cachedFamily which cannot be instantiated with a null value.And its value 
        ///     cannot be set outside of the constructor. It is critical because it exposes a pointer
        ///  
        [SecurityCritical] 
        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; 
        }
 
 

        #endregion Internal Methods 

        //------------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region IFontFamily Properties
 
        /// 
        /// Font family name table indexed by culture
        /// 
        IDictionary IFontFamily.Names 
        {
            get 
            { 
                return _cachedFamily.Names;
            } 
        }


        ///  
        /// Distance from character cell top to English baseline relative to em size.
        ///  
        double IFontFamily.Baseline 
        {
            get 
            {
                if (_cachedFamily.Baseline != 0)
                    return _cachedFamily.Baseline;
                return GetFirstFontFamily().Baseline; 
            }
        } 
 

        ///  
        /// Recommended baseline-to-baseline distance for text in this font
        /// 
        double IFontFamily.LineSpacing
        { 
            get
            { 
                if (_cachedFamily.LineSpacing != 0) 
                    return _cachedFamily.LineSpacing;
                return GetFirstFontFamily().LineSpacing; 
            }
        }

        ICollection IFontFamily.GetTypefaces(FontFamilyIdentifier familyIdentifier) 
        {
            return new TypefaceCollection(new FontFamily(familyIdentifier), _cachedFamily); 
        } 

        #endregion Internal Properties 

        //-----------------------------------------------------
        //
        //  Private Methods 
        //
        //------------------------------------------------------ 
 
        #region Private Methods
 
        /// 
        /// Get the first font family of the first target family name
        /// 
        private IFontFamily GetFirstFontFamily() 
        {
            if(_firstFontFamily == null) 
            { 
                _firstFontFamily = FontFamily.FindFontFamilyFromFriendlyNameList(GetFirstTargetFamilyName());
                Debug.Assert(_firstFontFamily != null); 
            }
            return _firstFontFamily;
        }
 
        /// 
        ///     Critical: This code calls into CompositeFamily which returns a pointer 
        ///     TreatAsSafe: This returns a string with the target family name 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private string GetFirstTargetFamilyName()
        {
            unsafe
            { 
                return Util.StringAndLengthCopyFromCheckedPointer(
                    _cachedFamily.CheckedPointer + _cachedFamily.CompositeFamily->OffsetToTargetFamilyNameStrings 
                    ); 
            }
        } 

        #endregion Private Methods

        #region Private Classes 

        private class DeviceFont : IDeviceFont 
        { 
            /// 
            /// Critical - as we assume the caller is giving us a valid pointer 
            /// 
            [SecurityCritical]
            internal DeviceFont(CachedFontFamily cachedFamily, CheckedPointer deviceFont)
            { 
                unsafe
                { 
                    _cachedFamily = cachedFamily; 
                    _deviceFont = (FamilyCollection.CachedDeviceFont*)deviceFont.Probe(0, sizeof(FamilyCollection.CachedDeviceFont));
                    _sizeInBytes = deviceFont.Size; 
                }
            }

            string IDeviceFont.Name 
            {
                get 
                { 
                    return Util.StringAndLengthCopyFromCheckedPointer(
                        CheckedPointer + FamilyCollection.CachedDeviceFont.OffsetToLengthPrefixedName 
                        );
                }
            }
 
            /// 
            /// Critical - as it calls a critical method that returns a pointer 
            /// TreatAsSafe - because it does not expose the pointer 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            bool IDeviceFont.ContainsCharacter(int unicodeScalar)
            {
                unsafe
                { 
                    return LookupMetrics(unicodeScalar) != null;
                } 
            } 

            ///  
            /// Critical - As it uses raw pointers.
            /// 
            [SecurityCritical]
            unsafe void IDeviceFont.GetAdvanceWidths( 
                char*   characterString,
                int     characterLength, 
                double  emSize, 
                int*    pAdvances
            ) 
            {
                unsafe
                {
                    for (int i = 0; i < characterLength; ++i) 
                    {
                        FamilyCollection.CachedCharacterMetrics* metrics = LookupMetrics(characterString[i]); 
                        if (metrics != null) 
                        {
                            // Side bearings are included in the advance width but are not used as offsets for glyph positioning. 
                            pAdvances[i] = Math.Max(0, (int)((metrics->blackBoxWidth + metrics->leftSideBearing + metrics->rightSideBearing) * emSize));
                        }
                        else
                        { 
                            pAdvances[i] = 0;
                        } 
                    } 
                }
            } 

            /// 
            /// Critical - as it accesses a critical field, performs pointer arithmetic, and returns a pointer.
            ///  
            [SecurityCritical]
            private unsafe FamilyCollection.CachedCharacterMetrics* LookupMetrics(int unicodeScalar) 
            { 
                if (unicodeScalar >= 0 && unicodeScalar <= FontFamilyMap.LastUnicodeScalar)
                { 
                    int pageTableOffset = _deviceFont->OffsetToCharacterMap;

                    int* pageTable = (int*)CheckedPointer.Probe(
                        pageTableOffset, 
                        CharacterMetricsDictionary.PageCount * sizeof(int)
                        ); 
 
                    int i = pageTable[unicodeScalar >> CharacterMetricsDictionary.PageShift];
                    if (i != 0) 
                    {
                        int* page = (int*)CheckedPointer.Probe(
                            pageTableOffset + (i * sizeof(int)),
                            CharacterMetricsDictionary.PageSize * sizeof(int) 
                            );
 
                        int offset = page[unicodeScalar & CharacterMetricsDictionary.PageMask]; 
                        if (offset != 0)
                        { 
                            return (FamilyCollection.CachedCharacterMetrics*)CheckedPointer.Probe(
                                offset,
                                sizeof(FamilyCollection.CachedCharacterMetrics)
                                ); 
                        }
                    } 
                } 
                return null;
            } 

            /// 
            /// Critical - constructs a CheckedPointer which is a critical operation
            /// TreatAsSafe - the pointer and size fields used to construct the CheckedPointer are tracked and 
            ///               the CheckedPointer itself is safe to use
            ///  
            private CheckedPointer CheckedPointer 
            {
                [SecurityCritical,SecurityTreatAsSafe] 
                get
                {
                    unsafe
                    { 
                        return new CheckedPointer(_deviceFont, _sizeInBytes);
                    } 
                } 
            }
 
            private CachedFontFamily _cachedFamily;

            /// 
            /// Critical - as this field is a pointer and therefore unsafe. 
            /// 
            [SecurityCritical] 
            private unsafe FamilyCollection.CachedDeviceFont* _deviceFont; 

            ///  
            /// Critical - used for bounds checking via CheckedPointer
            /// 
            [SecurityCritical]
            private int _sizeInBytes; 
        }
 
        #endregion 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //----------------------------------------------------- 

        #region Private Fields 
 
        private CachedFontFamily    _cachedFamily;
 
        private IFontFamily         _firstFontFamily;

        #endregion Private Fields
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK