FamilyCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / FontCache / FamilyCollection.cs / 1407647 / FamilyCollection.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: FamilyCollection font cache element class is responsible for 
// storing the mapping between a folder and font families in it.
// 
// History: 
//  07/23/2003 : mleonov - Big rewrite to change cache structure.
//  03/04/2004 : mleonov - Cache layout and interface changes for font enumeration. 
//  11/04/2005 : mleonov - Refactoring to support font disambiguation.
//  08/08/2008 : [....] - Integrating with DWrite.
//
//--------------------------------------------------------------------------- 

using System; 
using System.Collections; 
using System.Collections.Generic;
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions; 
using System.Windows; 
using System.Windows.Markup;    // for XmlLanguage
using System.Windows.Media; 

using MS.Win32;
using MS.Utility;
using MS.Internal; 
using MS.Internal.FontFace;
using MS.Internal.PresentationCore; 
using MS.Internal.Shaping; 

// Since we disable PreSharp warnings in this file, we first need to disable warnings about unknown message numbers and unknown pragmas. 
#pragma warning disable 1634, 1691

namespace MS.Internal.FontCache
{ 
    /// 
    /// FamilyCollection font cache element class is responsible for 
    /// storing the mapping between a folder and font families in it 
    /// 
    [FriendAccessAllowed] 
    internal class FamilyCollection
    {
        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private Text.TextInterface.FontCollection _fontCollection;
        private Uri                               _folderUri;
        private List         _userCompositeFonts; 
        private const string                      _sxsFontsRelativeLocation = @"WPF\Fonts\";
        private static object                     _staticLock = new object(); 
 
        /// 
        ///  Critical : contains the location of the .Net framework installation. 
        /// 
        [SecurityCritical]
        private static string _sxsFontsLocation;
 
        #endregion Private Fields
 
        internal static string SxSFontsLocation 
        {
            ///  
            ///  Critical : exposes security critical _sxsFontsLocation and calls into
            ///  security critical method GetSystemSxSFontsLocation.
            /// 
            [SecurityCritical] 
            get
            { 
                if (_sxsFontsLocation == String.Empty) 
                {
                    lock (_staticLock) 
                    {
                        if (_sxsFontsLocation == String.Empty)
                        {
                            _sxsFontsLocation = GetSystemSxSFontsLocation(); 
                        }
                    } 
                } 
                return _sxsFontsLocation;
            } 
        }

        /// 
        ///  Critical : Reads the registry and asserts permissions. 
        /// 
        [SecurityCritical] 
        private static string GetSystemSxSFontsLocation() 
        {
            RegistryPermission registryPermission = new RegistryPermission( 
                                                        RegistryPermissionAccess.Read,
                                                        RegistryKeys.FRAMEWORK_RegKey_FullPath);
            registryPermission.Assert(); // BlessedAssert
 
            try
            { 
                using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(MS.Internal.RegistryKeys.FRAMEWORK_RegKey)) 
                {
                    // The registry key should be present on a valid WPF installation. 
                    Invariant.Assert(key != null);

                    string frameworkInstallPath = key.GetValue(RegistryKeys.FRAMEWORK_InstallPath_RegValue) as string;
                    CheckFrameworkInstallPath(frameworkInstallPath); 
                    return System.IO.Path.Combine(frameworkInstallPath, _sxsFontsRelativeLocation);
                } 
            } 
            finally
            { 
                CodeAccessPermission.RevertAssert();
            }
        }
 
        private static void CheckFrameworkInstallPath(string frameworkInstallPath)
        { 
            if (frameworkInstallPath == null) 
            {
                throw new ArgumentNullException("frameworkInstallPath", SR.Get(SRID.FamilyCollection_CannotFindCompositeFontsLocation)); 
            }
        }

        ///  
        ///     Critical    : Accesses the Security Critical FontSource.GetStream().
        ///     TreatAsSafe : Does not expose this stream publicly. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private static List GetCompositeFontList(FontSourceCollection fontSourceCollection) 
        {
            List compositeFonts = new List();

            foreach (FontSource fontSource in fontSourceCollection) 
            {
                if (fontSource.IsComposite) 
                { 
                    CompositeFontInfo fontInfo = CompositeFontParser.LoadXml(fontSource.GetStream());
                    CompositeFontFamily compositeFamily = new CompositeFontFamily(fontInfo); 
                    compositeFonts.Add(compositeFamily);
                }
            }
 
            return compositeFonts;
        } 
 
        private bool UseSystemFonts
        { 
            /// 
            ///     Critical    : Access the security critical DWriteFactory.SystemFontCollection.
            ///     TreatAsSafe : Does not modify it.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            { 
                return (_fontCollection == DWriteFactory.SystemFontCollection);
            } 
        }

        private IList UserCompositeFonts
        { 
            /// 
            ///     Critical    : Contructs security critical FontSourceCollection. 
            ///     TreatAsSafe : Does not expose critical info from this object publicly. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                if (_userCompositeFonts == null)
                { 
                    _userCompositeFonts = GetCompositeFontList(new FontSourceCollection(_folderUri, false, true));
                } 
                return _userCompositeFonts; 
            }
        } 

        private static class LegacyArabicFonts
        {
            private static bool              _usePrivateFontCollectionIsInitialized = false; 
            private static object            _staticLock = new object();
            private static bool              _usePrivateFontCollectionForLegacyArabicFonts; 
            private static readonly string[] _legacyArabicFonts; 
            private static Text.TextInterface.FontCollection _legacyArabicFontCollection;
 

            static LegacyArabicFonts()
            {
                _legacyArabicFonts = new string[] { "Traditional Arabic", 
                                                    "Andalus",
                                                    "Simplified Arabic", 
                                                    "Simplified Arabic Fixed" }; 
            }
 
            internal static Text.TextInterface.FontCollection LegacyArabicFontCollection
            {
                /// 
                ///     Critical    : Accesses FamilyCollection.SxSFontsLocation security critical. 
                ///                 : Asserts to get a FontCollection by full path
                ///     TreatAsSafe : Does not expose security critical data. 
                ///  
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                {
                    if (_legacyArabicFontCollection == null)
                    {
                        lock (_staticLock) 
                        {
                            if (_legacyArabicFontCollection == null) 
                            { 
                                Uri criticalSxSFontsLocation = new Uri(FamilyCollection.SxSFontsLocation);
                                SecurityHelper.CreateUriDiscoveryPermission(criticalSxSFontsLocation).Assert(); 
                                try
                                {
                                    _legacyArabicFontCollection = DWriteFactory.GetFontCollectionFromFolder(criticalSxSFontsLocation);
                                } 
                                finally
                                { 
                                    CodeAccessPermission.RevertAssert(); 
                                }
                            } 
                        }
                    }
                    return _legacyArabicFontCollection;
                } 
            }
 
            ///  
            /// Checks if a given family name is one of the legacy Arabic fonts.
            ///  
            /// The family name without any face info.
            internal static bool IsLegacyArabicFont(string familyName)
            {
                for (int i = 0; i < _legacyArabicFonts.Length; ++i) 
                {
                    if (String.Compare(familyName, _legacyArabicFonts[i], StringComparison.OrdinalIgnoreCase) == 0) 
                    { 
                        return true;
                    } 
                }
                return false;
            }
 
            /// 
            /// We will use the private font collection to load some Arabic fonts 
            /// only on OSes lower than Win7, since the fonts on these OSes are legacy fonts 
            /// and the shaping engines that DWrite uses does not handle them properly.
            ///  
            internal static bool UsePrivateFontCollectionForLegacyArabicFonts
            {
                get
                { 
                    if (!_usePrivateFontCollectionIsInitialized)
                    { 
                        lock (_staticLock) 
                        {
                            if (!_usePrivateFontCollectionIsInitialized) 
                            {
                                try
                                {
                                    OperatingSystem osInfo = Environment.OSVersion; 
                                    // The version of Win7 is 6.1
                                    _usePrivateFontCollectionForLegacyArabicFonts = (osInfo.Version.Major < 6) 
                                                                                 || (osInfo.Version.Major == 6 
                                                                                     &&
                                                                                     osInfo.Version.Minor == 0); 
                                }
                                //Environment.OSVersion was unable to obtain the system version.
                                //-or-
                                //The obtained platform identifier is not a member of PlatformID. 
                                catch (InvalidOperationException)
                                { 
                                    // We do not want to bubble this exception up to the user since the user 
                                    // has nothing to do about it.
                                    // Instead we will silently fallback to using the private fonts collection 
                                    // so that we guarantee that the text shows properly.
                                    _usePrivateFontCollectionForLegacyArabicFonts = true;
                                }
 
                                _usePrivateFontCollectionIsInitialized = true;
                            } 
                        } 
                    }
                    return _usePrivateFontCollectionForLegacyArabicFonts; 
                }
            }
        }
 
        /// 
        /// This class encapsulates the 4 system composite fonts. 
        ///  
        /// 
        /// This class has direct knowledge about the 4 composite fonts that ship with WPF. 
        /// 
        private static class SystemCompositeFonts
        {
            /// The number of the system composite fonts that ship with WPF is 4. 
            internal const int NumOfSystemCompositeFonts = 4;
 
            private static object                _systemCompositeFontsLock = new object(); 
            private static readonly string[]     _systemCompositeFontsNames;
            private static readonly string[]     _systemCompositeFontsFileNames; 
            private static CompositeFontFamily[] _systemCompositeFonts;

            static SystemCompositeFonts()
            { 
                _systemCompositeFontsNames     = new string[] { "Global User Interface", "Global Monospace", "Global Sans Serif", "Global Serif" };
                _systemCompositeFontsFileNames = new string[] { "GlobalUserInterface", "GlobalMonospace", "GlobalSansSerif", "GlobalSerif" }; 
                _systemCompositeFonts = new CompositeFontFamily[NumOfSystemCompositeFonts]; 
            }
 
            /// 
            /// Returns the composite font to be used to fallback to a different font
            /// if one of the legacy Arabic fonts is specifed.
            ///  
            internal static CompositeFontFamily GetFallbackFontForArabicLegacyFonts()
            { 
                return GetCompositeFontFamilyAtIndex(1); 
            }
 
            /// 
            /// This method returns the composite font family (or null if not found) given its name
            /// 
            internal static CompositeFontFamily FindFamily(string familyName) 
            {
                int index = GetIndexOfFamily(familyName); 
                if (index >= 0) 
                {
                    return GetCompositeFontFamilyAtIndex(index); 
                }
                return null;
            }
 
            /// 
            /// This method returns the composite font with the given index after 
            /// lazily allocating it if it has not been already allocated. 
            /// 
            ///  
            ///     Critical : Creates a Security Critical FontSource object while skipping
            ///                the demand for read permission and accesses
            ///                FamilyCollection.SxSFontsLocation security critical.
            ///     TreatAsSafe : Does not expose security critical data. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            internal static CompositeFontFamily GetCompositeFontFamilyAtIndex(int index) 
            {
                if (_systemCompositeFonts[index] == null) 
                {
                    lock (_systemCompositeFontsLock)
                    {
                        if (_systemCompositeFonts[index] == null) 
                        {
                            FontSource fontSource = new FontSource(new Uri(FamilyCollection.SxSFontsLocation + _systemCompositeFontsFileNames[index] + Util.CompositeFontExtension, UriKind.Absolute), 
                                                                   true,  //skipDemand. 
                                                                   //We skip demand here since this class should cache
                                                                   //all system composite fonts for the current process 
                                                                   //Demanding read permissions should be done by FamilyCollection.cs

                                                                   true   //isComposite
                                                                   ); 

                            CompositeFontInfo fontInfo = CompositeFontParser.LoadXml(fontSource.GetStream()); 
                            _systemCompositeFonts[index] = new CompositeFontFamily(fontInfo); 
                        }
                    } 
                }
                return _systemCompositeFonts[index];
            }
 
            /// 
            /// This method returns the index of the system composite font in _systemCompositeFontsNames. 
            ///  
            private static int GetIndexOfFamily(string familyName)
            { 
                for (int i = 0; i < _systemCompositeFontsNames.Length; ++i)
                {
                    if (String.Compare(_systemCompositeFontsNames[i], familyName, StringComparison.OrdinalIgnoreCase) == 0)
                    { 
                        return i;
                    } 
                } 
                return -1;
            } 
        }

        //------------------------------------------------------
        // 
        //  Constructors
        // 
        //------------------------------------------------------ 

        #region Constructors 
        /// 
        /// Creates a font family collection cache element from a canonical font family reference.
        /// 
        /// Absolute Uri of a folder 
        /// Collection of fonts loaded from the folderUri location
        ///  
        /// Critical -  The ability to control the place fonts are loaded from is critical. 
        ///
        ///             The folderUri parameter is critical as it may contain privileged information 
        ///             (i.e., the location of Windows Fonts);
        /// 
        [SecurityCritical]
        private FamilyCollection(Uri folderUri, MS.Internal.Text.TextInterface.FontCollection fontCollection) 
        {
            _folderUri = folderUri; 
            _fontCollection = fontCollection; 
        }
 
        /// 
        /// Creates a font family collection cache element from a canonical font family reference.
        /// 
        /// Absolute Uri of a folder 
        /// 
        /// Critical    -  Calls critical constructors to initialize the returned FamilyCollection 
        ///                The folderUri parameter is critical as it may contain privileged information 
        ///                (i.e., the location of Windows Fonts); it is passed to the FontSourceCollection
        ///                constructor which is declared critical and guarantees not to disclose the URI. 
        /// TreatAsSafe -  Demands Uri Read permissions for the uri passed to constructors
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal static FamilyCollection FromUri(Uri folderUri) 
        {
            SecurityHelper.DemandUriReadPermission(folderUri); 
            return new FamilyCollection(folderUri, DWriteFactory.GetFontCollectionFromFolder(folderUri)); 
        }
 
        /// 
        /// Creates a font family collection cache element from a canonical font family reference.
        /// 
        /// Absolute Uri to the Windows Fonts folder or a file in the Windows Fonts folder. 
        /// 
        /// Critical  -  calls critical constructors to initialize the returned FamilyCollection 
        /// 
        ///             Callers should only call this method if the URI comes from internal
        ///             WPF code, NOT if it comes from the client. E.g., we want FontFamily="Arial" and 
        ///             FontFamily="arial.ttf#Arial" to work in partial trust.
        ///             But FontFamily="file:///c:/windows/fonts/#Arial" should NOT work in partial trust
        ///             (even -- or especially -- if the URI is right), as this would enable partial trust
        ///             clients to guess the location of Windows Fonts through trial and error. 
        /// 
        [SecurityCritical] 
        internal static FamilyCollection FromWindowsFonts(Uri folderUri) 
        {
            return new FamilyCollection(folderUri, DWriteFactory.SystemFontCollection); 
        }

        /// 
        /// Critical    - Initializes security critical _sxsFontsLocation. 
        /// TreatAsSafe - Always initialzes _sxsFontsLocation to String.Empty.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        static FamilyCollection()
        { 
            _sxsFontsLocation = String.Empty;
        }

        #endregion Constructors 

 
        //------------------------------------------------------ 
        //
        //  Internal Methods 
        //
        //-----------------------------------------------------

        #region Internal methods 

        ///  
        /// This method looks up a certain family in this collection given its name. 
        /// If the name was for a specific font face then this method will return its
        /// style, weight and stretch information. 
        /// 
        /// The name of the family to look for.
        /// The style if the font face in case family name contained style info.
        /// The weight if the font face in case family name contained style info. 
        /// The stretch if the font face in case family name contained style info.
        /// The font family if found. 
        ///  
        /// Critical - calls into critical GetFontFromFamily
        ///  
        [SecurityCritical]
        internal IFontFamily LookupFamily(
            string familyName,
            ref FontStyle fontStyle, 
            ref FontWeight fontWeight,
            ref FontStretch fontStretch 
            ) 
        {
            if (familyName == null || familyName.Length == 0) 
                return null;

            familyName = familyName.Trim();
 
            // If we are referencing fonts from the system fonts, then it is cheap to lookup the 4 composite fonts
            // that ship with WPF. Also, it happens often that familyName is "Global User Interface". 
            // So in this case we preceed looking into SystemComposite Fonts. 
            if (UseSystemFonts)
            { 
                CompositeFontFamily compositeFamily = SystemCompositeFonts.FindFamily(familyName);
                if (compositeFamily != null)
                {
                    return compositeFamily; 
                }
            } 
 
            Text.TextInterface.FontFamily fontFamilyDWrite = _fontCollection[familyName];
 
            // A font family was not found in DWrite's font collection.
            if (fontFamilyDWrite == null)
            {
                // Having user defined composite fonts is not very common. So we defer looking into them to looking DWrite 
                // (which is opposite to what we do for system fonts).
                if (!UseSystemFonts) 
                { 
                    // The family name was not found in DWrite's font collection. It may possibly be the name of a composite font
                    // since DWrite does not recognize composite fonts. 
                    CompositeFontFamily compositeFamily = LookUpUserCompositeFamily(familyName);
                    if (compositeFamily != null)
                    {
                        return compositeFamily; 
                    }
                } 
 
                // The family name cannot be found. This may possibly be because the family name contains styling info.
                // For example, "Arial Bold" 
                // We will strip off the styling info (one word at a time from the end) and try to find the family name.
                int indexOfSpace = -1;
                System.Text.StringBuilder potentialFaceName = new System.Text.StringBuilder();
 
                // Start removing off strings from the end hoping they are
                // style info so as to get down to the family name. 
                do 
                {
                    indexOfSpace = familyName.LastIndexOf(' '); 
                    if (indexOfSpace < 0)
                    {
                        break;
                    } 
                    else
                    { 
                        // store the stripped off style names to look for the specific face later. 
                        potentialFaceName.Insert(0, familyName.Substring(indexOfSpace));
                        familyName = familyName.Substring(0, indexOfSpace); 
                    }

                    fontFamilyDWrite = _fontCollection[familyName];
 
                } while (fontFamilyDWrite == null);
 
 
                if (fontFamilyDWrite == null)
                { 
                    return null;
                }

                // If there was styling information. 
                if (potentialFaceName.Length > 0)
                { 
                    // The first character in the potentialFaceName will be a space so we need to strip it off. 
                    Text.TextInterface.Font font = GetFontFromFamily(fontFamilyDWrite, potentialFaceName.ToString(1, potentialFaceName.Length - 1));
 
                    if (font != null)
                    {
                        fontStyle = new FontStyle((int)font.Style);
                        fontWeight = new FontWeight((int)font.Weight); 
                        fontStretch = new FontStretch((int)font.Stretch);
                    } 
                } 
            }
 
            if (UseSystemFonts
                && LegacyArabicFonts.UsePrivateFontCollectionForLegacyArabicFonts
                // familyName will hold the family name without any face info.
                && LegacyArabicFonts.IsLegacyArabicFont(familyName)) 
            {
                fontFamilyDWrite = LegacyArabicFonts.LegacyArabicFontCollection[familyName]; 
                if (fontFamilyDWrite == null) 
                {
                    return SystemCompositeFonts.GetFallbackFontForArabicLegacyFonts(); 
                }
            }

            return new PhysicalFontFamily(fontFamilyDWrite); 
        }
 
        private CompositeFontFamily LookUpUserCompositeFamily(string familyName) 
        {
            if (UserCompositeFonts != null) 
            {
                foreach (CompositeFontFamily compositeFamily in UserCompositeFonts)
                {
                    foreach (KeyValuePair localizedFamilyName in compositeFamily.FamilyNames) 
                    {
                        if (String.Compare(localizedFamilyName.Value, familyName, StringComparison.OrdinalIgnoreCase) == 0) 
                        { 
                            return compositeFamily;
                        } 
                    }
                }
            }
 
            return null;
        } 
 
        /// 
        /// Given a DWrite font family, look into it for the given face. 
        /// 
        /// The font family to look in.
        /// The face to look for.
        /// The font face if found and null if nothing was found. 
        /// 
        /// Critical - calls into critical Text.TextInterface.Font.FaceNames 
        ///  
        [SecurityCritical]
        private static Text.TextInterface.Font GetFontFromFamily(Text.TextInterface.FontFamily fontFamily, string faceName) 
        {
            faceName = faceName.ToUpper(CultureInfo.InvariantCulture);

            // The search that DWrite supports is a linear search. 
            // Look at every font face.
            foreach (Text.TextInterface.Font font in fontFamily) 
            { 
                // and at every locale name this font face has.
                foreach (KeyValuePair name in font.FaceNames) 
                {
                    string currentFontName = name.Value.ToUpper(CultureInfo.InvariantCulture);
                    if (currentFontName == faceName)
                    { 
                        return font;
                    } 
                } 
            }
 
            // This dictionary is used to store the faces (indexed by their names).
            // This dictionary will be used in case the exact string "faceName" was not found,
            // thus we will start again removing words (separated by ' ') from its end and looking
            // for the resulting faceName in that dictionary. So this dictionary is 
            // used to speed the search.
            Dictionary faces = new Dictionary(); 
 
            //We could have merged this loop with the one above. However this will degrade the performance
            //of the scenario where the user entered  a correct face name (which is the common scenario). 
            //Thus we adopt a pay for play approach, meaning that only whenever the face name does not
            //exactly correspond to an actual face name we will incure this overhead.
            foreach (Text.TextInterface.Font font in fontFamily)
            { 
                foreach (KeyValuePair name in font.FaceNames)
                { 
                    string currentFontName = name.Value.ToUpper(CultureInfo.InvariantCulture); 
                    if (!faces.ContainsKey(currentFontName))
                    { 
                        faces.Add(currentFontName, font);
                    }
                }
            } 

            // An exact match was not found and so we will start looking for the best match. 
            Text.TextInterface.Font matchingFont = null; 
            int indexOfSpace = faceName.LastIndexOf(' ');
 
            while (indexOfSpace > 0)
            {
                faceName = faceName.Substring(0, indexOfSpace);
                if (faces.TryGetValue(faceName, out matchingFont)) 
                {
                    return matchingFont; 
                } 

                indexOfSpace = faceName.LastIndexOf(' '); 
            }

            // No match was found.
            return null; 
        }
 
        private struct FamilyEnumerator : IEnumerator, IEnumerable 
        {
            private uint _familyCount; 
            private Text.TextInterface.FontCollection _fontCollection;
            private bool _firstEnumeration;
            private uint _currentFamily;
 
            internal FamilyEnumerator(Text.TextInterface.FontCollection fontCollection)
            { 
                _fontCollection = fontCollection; 
                _currentFamily = 0;
                _firstEnumeration = true; 
                _familyCount = fontCollection.FamilyCount;

            }
 
            #region IEnumerator Members
 
            public bool MoveNext() 
            {
                if (_firstEnumeration) 
                {
                    _firstEnumeration = false;
                }
                else 
                {
                    ++_currentFamily; 
                } 
                if (_currentFamily >= _familyCount)
                { 
                    // prevent cycling
                    _currentFamily = _familyCount;
                    return false;
                } 
                return true;
            } 
 
            Text.TextInterface.FontFamily IEnumerator.Current
            { 
                /// 
                /// Critical - calls into critical Text.TextInterface.FontCollection
                /// TreatAsSafe - safe to return a Text.TextInterface.FontFamily object, all access to it is critical
                ///  
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                { 

                    if (_currentFamily < 0 || _currentFamily >= _familyCount) 
                    {
                        throw new InvalidOperationException();
                    }
 
                    return _fontCollection[_currentFamily];
                } 
            } 

            #endregion 

            #region IEnumerator Members

            object IEnumerator.Current 
            {
                get 
                { 
                    return ((IEnumerator)this).Current;
                } 
            }

            public void Reset()
            { 
                _currentFamily = 0;
                _firstEnumeration = true; 
            } 

            #endregion 


            #region IDisposable Members
 
            public void Dispose() { }
 
            #endregion 

            #region IEnumerable Members 

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this as IEnumerator; 
            }
 
            #endregion 

            #region IEnumerable Members 

            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable)this).GetEnumerator(); 
            }
 
            #endregion 
        }
 
        private IEnumerable GetPhysicalFontFamilies()
        {
            return new FamilyEnumerator(this._fontCollection);
        } 

        internal FontFamily[] GetFontFamilies(Uri fontFamilyBaseUri, string fontFamilyLocationReference) 
        { 
            FontFamily[] fontFamilyList = new FontFamily[FamilyCount];
            int i = 0; 
            foreach (MS.Internal.Text.TextInterface.FontFamily family in GetPhysicalFontFamilies())
            {
                string fontFamilyReference = Util.ConvertFamilyNameAndLocationToFontFamilyReference(
                    family.OrdinalName, 
                    fontFamilyLocationReference
                    ); 
 
                string friendlyName = Util.ConvertFontFamilyReferenceToFriendlyName(fontFamilyReference);
 
                fontFamilyList[i++] = new FontFamily(fontFamilyBaseUri, friendlyName);
            }

            FontFamily fontFamily; 
            if (UseSystemFonts)
            { 
                for (int j = 0; j < SystemCompositeFonts.NumOfSystemCompositeFonts; ++j) 
                {
                    fontFamily = CreateFontFamily(SystemCompositeFonts.GetCompositeFontFamilyAtIndex(j), fontFamilyBaseUri, fontFamilyLocationReference); 
                    if (fontFamily != null)
                    {
                        fontFamilyList[i++] = fontFamily;
                    } 
                }
            } 
            else 
            {
                foreach (CompositeFontFamily compositeFontFamily in UserCompositeFonts) 
                {
                    fontFamily = CreateFontFamily(compositeFontFamily, fontFamilyBaseUri, fontFamilyLocationReference);
                    if (fontFamily != null)
                    { 
                        fontFamilyList[i++] = fontFamily;
                    } 
                } 
            }
 
            Debug.Assert(i == FamilyCount);

            return fontFamilyList;
        } 

        private FontFamily CreateFontFamily(CompositeFontFamily compositeFontFamily, Uri fontFamilyBaseUri, string fontFamilyLocationReference) 
        { 
            IFontFamily fontFamily = (IFontFamily)compositeFontFamily;
            IEnumerator familyNames = fontFamily.Names.Values.GetEnumerator(); 
            if (familyNames.MoveNext())
            {
                string ordinalName = familyNames.Current;
                string fontFamilyReference = Util.ConvertFamilyNameAndLocationToFontFamilyReference( 
                ordinalName,
                fontFamilyLocationReference 
                ); 

                string friendlyName = Util.ConvertFontFamilyReferenceToFriendlyName(fontFamilyReference); 

                return new FontFamily(fontFamilyBaseUri, friendlyName);
            }
            return null; 
        }
 
        ///  
        ///  Critical: Calls critical Text.TextInterface.FontCollection FamilyCount
        ///  SecurityTreatAsSafe: Safe to expose the number of font families in a folder. 
        /// 
        internal uint FamilyCount
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                return _fontCollection.FamilyCount + (UseSystemFonts ? SystemCompositeFonts.NumOfSystemCompositeFonts : checked((uint)UserCompositeFonts.Count)); 
            }
        } 


        #endregion Internal methods
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: FamilyCollection font cache element class is responsible for 
// storing the mapping between a folder and font families in it.
// 
// History: 
//  07/23/2003 : mleonov - Big rewrite to change cache structure.
//  03/04/2004 : mleonov - Cache layout and interface changes for font enumeration. 
//  11/04/2005 : mleonov - Refactoring to support font disambiguation.
//  08/08/2008 : [....] - Integrating with DWrite.
//
//--------------------------------------------------------------------------- 

using System; 
using System.Collections; 
using System.Collections.Generic;
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions; 
using System.Windows; 
using System.Windows.Markup;    // for XmlLanguage
using System.Windows.Media; 

using MS.Win32;
using MS.Utility;
using MS.Internal; 
using MS.Internal.FontFace;
using MS.Internal.PresentationCore; 
using MS.Internal.Shaping; 

// Since we disable PreSharp warnings in this file, we first need to disable warnings about unknown message numbers and unknown pragmas. 
#pragma warning disable 1634, 1691

namespace MS.Internal.FontCache
{ 
    /// 
    /// FamilyCollection font cache element class is responsible for 
    /// storing the mapping between a folder and font families in it 
    /// 
    [FriendAccessAllowed] 
    internal class FamilyCollection
    {
        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private Text.TextInterface.FontCollection _fontCollection;
        private Uri                               _folderUri;
        private List         _userCompositeFonts; 
        private const string                      _sxsFontsRelativeLocation = @"WPF\Fonts\";
        private static object                     _staticLock = new object(); 
 
        /// 
        ///  Critical : contains the location of the .Net framework installation. 
        /// 
        [SecurityCritical]
        private static string _sxsFontsLocation;
 
        #endregion Private Fields
 
        internal static string SxSFontsLocation 
        {
            ///  
            ///  Critical : exposes security critical _sxsFontsLocation and calls into
            ///  security critical method GetSystemSxSFontsLocation.
            /// 
            [SecurityCritical] 
            get
            { 
                if (_sxsFontsLocation == String.Empty) 
                {
                    lock (_staticLock) 
                    {
                        if (_sxsFontsLocation == String.Empty)
                        {
                            _sxsFontsLocation = GetSystemSxSFontsLocation(); 
                        }
                    } 
                } 
                return _sxsFontsLocation;
            } 
        }

        /// 
        ///  Critical : Reads the registry and asserts permissions. 
        /// 
        [SecurityCritical] 
        private static string GetSystemSxSFontsLocation() 
        {
            RegistryPermission registryPermission = new RegistryPermission( 
                                                        RegistryPermissionAccess.Read,
                                                        RegistryKeys.FRAMEWORK_RegKey_FullPath);
            registryPermission.Assert(); // BlessedAssert
 
            try
            { 
                using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(MS.Internal.RegistryKeys.FRAMEWORK_RegKey)) 
                {
                    // The registry key should be present on a valid WPF installation. 
                    Invariant.Assert(key != null);

                    string frameworkInstallPath = key.GetValue(RegistryKeys.FRAMEWORK_InstallPath_RegValue) as string;
                    CheckFrameworkInstallPath(frameworkInstallPath); 
                    return System.IO.Path.Combine(frameworkInstallPath, _sxsFontsRelativeLocation);
                } 
            } 
            finally
            { 
                CodeAccessPermission.RevertAssert();
            }
        }
 
        private static void CheckFrameworkInstallPath(string frameworkInstallPath)
        { 
            if (frameworkInstallPath == null) 
            {
                throw new ArgumentNullException("frameworkInstallPath", SR.Get(SRID.FamilyCollection_CannotFindCompositeFontsLocation)); 
            }
        }

        ///  
        ///     Critical    : Accesses the Security Critical FontSource.GetStream().
        ///     TreatAsSafe : Does not expose this stream publicly. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private static List GetCompositeFontList(FontSourceCollection fontSourceCollection) 
        {
            List compositeFonts = new List();

            foreach (FontSource fontSource in fontSourceCollection) 
            {
                if (fontSource.IsComposite) 
                { 
                    CompositeFontInfo fontInfo = CompositeFontParser.LoadXml(fontSource.GetStream());
                    CompositeFontFamily compositeFamily = new CompositeFontFamily(fontInfo); 
                    compositeFonts.Add(compositeFamily);
                }
            }
 
            return compositeFonts;
        } 
 
        private bool UseSystemFonts
        { 
            /// 
            ///     Critical    : Access the security critical DWriteFactory.SystemFontCollection.
            ///     TreatAsSafe : Does not modify it.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            get 
            { 
                return (_fontCollection == DWriteFactory.SystemFontCollection);
            } 
        }

        private IList UserCompositeFonts
        { 
            /// 
            ///     Critical    : Contructs security critical FontSourceCollection. 
            ///     TreatAsSafe : Does not expose critical info from this object publicly. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                if (_userCompositeFonts == null)
                { 
                    _userCompositeFonts = GetCompositeFontList(new FontSourceCollection(_folderUri, false, true));
                } 
                return _userCompositeFonts; 
            }
        } 

        private static class LegacyArabicFonts
        {
            private static bool              _usePrivateFontCollectionIsInitialized = false; 
            private static object            _staticLock = new object();
            private static bool              _usePrivateFontCollectionForLegacyArabicFonts; 
            private static readonly string[] _legacyArabicFonts; 
            private static Text.TextInterface.FontCollection _legacyArabicFontCollection;
 

            static LegacyArabicFonts()
            {
                _legacyArabicFonts = new string[] { "Traditional Arabic", 
                                                    "Andalus",
                                                    "Simplified Arabic", 
                                                    "Simplified Arabic Fixed" }; 
            }
 
            internal static Text.TextInterface.FontCollection LegacyArabicFontCollection
            {
                /// 
                ///     Critical    : Accesses FamilyCollection.SxSFontsLocation security critical. 
                ///                 : Asserts to get a FontCollection by full path
                ///     TreatAsSafe : Does not expose security critical data. 
                ///  
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                {
                    if (_legacyArabicFontCollection == null)
                    {
                        lock (_staticLock) 
                        {
                            if (_legacyArabicFontCollection == null) 
                            { 
                                Uri criticalSxSFontsLocation = new Uri(FamilyCollection.SxSFontsLocation);
                                SecurityHelper.CreateUriDiscoveryPermission(criticalSxSFontsLocation).Assert(); 
                                try
                                {
                                    _legacyArabicFontCollection = DWriteFactory.GetFontCollectionFromFolder(criticalSxSFontsLocation);
                                } 
                                finally
                                { 
                                    CodeAccessPermission.RevertAssert(); 
                                }
                            } 
                        }
                    }
                    return _legacyArabicFontCollection;
                } 
            }
 
            ///  
            /// Checks if a given family name is one of the legacy Arabic fonts.
            ///  
            /// The family name without any face info.
            internal static bool IsLegacyArabicFont(string familyName)
            {
                for (int i = 0; i < _legacyArabicFonts.Length; ++i) 
                {
                    if (String.Compare(familyName, _legacyArabicFonts[i], StringComparison.OrdinalIgnoreCase) == 0) 
                    { 
                        return true;
                    } 
                }
                return false;
            }
 
            /// 
            /// We will use the private font collection to load some Arabic fonts 
            /// only on OSes lower than Win7, since the fonts on these OSes are legacy fonts 
            /// and the shaping engines that DWrite uses does not handle them properly.
            ///  
            internal static bool UsePrivateFontCollectionForLegacyArabicFonts
            {
                get
                { 
                    if (!_usePrivateFontCollectionIsInitialized)
                    { 
                        lock (_staticLock) 
                        {
                            if (!_usePrivateFontCollectionIsInitialized) 
                            {
                                try
                                {
                                    OperatingSystem osInfo = Environment.OSVersion; 
                                    // The version of Win7 is 6.1
                                    _usePrivateFontCollectionForLegacyArabicFonts = (osInfo.Version.Major < 6) 
                                                                                 || (osInfo.Version.Major == 6 
                                                                                     &&
                                                                                     osInfo.Version.Minor == 0); 
                                }
                                //Environment.OSVersion was unable to obtain the system version.
                                //-or-
                                //The obtained platform identifier is not a member of PlatformID. 
                                catch (InvalidOperationException)
                                { 
                                    // We do not want to bubble this exception up to the user since the user 
                                    // has nothing to do about it.
                                    // Instead we will silently fallback to using the private fonts collection 
                                    // so that we guarantee that the text shows properly.
                                    _usePrivateFontCollectionForLegacyArabicFonts = true;
                                }
 
                                _usePrivateFontCollectionIsInitialized = true;
                            } 
                        } 
                    }
                    return _usePrivateFontCollectionForLegacyArabicFonts; 
                }
            }
        }
 
        /// 
        /// This class encapsulates the 4 system composite fonts. 
        ///  
        /// 
        /// This class has direct knowledge about the 4 composite fonts that ship with WPF. 
        /// 
        private static class SystemCompositeFonts
        {
            /// The number of the system composite fonts that ship with WPF is 4. 
            internal const int NumOfSystemCompositeFonts = 4;
 
            private static object                _systemCompositeFontsLock = new object(); 
            private static readonly string[]     _systemCompositeFontsNames;
            private static readonly string[]     _systemCompositeFontsFileNames; 
            private static CompositeFontFamily[] _systemCompositeFonts;

            static SystemCompositeFonts()
            { 
                _systemCompositeFontsNames     = new string[] { "Global User Interface", "Global Monospace", "Global Sans Serif", "Global Serif" };
                _systemCompositeFontsFileNames = new string[] { "GlobalUserInterface", "GlobalMonospace", "GlobalSansSerif", "GlobalSerif" }; 
                _systemCompositeFonts = new CompositeFontFamily[NumOfSystemCompositeFonts]; 
            }
 
            /// 
            /// Returns the composite font to be used to fallback to a different font
            /// if one of the legacy Arabic fonts is specifed.
            ///  
            internal static CompositeFontFamily GetFallbackFontForArabicLegacyFonts()
            { 
                return GetCompositeFontFamilyAtIndex(1); 
            }
 
            /// 
            /// This method returns the composite font family (or null if not found) given its name
            /// 
            internal static CompositeFontFamily FindFamily(string familyName) 
            {
                int index = GetIndexOfFamily(familyName); 
                if (index >= 0) 
                {
                    return GetCompositeFontFamilyAtIndex(index); 
                }
                return null;
            }
 
            /// 
            /// This method returns the composite font with the given index after 
            /// lazily allocating it if it has not been already allocated. 
            /// 
            ///  
            ///     Critical : Creates a Security Critical FontSource object while skipping
            ///                the demand for read permission and accesses
            ///                FamilyCollection.SxSFontsLocation security critical.
            ///     TreatAsSafe : Does not expose security critical data. 
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            internal static CompositeFontFamily GetCompositeFontFamilyAtIndex(int index) 
            {
                if (_systemCompositeFonts[index] == null) 
                {
                    lock (_systemCompositeFontsLock)
                    {
                        if (_systemCompositeFonts[index] == null) 
                        {
                            FontSource fontSource = new FontSource(new Uri(FamilyCollection.SxSFontsLocation + _systemCompositeFontsFileNames[index] + Util.CompositeFontExtension, UriKind.Absolute), 
                                                                   true,  //skipDemand. 
                                                                   //We skip demand here since this class should cache
                                                                   //all system composite fonts for the current process 
                                                                   //Demanding read permissions should be done by FamilyCollection.cs

                                                                   true   //isComposite
                                                                   ); 

                            CompositeFontInfo fontInfo = CompositeFontParser.LoadXml(fontSource.GetStream()); 
                            _systemCompositeFonts[index] = new CompositeFontFamily(fontInfo); 
                        }
                    } 
                }
                return _systemCompositeFonts[index];
            }
 
            /// 
            /// This method returns the index of the system composite font in _systemCompositeFontsNames. 
            ///  
            private static int GetIndexOfFamily(string familyName)
            { 
                for (int i = 0; i < _systemCompositeFontsNames.Length; ++i)
                {
                    if (String.Compare(_systemCompositeFontsNames[i], familyName, StringComparison.OrdinalIgnoreCase) == 0)
                    { 
                        return i;
                    } 
                } 
                return -1;
            } 
        }

        //------------------------------------------------------
        // 
        //  Constructors
        // 
        //------------------------------------------------------ 

        #region Constructors 
        /// 
        /// Creates a font family collection cache element from a canonical font family reference.
        /// 
        /// Absolute Uri of a folder 
        /// Collection of fonts loaded from the folderUri location
        ///  
        /// Critical -  The ability to control the place fonts are loaded from is critical. 
        ///
        ///             The folderUri parameter is critical as it may contain privileged information 
        ///             (i.e., the location of Windows Fonts);
        /// 
        [SecurityCritical]
        private FamilyCollection(Uri folderUri, MS.Internal.Text.TextInterface.FontCollection fontCollection) 
        {
            _folderUri = folderUri; 
            _fontCollection = fontCollection; 
        }
 
        /// 
        /// Creates a font family collection cache element from a canonical font family reference.
        /// 
        /// Absolute Uri of a folder 
        /// 
        /// Critical    -  Calls critical constructors to initialize the returned FamilyCollection 
        ///                The folderUri parameter is critical as it may contain privileged information 
        ///                (i.e., the location of Windows Fonts); it is passed to the FontSourceCollection
        ///                constructor which is declared critical and guarantees not to disclose the URI. 
        /// TreatAsSafe -  Demands Uri Read permissions for the uri passed to constructors
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal static FamilyCollection FromUri(Uri folderUri) 
        {
            SecurityHelper.DemandUriReadPermission(folderUri); 
            return new FamilyCollection(folderUri, DWriteFactory.GetFontCollectionFromFolder(folderUri)); 
        }
 
        /// 
        /// Creates a font family collection cache element from a canonical font family reference.
        /// 
        /// Absolute Uri to the Windows Fonts folder or a file in the Windows Fonts folder. 
        /// 
        /// Critical  -  calls critical constructors to initialize the returned FamilyCollection 
        /// 
        ///             Callers should only call this method if the URI comes from internal
        ///             WPF code, NOT if it comes from the client. E.g., we want FontFamily="Arial" and 
        ///             FontFamily="arial.ttf#Arial" to work in partial trust.
        ///             But FontFamily="file:///c:/windows/fonts/#Arial" should NOT work in partial trust
        ///             (even -- or especially -- if the URI is right), as this would enable partial trust
        ///             clients to guess the location of Windows Fonts through trial and error. 
        /// 
        [SecurityCritical] 
        internal static FamilyCollection FromWindowsFonts(Uri folderUri) 
        {
            return new FamilyCollection(folderUri, DWriteFactory.SystemFontCollection); 
        }

        /// 
        /// Critical    - Initializes security critical _sxsFontsLocation. 
        /// TreatAsSafe - Always initialzes _sxsFontsLocation to String.Empty.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        static FamilyCollection()
        { 
            _sxsFontsLocation = String.Empty;
        }

        #endregion Constructors 

 
        //------------------------------------------------------ 
        //
        //  Internal Methods 
        //
        //-----------------------------------------------------

        #region Internal methods 

        ///  
        /// This method looks up a certain family in this collection given its name. 
        /// If the name was for a specific font face then this method will return its
        /// style, weight and stretch information. 
        /// 
        /// The name of the family to look for.
        /// The style if the font face in case family name contained style info.
        /// The weight if the font face in case family name contained style info. 
        /// The stretch if the font face in case family name contained style info.
        /// The font family if found. 
        ///  
        /// Critical - calls into critical GetFontFromFamily
        ///  
        [SecurityCritical]
        internal IFontFamily LookupFamily(
            string familyName,
            ref FontStyle fontStyle, 
            ref FontWeight fontWeight,
            ref FontStretch fontStretch 
            ) 
        {
            if (familyName == null || familyName.Length == 0) 
                return null;

            familyName = familyName.Trim();
 
            // If we are referencing fonts from the system fonts, then it is cheap to lookup the 4 composite fonts
            // that ship with WPF. Also, it happens often that familyName is "Global User Interface". 
            // So in this case we preceed looking into SystemComposite Fonts. 
            if (UseSystemFonts)
            { 
                CompositeFontFamily compositeFamily = SystemCompositeFonts.FindFamily(familyName);
                if (compositeFamily != null)
                {
                    return compositeFamily; 
                }
            } 
 
            Text.TextInterface.FontFamily fontFamilyDWrite = _fontCollection[familyName];
 
            // A font family was not found in DWrite's font collection.
            if (fontFamilyDWrite == null)
            {
                // Having user defined composite fonts is not very common. So we defer looking into them to looking DWrite 
                // (which is opposite to what we do for system fonts).
                if (!UseSystemFonts) 
                { 
                    // The family name was not found in DWrite's font collection. It may possibly be the name of a composite font
                    // since DWrite does not recognize composite fonts. 
                    CompositeFontFamily compositeFamily = LookUpUserCompositeFamily(familyName);
                    if (compositeFamily != null)
                    {
                        return compositeFamily; 
                    }
                } 
 
                // The family name cannot be found. This may possibly be because the family name contains styling info.
                // For example, "Arial Bold" 
                // We will strip off the styling info (one word at a time from the end) and try to find the family name.
                int indexOfSpace = -1;
                System.Text.StringBuilder potentialFaceName = new System.Text.StringBuilder();
 
                // Start removing off strings from the end hoping they are
                // style info so as to get down to the family name. 
                do 
                {
                    indexOfSpace = familyName.LastIndexOf(' '); 
                    if (indexOfSpace < 0)
                    {
                        break;
                    } 
                    else
                    { 
                        // store the stripped off style names to look for the specific face later. 
                        potentialFaceName.Insert(0, familyName.Substring(indexOfSpace));
                        familyName = familyName.Substring(0, indexOfSpace); 
                    }

                    fontFamilyDWrite = _fontCollection[familyName];
 
                } while (fontFamilyDWrite == null);
 
 
                if (fontFamilyDWrite == null)
                { 
                    return null;
                }

                // If there was styling information. 
                if (potentialFaceName.Length > 0)
                { 
                    // The first character in the potentialFaceName will be a space so we need to strip it off. 
                    Text.TextInterface.Font font = GetFontFromFamily(fontFamilyDWrite, potentialFaceName.ToString(1, potentialFaceName.Length - 1));
 
                    if (font != null)
                    {
                        fontStyle = new FontStyle((int)font.Style);
                        fontWeight = new FontWeight((int)font.Weight); 
                        fontStretch = new FontStretch((int)font.Stretch);
                    } 
                } 
            }
 
            if (UseSystemFonts
                && LegacyArabicFonts.UsePrivateFontCollectionForLegacyArabicFonts
                // familyName will hold the family name without any face info.
                && LegacyArabicFonts.IsLegacyArabicFont(familyName)) 
            {
                fontFamilyDWrite = LegacyArabicFonts.LegacyArabicFontCollection[familyName]; 
                if (fontFamilyDWrite == null) 
                {
                    return SystemCompositeFonts.GetFallbackFontForArabicLegacyFonts(); 
                }
            }

            return new PhysicalFontFamily(fontFamilyDWrite); 
        }
 
        private CompositeFontFamily LookUpUserCompositeFamily(string familyName) 
        {
            if (UserCompositeFonts != null) 
            {
                foreach (CompositeFontFamily compositeFamily in UserCompositeFonts)
                {
                    foreach (KeyValuePair localizedFamilyName in compositeFamily.FamilyNames) 
                    {
                        if (String.Compare(localizedFamilyName.Value, familyName, StringComparison.OrdinalIgnoreCase) == 0) 
                        { 
                            return compositeFamily;
                        } 
                    }
                }
            }
 
            return null;
        } 
 
        /// 
        /// Given a DWrite font family, look into it for the given face. 
        /// 
        /// The font family to look in.
        /// The face to look for.
        /// The font face if found and null if nothing was found. 
        /// 
        /// Critical - calls into critical Text.TextInterface.Font.FaceNames 
        ///  
        [SecurityCritical]
        private static Text.TextInterface.Font GetFontFromFamily(Text.TextInterface.FontFamily fontFamily, string faceName) 
        {
            faceName = faceName.ToUpper(CultureInfo.InvariantCulture);

            // The search that DWrite supports is a linear search. 
            // Look at every font face.
            foreach (Text.TextInterface.Font font in fontFamily) 
            { 
                // and at every locale name this font face has.
                foreach (KeyValuePair name in font.FaceNames) 
                {
                    string currentFontName = name.Value.ToUpper(CultureInfo.InvariantCulture);
                    if (currentFontName == faceName)
                    { 
                        return font;
                    } 
                } 
            }
 
            // This dictionary is used to store the faces (indexed by their names).
            // This dictionary will be used in case the exact string "faceName" was not found,
            // thus we will start again removing words (separated by ' ') from its end and looking
            // for the resulting faceName in that dictionary. So this dictionary is 
            // used to speed the search.
            Dictionary faces = new Dictionary(); 
 
            //We could have merged this loop with the one above. However this will degrade the performance
            //of the scenario where the user entered  a correct face name (which is the common scenario). 
            //Thus we adopt a pay for play approach, meaning that only whenever the face name does not
            //exactly correspond to an actual face name we will incure this overhead.
            foreach (Text.TextInterface.Font font in fontFamily)
            { 
                foreach (KeyValuePair name in font.FaceNames)
                { 
                    string currentFontName = name.Value.ToUpper(CultureInfo.InvariantCulture); 
                    if (!faces.ContainsKey(currentFontName))
                    { 
                        faces.Add(currentFontName, font);
                    }
                }
            } 

            // An exact match was not found and so we will start looking for the best match. 
            Text.TextInterface.Font matchingFont = null; 
            int indexOfSpace = faceName.LastIndexOf(' ');
 
            while (indexOfSpace > 0)
            {
                faceName = faceName.Substring(0, indexOfSpace);
                if (faces.TryGetValue(faceName, out matchingFont)) 
                {
                    return matchingFont; 
                } 

                indexOfSpace = faceName.LastIndexOf(' '); 
            }

            // No match was found.
            return null; 
        }
 
        private struct FamilyEnumerator : IEnumerator, IEnumerable 
        {
            private uint _familyCount; 
            private Text.TextInterface.FontCollection _fontCollection;
            private bool _firstEnumeration;
            private uint _currentFamily;
 
            internal FamilyEnumerator(Text.TextInterface.FontCollection fontCollection)
            { 
                _fontCollection = fontCollection; 
                _currentFamily = 0;
                _firstEnumeration = true; 
                _familyCount = fontCollection.FamilyCount;

            }
 
            #region IEnumerator Members
 
            public bool MoveNext() 
            {
                if (_firstEnumeration) 
                {
                    _firstEnumeration = false;
                }
                else 
                {
                    ++_currentFamily; 
                } 
                if (_currentFamily >= _familyCount)
                { 
                    // prevent cycling
                    _currentFamily = _familyCount;
                    return false;
                } 
                return true;
            } 
 
            Text.TextInterface.FontFamily IEnumerator.Current
            { 
                /// 
                /// Critical - calls into critical Text.TextInterface.FontCollection
                /// TreatAsSafe - safe to return a Text.TextInterface.FontFamily object, all access to it is critical
                ///  
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                { 

                    if (_currentFamily < 0 || _currentFamily >= _familyCount) 
                    {
                        throw new InvalidOperationException();
                    }
 
                    return _fontCollection[_currentFamily];
                } 
            } 

            #endregion 

            #region IEnumerator Members

            object IEnumerator.Current 
            {
                get 
                { 
                    return ((IEnumerator)this).Current;
                } 
            }

            public void Reset()
            { 
                _currentFamily = 0;
                _firstEnumeration = true; 
            } 

            #endregion 


            #region IDisposable Members
 
            public void Dispose() { }
 
            #endregion 

            #region IEnumerable Members 

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this as IEnumerator; 
            }
 
            #endregion 

            #region IEnumerable Members 

            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IEnumerable)this).GetEnumerator(); 
            }
 
            #endregion 
        }
 
        private IEnumerable GetPhysicalFontFamilies()
        {
            return new FamilyEnumerator(this._fontCollection);
        } 

        internal FontFamily[] GetFontFamilies(Uri fontFamilyBaseUri, string fontFamilyLocationReference) 
        { 
            FontFamily[] fontFamilyList = new FontFamily[FamilyCount];
            int i = 0; 
            foreach (MS.Internal.Text.TextInterface.FontFamily family in GetPhysicalFontFamilies())
            {
                string fontFamilyReference = Util.ConvertFamilyNameAndLocationToFontFamilyReference(
                    family.OrdinalName, 
                    fontFamilyLocationReference
                    ); 
 
                string friendlyName = Util.ConvertFontFamilyReferenceToFriendlyName(fontFamilyReference);
 
                fontFamilyList[i++] = new FontFamily(fontFamilyBaseUri, friendlyName);
            }

            FontFamily fontFamily; 
            if (UseSystemFonts)
            { 
                for (int j = 0; j < SystemCompositeFonts.NumOfSystemCompositeFonts; ++j) 
                {
                    fontFamily = CreateFontFamily(SystemCompositeFonts.GetCompositeFontFamilyAtIndex(j), fontFamilyBaseUri, fontFamilyLocationReference); 
                    if (fontFamily != null)
                    {
                        fontFamilyList[i++] = fontFamily;
                    } 
                }
            } 
            else 
            {
                foreach (CompositeFontFamily compositeFontFamily in UserCompositeFonts) 
                {
                    fontFamily = CreateFontFamily(compositeFontFamily, fontFamilyBaseUri, fontFamilyLocationReference);
                    if (fontFamily != null)
                    { 
                        fontFamilyList[i++] = fontFamily;
                    } 
                } 
            }
 
            Debug.Assert(i == FamilyCount);

            return fontFamilyList;
        } 

        private FontFamily CreateFontFamily(CompositeFontFamily compositeFontFamily, Uri fontFamilyBaseUri, string fontFamilyLocationReference) 
        { 
            IFontFamily fontFamily = (IFontFamily)compositeFontFamily;
            IEnumerator familyNames = fontFamily.Names.Values.GetEnumerator(); 
            if (familyNames.MoveNext())
            {
                string ordinalName = familyNames.Current;
                string fontFamilyReference = Util.ConvertFamilyNameAndLocationToFontFamilyReference( 
                ordinalName,
                fontFamilyLocationReference 
                ); 

                string friendlyName = Util.ConvertFontFamilyReferenceToFriendlyName(fontFamilyReference); 

                return new FontFamily(fontFamilyBaseUri, friendlyName);
            }
            return null; 
        }
 
        ///  
        ///  Critical: Calls critical Text.TextInterface.FontCollection FamilyCount
        ///  SecurityTreatAsSafe: Safe to expose the number of font families in a folder. 
        /// 
        internal uint FamilyCount
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                return _fontCollection.FamilyCount + (UseSystemFonts ? SystemCompositeFonts.NumOfSystemCompositeFonts : checked((uint)UserCompositeFonts.Count)); 
            }
        } 


        #endregion Internal methods
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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