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 ListGetCompositeFontList(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 IListUserCompositeFonts { /// /// 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 (KeyValuePairlocalizedFamilyName 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 (KeyValuePairname 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 ListGetCompositeFontList(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 IListUserCompositeFonts { /// /// 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 (KeyValuePairlocalizedFamilyName 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 (KeyValuePairname 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DocumentPageViewAutomationPeer.cs
- WindowsFormsHost.cs
- MinimizableAttributeTypeConverter.cs
- WindowsAuthenticationModule.cs
- SvcMapFileLoader.cs
- XmlIncludeAttribute.cs
- ApplicationProxyInternal.cs
- DigitalSignature.cs
- ToolBarTray.cs
- SettingsPropertyValue.cs
- _NativeSSPI.cs
- XmlCountingReader.cs
- EncodingInfo.cs
- PartitionedStreamMerger.cs
- ContentPropertyAttribute.cs
- DataControlCommands.cs
- DynamicPropertyReader.cs
- SafeRegistryHandle.cs
- SqlServices.cs
- SQLInt32.cs
- ObjectViewQueryResultData.cs
- SchemaDeclBase.cs
- UnauthorizedWebPart.cs
- XmlnsDictionary.cs
- DataGridViewCellConverter.cs
- DescendantBaseQuery.cs
- Pair.cs
- XmlBinaryReaderSession.cs
- StrokeNodeData.cs
- MethodInfo.cs
- DataRowComparer.cs
- TextContainerHelper.cs
- KnownBoxes.cs
- WebPartManager.cs
- Vector3DAnimationUsingKeyFrames.cs
- ThicknessAnimation.cs
- SystemResourceHost.cs
- HtmlInputPassword.cs
- BindingsCollection.cs
- MaskedTextBox.cs
- OdbcConnectionPoolProviderInfo.cs
- IntellisenseTextBox.designer.cs
- DesignerObjectListAdapter.cs
- SchemaExporter.cs
- TableSectionStyle.cs
- WebPartAuthorizationEventArgs.cs
- Rect3D.cs
- NamespaceList.cs
- XmlUnspecifiedAttribute.cs
- Descriptor.cs
- JournalEntryStack.cs
- transactioncontext.cs
- ValuePattern.cs
- StrongNameUtility.cs
- NonVisualControlAttribute.cs
- DESCryptoServiceProvider.cs
- LogSwitch.cs
- SqlXmlStorage.cs
- TraceHandler.cs
- GenericEnumConverter.cs
- Brush.cs
- FormViewUpdatedEventArgs.cs
- FormViewInsertedEventArgs.cs
- SoapAttributeOverrides.cs
- SqlDataSourceCustomCommandPanel.cs
- SharedStatics.cs
- DetailsViewCommandEventArgs.cs
- ColumnResizeAdorner.cs
- JpegBitmapEncoder.cs
- HiddenFieldDesigner.cs
- BrushMappingModeValidation.cs
- HtmlSelect.cs
- XPathAncestorIterator.cs
- NamedPipeChannelListener.cs
- DataGridViewCellErrorTextNeededEventArgs.cs
- EventManager.cs
- ReadOnlyDataSourceView.cs
- CryptoProvider.cs
- DataBoundControlAdapter.cs
- EntityClientCacheKey.cs
- AsynchronousChannel.cs
- CreateParams.cs
- XmlSchemaSimpleTypeUnion.cs
- UInt64.cs
- OutOfProcStateClientManager.cs
- Label.cs
- DataGridViewSortCompareEventArgs.cs
- GeometryHitTestResult.cs
- DeclarativeCatalogPartDesigner.cs
- MenuItemStyle.cs
- TagNameToTypeMapper.cs
- DataIdProcessor.cs
- ListGeneralPage.cs
- RadioButtonPopupAdapter.cs
- DataTableTypeConverter.cs
- MatrixTransform3D.cs
- CompressionTransform.cs
- ValueTable.cs
- xsdvalidator.cs
- infer.cs