Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / FontFace / CompositeFontParser.cs / 1 / CompositeFontParser.cs
//---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // Contents: The XML Composite font parsing // // Created: 6-11-2003 Tarek Mahmoud Sayed ([....]) // //--------------------------------------------------------------------------- using System; using System.IO; using System.Security; using System.Security.Permissions; using System.Text; using System.Windows; using System.Windows.Media; using System.Windows.Markup; using System.Xml; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using MS.Internal.TextFormatting; using System.Reflection; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace MS.Internal.FontFace { internal class CompositeFontParser { internal static void VerifyMultiplierOfEm(string propertyName, ref double value) { if (DoubleUtil.IsNaN(value)) { throw new ArgumentException(SR.Get(SRID.PropertyValueCannotBeNaN, propertyName)); } else if (value > Constants.GreatestMutiplierOfEm) { value = Constants.GreatestMutiplierOfEm; } else if (value < -Constants.GreatestMutiplierOfEm) { value = -Constants.GreatestMutiplierOfEm; } } internal static void VerifyPositiveMultiplierOfEm(string propertyName, ref double value) { if (DoubleUtil.IsNaN(value)) { throw new ArgumentException(SR.Get(SRID.PropertyValueCannotBeNaN, propertyName)); } else if (value > Constants.GreatestMutiplierOfEm) { value = Constants.GreatestMutiplierOfEm; } else if (value <= 0) { throw new ArgumentException(SR.Get(SRID.PropertyMustBeGreaterThanZero, propertyName)); } } internal static void VerifyNonNegativeMultiplierOfEm(string propertyName, ref double value) { if (DoubleUtil.IsNaN(value)) { throw new ArgumentException(SR.Get(SRID.PropertyValueCannotBeNaN, propertyName)); } else if (value > Constants.GreatestMutiplierOfEm) { value = Constants.GreatestMutiplierOfEm; } else if (value < 0) { throw new ArgumentException(SR.Get(SRID.PropertyCannotBeNegative, propertyName)); } } private double GetAttributeAsDouble() { object value = null; try { value = _doubleTypeConverter.ConvertFromString( null, // type converter context _englishUSCulture, GetAttributeValue() ); } catch (NotSupportedException) { FailAttributeValue(); } if (value == null) FailAttributeValue(); return (double)value; } private XmlLanguage GetAttributeAsXmlLanguage() { object value = null; try { value = _xmlLanguageTypeConverter.ConvertFromString( null, // type converter context _englishUSCulture, GetAttributeValue() ); } catch (NotSupportedException) { FailAttributeValue(); } if (value == null) FailAttributeValue(); return (XmlLanguage)value; } ////// Gets the value of the value of the current node which is assumed to be an /// attribute. Checks for markup expressions or escaped braces. /// private string GetAttributeValue() { string s = _reader.Value; if (string.IsNullOrEmpty(s)) return string.Empty; if (s[0] == '{') { if (s.Length > 1 && s[1] == '}') { s = s.Substring(2); } else { FailAttributeValue(); } } return s; } private const NumberStyles UnsignedDecimalPointStyle = NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingWhite | NumberStyles.AllowDecimalPoint; private const NumberStyles SignedDecimalPointStyle = UnsignedDecimalPointStyle | NumberStyles.AllowLeadingSign; ////// Reads the specified composite font file. /// internal static CompositeFontInfo LoadXml(Stream fileStream) { CompositeFontParser parser = new CompositeFontParser(fileStream); return parser._compositeFontInfo; } ////// Constructs the composite font parser and parses the file. /// /// File stream to parse. private CompositeFontParser(Stream fileStream) { _compositeFontInfo = new CompositeFontInfo(); _namespaceMap = new Hashtable(); _englishUSCulture = CultureInfo.GetCultureInfoByIetfLanguageTag("en-US"); _doubleTypeConverter = TypeDescriptor.GetConverter(typeof(double)); _xmlLanguageTypeConverter = new System.Windows.Markup.XmlLanguageConverter(); _reader = CreateXmlReader(fileStream); try { if (IsStartElement(FontFamilyElement, CompositeFontNamespace)) { ParseFontFamilyElement(); } else { FailUnknownElement(); } } catch (XmlException x) { FailNotWellFormed(x); } catch (XmlSyntaxException x) { FailNotWellFormed(x); } catch (FormatException x) { if (_reader.NodeType == XmlNodeType.Attribute) FailAttributeValue(x); else Fail(x.Message, x); } catch (ArgumentException x) { if (_reader.NodeType == XmlNodeType.Attribute) FailAttributeValue(x); else Fail(x.Message, x); } finally { _reader.Close(); _reader = null; } } ////// Creates the XML reader for the specified file. /// private XmlReader CreateXmlReader(Stream fileStream) { XmlReaderSettings settings = new XmlReaderSettings(); settings.CloseInput = true; settings.IgnoreComments = true; settings.IgnoreWhitespace = false; settings.ProhibitDtd = true; XmlReader baseReader = XmlReader.Create(fileStream, settings); return new XmlCompatibilityReader(baseReader, new IsXmlNamespaceSupportedCallback(IsXmlNamespaceSupported)); } ////// Determines whether a given XML namespace is "known" (i.e., should always be processed) /// or "unknown" (i.e., should be skipped if declared ignorable). /// /// XML namespace to look up. /// Other namespace to map to, if any. Used for versioning. /// This implementation always returns null in this parameter. ////// Returns true ("known") for the XAML namespace or the composite font namespace. /// for which a Mapping PI exists. /// ////// System.String is the only object in a mapped namespace that we can instantiate. However, /// we don't want to ignore any mapped namespaces for compatibility reasons. In general, it's /// better for us to reject valid XAML than to accept invalid XAML. We therefore don't want /// to ignore an element which the XAML parser would not ignore -- the ignored element might /// be invalid. If mapped elements other than System.String are needed in future versions, a /// composite font author can achieve backwards compatibility by conditionalizing mapped /// elements using c:AlternateContent markup. /// private bool IsXmlNamespaceSupported(string xmlNamespace, out string newXmlNamespace) { newXmlNamespace = null; return xmlNamespace == CompositeFontNamespace || xmlNamespace == XamlNamespace || IsMappedNamespace(xmlNamespace); } ////// Calls MoveToContent and checks whether the reader is positioned on the specified element. /// ////// We should always call this method instead of calling _reader.IsStartElement directly because /// the latter calls MoveToContent on the underlying reader which means we could fail to parse /// Mapping processing instructions. /// private bool IsStartElement(string localName, string namespaceURI) { MoveToContent(); return _reader.IsStartElement(localName, namespaceURI); } ////// Same semantics as XmlReader.MoveToContent, but this method processes Mapping processing /// instructions as it advances past them. /// private XmlNodeType MoveToContent() { bool contentNode = false; do { switch (_reader.NodeType) { case XmlNodeType.CDATA: case XmlNodeType.Element: case XmlNodeType.EndElement: case XmlNodeType.EntityReference: case XmlNodeType.EndEntity: contentNode = true; break; } } while (!contentNode && _reader.Read()); return _reader.NodeType; } #region ProcessingInstructions private bool IsMappedNamespace(string xmlNamespace) { return _namespaceMap.ContainsKey(xmlNamespace); } private bool IsSystemNamespace(string xmlNamespace) { return (xmlNamespace == "clr-namespace:System;assembly=mscorlib"); } #endregion ProcessingInstructions ////// Parses the FontFamily element, including its attributes and children, /// and advances to the next sibling element. /// private void ParseFontFamilyElement() { // Iterate over the attributes. if (_reader.MoveToFirstAttribute()) { do { // Process attributes in the composite font namespace if (IsCompositeFontAttribute()) { string name = _reader.LocalName; if (name == BaselineAttribute) { _compositeFontInfo.Baseline = GetAttributeAsDouble(); } else if (name == LineSpacingAttribute) { _compositeFontInfo.LineSpacing = GetAttributeAsDouble(); } else { FailUnknownAttribute(); } } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } // Empty element? if (_reader.IsEmptyElement) { VerifyCompositeFontInfo(); _reader.Read(); return; } // Advance past the start tag. _reader.Read(); // Iterate over children. while (MoveToContent() != XmlNodeType.EndElement) { if (_reader.NodeType == XmlNodeType.Element && _reader.NamespaceURI == CompositeFontNamespace) { bool isEmpty = _reader.IsEmptyElement; // It's an element in the composite font namespace; branch depending on the name. switch (_reader.LocalName) { case FamilyNamesPropertyElement: VerifyNoAttributes(); _reader.Read(); if (!isEmpty) { // Process all child elements. while (MoveToContent() == XmlNodeType.Element) { if (_reader.LocalName == StringElement && IsSystemNamespace(_reader.NamespaceURI)) { // It's a System.String. ParseFamilyNameElement(); } else { // Only System.String is valid in this context. FailUnknownElement(); } } // Advance past the end element, or throw // an exception if we're not at an end element. _reader.ReadEndElement(); } break; case FamilyTypefacesPropertyElement: VerifyNoAttributes(); _reader.Read(); if (!isEmpty) { // Process child elements, of which the only one we recognize in this // context is FamilyTypeface. while (IsStartElement(FamilyTypefaceElement, CompositeFontNamespace)) { ParseFamilyTypefaceElement(); } // Advance past the end element, or throw // an exception if we're not at an end element. _reader.ReadEndElement(); } break; case FamilyMapsPropertyElement: VerifyNoAttributes(); _reader.Read(); if (!isEmpty) { // Process child elements, of which the only one we recognize in this // context is FontFamilyMap. while (IsStartElement(FamilyMapElement, CompositeFontNamespace)) { ParseFamilyMapElement(); } // Advance past the end element, or throw // an exception if we're not at an end element. _reader.ReadEndElement(); } break; default: // It's some other element. FailUnknownElement(); break; } } else { // It's some other content besides an element in the composite font namespace; skip it. _reader.Skip(); } } // We should now have read right up to the end tag. VerifyCompositeFontInfo(); _reader.ReadEndElement(); } ////// Makes sure the current element has no attributes (except ignorable ones). /// private void VerifyNoAttributes() { if (_reader.MoveToFirstAttribute()) { do { if (!IsIgnorableAttribute()) FailUnknownAttribute(); } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } } ////// Parses the FamilyName element (actually String), including its attributes /// and children, and advances to the next sibling element. /// private void ParseFamilyNameElement() { XmlLanguage language = null; // Iterate over the attributes. if (_reader.MoveToFirstAttribute()) { do { if (_reader.NamespaceURI == XamlNamespace && _reader.LocalName == KeyAttribute) { language = GetAttributeAsXmlLanguage(); } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } // XAML requires x:Key so we should, too. if (language == null) { FailMissingAttribute(LanguageAttribute); } // The family name is the element content. string familyName = _reader.ReadElementString(); if (string.IsNullOrEmpty(familyName)) { FailMissingAttribute(NameAttribute); } _compositeFontInfo.FamilyNames.Add(language, familyName); } ////// Parses the FamilyTypeface element, including its attributes and children, /// and advances to the next sibling element. /// private void ParseFamilyTypefaceElement() { FamilyTypeface face = new FamilyTypeface(); ParseFamilyTypefaceAttributes(face); if (_reader.IsEmptyElement) { _reader.Read(); } else { _reader.Read(); while (MoveToContent() != XmlNodeType.EndElement) { if (_reader.NodeType == XmlNodeType.Element && _reader.NamespaceURI == CompositeFontNamespace) { if (_reader.LocalName == DeviceFontCharacterMetricsPropertyElement) { VerifyNoAttributes(); if (_reader.IsEmptyElement) { _reader.Read(); } else { _reader.Read(); // Process all child elements. while (MoveToContent() == XmlNodeType.Element) { if (_reader.LocalName == CharacterMetricsElement) { ParseCharacterMetricsElement(face); } else { // Only CharacterMetricsElement is valid in this context. FailUnknownElement(); } } // Process the end element for the collection. _reader.ReadEndElement(); } } else { FailUnknownElement(); } } else { _reader.Skip(); } } _reader.ReadEndElement(); } // Add the typeface. _compositeFontInfo.GetFamilyTypefaceList().Add(face); } ////// Parses the attributes of the FamilyTypeface element and sets the corresponding /// properties on the specified FamilyTypeface object. On return, the reader remains /// positioned on the element. /// private void ParseFamilyTypefaceAttributes(FamilyTypeface face) { // Iterate over the attributes. if (_reader.MoveToFirstAttribute()) { do { // Process attributes in the composite font namespace; ignore any others. if (IsCompositeFontAttribute()) { string name = _reader.LocalName; if (name == StyleAttribute) { FontStyle fontStyle = new FontStyle(); if (!FontStyles.FontStyleStringToKnownStyle(GetAttributeValue(), CultureInfo.InvariantCulture, ref fontStyle)) FailAttributeValue(); face.Style = fontStyle; } else if (name == WeightAttribute) { FontWeight fontWeight = new FontWeight(); if (!FontWeights.FontWeightStringToKnownWeight(GetAttributeValue(), CultureInfo.InvariantCulture, ref fontWeight)) FailAttributeValue(); face.Weight = fontWeight; } else if (name == StretchAttribute) { FontStretch fontStretch = new FontStretch(); if (!FontStretches.FontStretchStringToKnownStretch(GetAttributeValue(), CultureInfo.InvariantCulture, ref fontStretch)) FailAttributeValue(); face.Stretch = fontStretch; } else if (name == UnderlinePositionAttribute) { face.UnderlinePosition = GetAttributeAsDouble(); } else if (name == UnderlineThicknessAttribute) { face.UnderlineThickness = GetAttributeAsDouble(); } else if (name == StrikethroughPositionAttribute) { face.StrikethroughPosition = GetAttributeAsDouble(); } else if (name == StrikethroughThicknessAttribute) { face.StrikethroughThickness = GetAttributeAsDouble(); } else if (name == CapsHeightAttribute) { face.CapsHeight = GetAttributeAsDouble(); } else if (name == XHeightAttribute) { face.XHeight = GetAttributeAsDouble(); } else if (name == DeviceFontNameAttribute) { face.DeviceFontName = GetAttributeValue(); } else { FailUnknownAttribute(); } } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } } ////// Parses a CharacterMetrics element, and advances the current position beyond the /// element. Adds a CharacterMetrics object to the given FamilyTypface. /// private void ParseCharacterMetricsElement(FamilyTypeface face) { string key = null; string metrics = null; if (_reader.MoveToFirstAttribute()) { do { if (_reader.NamespaceURI == XamlNamespace && _reader.LocalName == KeyAttribute) { key = GetAttributeValue(); } else if (IsCompositeFontAttribute() && _reader.LocalName == MetricsAttribute) { metrics = GetAttributeValue(); } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } if (key == null) FailMissingAttribute(KeyAttribute); if (metrics == null) FailMissingAttribute(MetricsAttribute); face.DeviceFontCharacterMetrics.Add( CharacterMetricsDictionary.ConvertKey(key), new CharacterMetrics(metrics) ); // There should be no child elements. ParseEmptyElement(); } ////// Parses the FontFamilyMap element, including its attributes and children, /// and advances to the next sibling element. /// private void ParseFamilyMapElement() { FontFamilyMap fmap = new FontFamilyMap(); // Parse the family map attributes. if (_reader.MoveToFirstAttribute()) { do { // Process attributes in the composite font namespace; ignore any others. if (IsCompositeFontAttribute()) { string name = _reader.LocalName; if (name == UnicodeAttribute) { fmap.Unicode = GetAttributeValue(); } else if (name == TargetAttribute) { fmap.Target = GetAttributeValue(); } else if (name == ScaleAttribute) { fmap.Scale = GetAttributeAsDouble(); } else if (name == LanguageAttribute) { fmap.Language = GetAttributeAsXmlLanguage(); } else { FailUnknownAttribute(); } } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } _compositeFontInfo.FamilyMaps.Add(fmap); // There should be no child elements. ParseEmptyElement(); } ////// Advances past the current element and its children, throwing and exception /// if there are any child elements in the composite font namespace. /// private void ParseEmptyElement() { if (_reader.IsEmptyElement) { _reader.Read(); return; } _reader.Read(); while (MoveToContent() != XmlNodeType.EndElement) { if (_reader.NodeType == XmlNodeType.Element && _reader.NamespaceURI == CompositeFontNamespace) { FailUnknownElement(); } else { _reader.Skip(); } } _reader.ReadEndElement(); } ////// Determines whether the reader is positioned on an composite font attribute, /// which we define to me either (a) it has no namespace at all, or (b) it's in /// the composite font namespace. /// private bool IsCompositeFontAttribute() { string ns = _reader.NamespaceURI; return string.IsNullOrEmpty(ns) || ns == CompositeFontNamespace; } ////// Determines whether the attribute can be safely ignored, even if it /// has not been explicitly declared as ignorable via compatibility markup. /// Currently, we ignore attributes defined by the XML and XML namespaces /// standards. /// private bool IsIgnorableAttribute() { string ns = _reader.NamespaceURI; return ns == XmlNamespace || ns == XmlnsNamespace; } #region error reporting ////// Make sure the minimum required information is specified. /// private void VerifyCompositeFontInfo() { if (_compositeFontInfo.FamilyMaps.Count == 0) Fail(SR.Get(SRID.CompositeFontMissingElement, FamilyMapElement)); if (_compositeFontInfo.FamilyNames.Count == 0) Fail(SR.Get(SRID.CompositeFontMissingElement, StringElement)); } ////// Fail because of an XML exception. /// private void FailNotWellFormed(Exception x) { throw new FileFormatException(new Uri(_reader.BaseURI, UriKind.RelativeOrAbsolute), x); } ////// Fail because of an incorrect attribute value. /// private void FailAttributeValue() { Fail(SR.Get( SRID.CompositeFontAttributeValue1, _reader.LocalName)); } ////// Fail because of an incorrect attribute value with an inner exception. /// private void FailAttributeValue(Exception x) { Fail(SR.Get( SRID.CompositeFontAttributeValue2, _reader.LocalName, x.Message), x); } ////// Fail because of an unknown element. /// private void FailUnknownElement() { Fail(SR.Get( SRID.CompositeFontUnknownElement, _reader.LocalName, _reader.NamespaceURI)); } ////// Fail because of an unknown attribute. /// private void FailUnknownAttribute() { Fail(SR.Get( SRID.CompositeFontUnknownAttribute, _reader.LocalName, _reader.NamespaceURI)); } ////// Fail because a required attribute is not present. /// /// private void FailMissingAttribute(string name) { Fail(SR.Get(SRID.CompositeFontMissingAttribute, name)); } ////// Fail with a specified error message. /// private void Fail(string message) { Fail(message, null); } ////// Fail with a specified error message and inner exception. /// private void Fail(string message, Exception innerException) { string fileName = _reader.BaseURI; throw new FileFormatException(new Uri(fileName, UriKind.RelativeOrAbsolute), message, innerException); } #endregion private CompositeFontInfo _compositeFontInfo; private XmlReader _reader; // XML namespaces for which Mapping processing instructions have been read. For each entry, // the key is the XML namespace, and the value is either SystemClrNamespace (if the the // Mapping PI specifies "System" and "MSCORLIB") or String.Empty (any other Mapping). private Hashtable _namespaceMap; // Type converters for double and XmlLanguage types. private CultureInfo _englishUSCulture; private TypeConverter _doubleTypeConverter; private TypeConverter _xmlLanguageTypeConverter; private const string SystemClrNamespace = "System"; private const string CompositeFontNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/composite-font"; private const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; private const string XmlNamespace = "http://www.w3.org/XML/1998/namespace"; private const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; private const string FontFamilyElement = "FontFamily"; private const string BaselineAttribute = "Baseline"; private const string LineSpacingAttribute = "LineSpacing"; private const string FamilyNamesPropertyElement = "FontFamily.FamilyNames"; private const string StringElement = "String"; private const string FamilyTypefacesPropertyElement = "FontFamily.FamilyTypefaces"; private const string FamilyTypefaceElement = "FamilyTypeface"; private const string FamilyMapsPropertyElement = "FontFamily.FamilyMaps"; private const string FamilyMapElement = "FontFamilyMap"; private const string KeyAttribute = "Key"; private const string LanguageAttribute = "Language"; private const string NameAttribute = "Name"; private const string StyleAttribute = "Style"; private const string WeightAttribute = "Weight"; private const string StretchAttribute = "Stretch"; private const string UnderlinePositionAttribute = "UnderlinePosition"; private const string UnderlineThicknessAttribute = "UnderlineThickness"; private const string StrikethroughPositionAttribute = "StrikethroughPosition"; private const string StrikethroughThicknessAttribute = "StrikethroughThickness"; private const string CapsHeightAttribute = "CapsHeight"; private const string XHeightAttribute = "XHeight"; private const string UnicodeAttribute = "Unicode"; private const string TargetAttribute = "Target"; private const string ScaleAttribute = "Scale"; private const string DeviceFontNameAttribute = "DeviceFontName"; private const string DeviceFontCharacterMetricsPropertyElement = "FamilyTypeface.DeviceFontCharacterMetrics"; private const string CharacterMetricsElement = "CharacterMetrics"; private const string MetricsAttribute = "Metrics"; } } namespace MS.Internal.TextFormatting { ////// Partial class splitted from the original one in LineServices.cs. /// We do this to avoid bringing in TextFormatting namespace when /// building FontCacheServices.exe /// internal static partial class Constants { ////// Greatest multiple of em allowed in composite font file /// public const double GreatestMutiplierOfEm = 100; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // Contents: The XML Composite font parsing // // Created: 6-11-2003 Tarek Mahmoud Sayed ([....]) // //--------------------------------------------------------------------------- using System; using System.IO; using System.Security; using System.Security.Permissions; using System.Text; using System.Windows; using System.Windows.Media; using System.Windows.Markup; using System.Xml; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using MS.Internal.TextFormatting; using System.Reflection; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; namespace MS.Internal.FontFace { internal class CompositeFontParser { internal static void VerifyMultiplierOfEm(string propertyName, ref double value) { if (DoubleUtil.IsNaN(value)) { throw new ArgumentException(SR.Get(SRID.PropertyValueCannotBeNaN, propertyName)); } else if (value > Constants.GreatestMutiplierOfEm) { value = Constants.GreatestMutiplierOfEm; } else if (value < -Constants.GreatestMutiplierOfEm) { value = -Constants.GreatestMutiplierOfEm; } } internal static void VerifyPositiveMultiplierOfEm(string propertyName, ref double value) { if (DoubleUtil.IsNaN(value)) { throw new ArgumentException(SR.Get(SRID.PropertyValueCannotBeNaN, propertyName)); } else if (value > Constants.GreatestMutiplierOfEm) { value = Constants.GreatestMutiplierOfEm; } else if (value <= 0) { throw new ArgumentException(SR.Get(SRID.PropertyMustBeGreaterThanZero, propertyName)); } } internal static void VerifyNonNegativeMultiplierOfEm(string propertyName, ref double value) { if (DoubleUtil.IsNaN(value)) { throw new ArgumentException(SR.Get(SRID.PropertyValueCannotBeNaN, propertyName)); } else if (value > Constants.GreatestMutiplierOfEm) { value = Constants.GreatestMutiplierOfEm; } else if (value < 0) { throw new ArgumentException(SR.Get(SRID.PropertyCannotBeNegative, propertyName)); } } private double GetAttributeAsDouble() { object value = null; try { value = _doubleTypeConverter.ConvertFromString( null, // type converter context _englishUSCulture, GetAttributeValue() ); } catch (NotSupportedException) { FailAttributeValue(); } if (value == null) FailAttributeValue(); return (double)value; } private XmlLanguage GetAttributeAsXmlLanguage() { object value = null; try { value = _xmlLanguageTypeConverter.ConvertFromString( null, // type converter context _englishUSCulture, GetAttributeValue() ); } catch (NotSupportedException) { FailAttributeValue(); } if (value == null) FailAttributeValue(); return (XmlLanguage)value; } ////// Gets the value of the value of the current node which is assumed to be an /// attribute. Checks for markup expressions or escaped braces. /// private string GetAttributeValue() { string s = _reader.Value; if (string.IsNullOrEmpty(s)) return string.Empty; if (s[0] == '{') { if (s.Length > 1 && s[1] == '}') { s = s.Substring(2); } else { FailAttributeValue(); } } return s; } private const NumberStyles UnsignedDecimalPointStyle = NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingWhite | NumberStyles.AllowDecimalPoint; private const NumberStyles SignedDecimalPointStyle = UnsignedDecimalPointStyle | NumberStyles.AllowLeadingSign; ////// Reads the specified composite font file. /// internal static CompositeFontInfo LoadXml(Stream fileStream) { CompositeFontParser parser = new CompositeFontParser(fileStream); return parser._compositeFontInfo; } ////// Constructs the composite font parser and parses the file. /// /// File stream to parse. private CompositeFontParser(Stream fileStream) { _compositeFontInfo = new CompositeFontInfo(); _namespaceMap = new Hashtable(); _englishUSCulture = CultureInfo.GetCultureInfoByIetfLanguageTag("en-US"); _doubleTypeConverter = TypeDescriptor.GetConverter(typeof(double)); _xmlLanguageTypeConverter = new System.Windows.Markup.XmlLanguageConverter(); _reader = CreateXmlReader(fileStream); try { if (IsStartElement(FontFamilyElement, CompositeFontNamespace)) { ParseFontFamilyElement(); } else { FailUnknownElement(); } } catch (XmlException x) { FailNotWellFormed(x); } catch (XmlSyntaxException x) { FailNotWellFormed(x); } catch (FormatException x) { if (_reader.NodeType == XmlNodeType.Attribute) FailAttributeValue(x); else Fail(x.Message, x); } catch (ArgumentException x) { if (_reader.NodeType == XmlNodeType.Attribute) FailAttributeValue(x); else Fail(x.Message, x); } finally { _reader.Close(); _reader = null; } } ////// Creates the XML reader for the specified file. /// private XmlReader CreateXmlReader(Stream fileStream) { XmlReaderSettings settings = new XmlReaderSettings(); settings.CloseInput = true; settings.IgnoreComments = true; settings.IgnoreWhitespace = false; settings.ProhibitDtd = true; XmlReader baseReader = XmlReader.Create(fileStream, settings); return new XmlCompatibilityReader(baseReader, new IsXmlNamespaceSupportedCallback(IsXmlNamespaceSupported)); } ////// Determines whether a given XML namespace is "known" (i.e., should always be processed) /// or "unknown" (i.e., should be skipped if declared ignorable). /// /// XML namespace to look up. /// Other namespace to map to, if any. Used for versioning. /// This implementation always returns null in this parameter. ////// Returns true ("known") for the XAML namespace or the composite font namespace. /// for which a Mapping PI exists. /// ////// System.String is the only object in a mapped namespace that we can instantiate. However, /// we don't want to ignore any mapped namespaces for compatibility reasons. In general, it's /// better for us to reject valid XAML than to accept invalid XAML. We therefore don't want /// to ignore an element which the XAML parser would not ignore -- the ignored element might /// be invalid. If mapped elements other than System.String are needed in future versions, a /// composite font author can achieve backwards compatibility by conditionalizing mapped /// elements using c:AlternateContent markup. /// private bool IsXmlNamespaceSupported(string xmlNamespace, out string newXmlNamespace) { newXmlNamespace = null; return xmlNamespace == CompositeFontNamespace || xmlNamespace == XamlNamespace || IsMappedNamespace(xmlNamespace); } ////// Calls MoveToContent and checks whether the reader is positioned on the specified element. /// ////// We should always call this method instead of calling _reader.IsStartElement directly because /// the latter calls MoveToContent on the underlying reader which means we could fail to parse /// Mapping processing instructions. /// private bool IsStartElement(string localName, string namespaceURI) { MoveToContent(); return _reader.IsStartElement(localName, namespaceURI); } ////// Same semantics as XmlReader.MoveToContent, but this method processes Mapping processing /// instructions as it advances past them. /// private XmlNodeType MoveToContent() { bool contentNode = false; do { switch (_reader.NodeType) { case XmlNodeType.CDATA: case XmlNodeType.Element: case XmlNodeType.EndElement: case XmlNodeType.EntityReference: case XmlNodeType.EndEntity: contentNode = true; break; } } while (!contentNode && _reader.Read()); return _reader.NodeType; } #region ProcessingInstructions private bool IsMappedNamespace(string xmlNamespace) { return _namespaceMap.ContainsKey(xmlNamespace); } private bool IsSystemNamespace(string xmlNamespace) { return (xmlNamespace == "clr-namespace:System;assembly=mscorlib"); } #endregion ProcessingInstructions ////// Parses the FontFamily element, including its attributes and children, /// and advances to the next sibling element. /// private void ParseFontFamilyElement() { // Iterate over the attributes. if (_reader.MoveToFirstAttribute()) { do { // Process attributes in the composite font namespace if (IsCompositeFontAttribute()) { string name = _reader.LocalName; if (name == BaselineAttribute) { _compositeFontInfo.Baseline = GetAttributeAsDouble(); } else if (name == LineSpacingAttribute) { _compositeFontInfo.LineSpacing = GetAttributeAsDouble(); } else { FailUnknownAttribute(); } } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } // Empty element? if (_reader.IsEmptyElement) { VerifyCompositeFontInfo(); _reader.Read(); return; } // Advance past the start tag. _reader.Read(); // Iterate over children. while (MoveToContent() != XmlNodeType.EndElement) { if (_reader.NodeType == XmlNodeType.Element && _reader.NamespaceURI == CompositeFontNamespace) { bool isEmpty = _reader.IsEmptyElement; // It's an element in the composite font namespace; branch depending on the name. switch (_reader.LocalName) { case FamilyNamesPropertyElement: VerifyNoAttributes(); _reader.Read(); if (!isEmpty) { // Process all child elements. while (MoveToContent() == XmlNodeType.Element) { if (_reader.LocalName == StringElement && IsSystemNamespace(_reader.NamespaceURI)) { // It's a System.String. ParseFamilyNameElement(); } else { // Only System.String is valid in this context. FailUnknownElement(); } } // Advance past the end element, or throw // an exception if we're not at an end element. _reader.ReadEndElement(); } break; case FamilyTypefacesPropertyElement: VerifyNoAttributes(); _reader.Read(); if (!isEmpty) { // Process child elements, of which the only one we recognize in this // context is FamilyTypeface. while (IsStartElement(FamilyTypefaceElement, CompositeFontNamespace)) { ParseFamilyTypefaceElement(); } // Advance past the end element, or throw // an exception if we're not at an end element. _reader.ReadEndElement(); } break; case FamilyMapsPropertyElement: VerifyNoAttributes(); _reader.Read(); if (!isEmpty) { // Process child elements, of which the only one we recognize in this // context is FontFamilyMap. while (IsStartElement(FamilyMapElement, CompositeFontNamespace)) { ParseFamilyMapElement(); } // Advance past the end element, or throw // an exception if we're not at an end element. _reader.ReadEndElement(); } break; default: // It's some other element. FailUnknownElement(); break; } } else { // It's some other content besides an element in the composite font namespace; skip it. _reader.Skip(); } } // We should now have read right up to the end tag. VerifyCompositeFontInfo(); _reader.ReadEndElement(); } ////// Makes sure the current element has no attributes (except ignorable ones). /// private void VerifyNoAttributes() { if (_reader.MoveToFirstAttribute()) { do { if (!IsIgnorableAttribute()) FailUnknownAttribute(); } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } } ////// Parses the FamilyName element (actually String), including its attributes /// and children, and advances to the next sibling element. /// private void ParseFamilyNameElement() { XmlLanguage language = null; // Iterate over the attributes. if (_reader.MoveToFirstAttribute()) { do { if (_reader.NamespaceURI == XamlNamespace && _reader.LocalName == KeyAttribute) { language = GetAttributeAsXmlLanguage(); } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } // XAML requires x:Key so we should, too. if (language == null) { FailMissingAttribute(LanguageAttribute); } // The family name is the element content. string familyName = _reader.ReadElementString(); if (string.IsNullOrEmpty(familyName)) { FailMissingAttribute(NameAttribute); } _compositeFontInfo.FamilyNames.Add(language, familyName); } ////// Parses the FamilyTypeface element, including its attributes and children, /// and advances to the next sibling element. /// private void ParseFamilyTypefaceElement() { FamilyTypeface face = new FamilyTypeface(); ParseFamilyTypefaceAttributes(face); if (_reader.IsEmptyElement) { _reader.Read(); } else { _reader.Read(); while (MoveToContent() != XmlNodeType.EndElement) { if (_reader.NodeType == XmlNodeType.Element && _reader.NamespaceURI == CompositeFontNamespace) { if (_reader.LocalName == DeviceFontCharacterMetricsPropertyElement) { VerifyNoAttributes(); if (_reader.IsEmptyElement) { _reader.Read(); } else { _reader.Read(); // Process all child elements. while (MoveToContent() == XmlNodeType.Element) { if (_reader.LocalName == CharacterMetricsElement) { ParseCharacterMetricsElement(face); } else { // Only CharacterMetricsElement is valid in this context. FailUnknownElement(); } } // Process the end element for the collection. _reader.ReadEndElement(); } } else { FailUnknownElement(); } } else { _reader.Skip(); } } _reader.ReadEndElement(); } // Add the typeface. _compositeFontInfo.GetFamilyTypefaceList().Add(face); } ////// Parses the attributes of the FamilyTypeface element and sets the corresponding /// properties on the specified FamilyTypeface object. On return, the reader remains /// positioned on the element. /// private void ParseFamilyTypefaceAttributes(FamilyTypeface face) { // Iterate over the attributes. if (_reader.MoveToFirstAttribute()) { do { // Process attributes in the composite font namespace; ignore any others. if (IsCompositeFontAttribute()) { string name = _reader.LocalName; if (name == StyleAttribute) { FontStyle fontStyle = new FontStyle(); if (!FontStyles.FontStyleStringToKnownStyle(GetAttributeValue(), CultureInfo.InvariantCulture, ref fontStyle)) FailAttributeValue(); face.Style = fontStyle; } else if (name == WeightAttribute) { FontWeight fontWeight = new FontWeight(); if (!FontWeights.FontWeightStringToKnownWeight(GetAttributeValue(), CultureInfo.InvariantCulture, ref fontWeight)) FailAttributeValue(); face.Weight = fontWeight; } else if (name == StretchAttribute) { FontStretch fontStretch = new FontStretch(); if (!FontStretches.FontStretchStringToKnownStretch(GetAttributeValue(), CultureInfo.InvariantCulture, ref fontStretch)) FailAttributeValue(); face.Stretch = fontStretch; } else if (name == UnderlinePositionAttribute) { face.UnderlinePosition = GetAttributeAsDouble(); } else if (name == UnderlineThicknessAttribute) { face.UnderlineThickness = GetAttributeAsDouble(); } else if (name == StrikethroughPositionAttribute) { face.StrikethroughPosition = GetAttributeAsDouble(); } else if (name == StrikethroughThicknessAttribute) { face.StrikethroughThickness = GetAttributeAsDouble(); } else if (name == CapsHeightAttribute) { face.CapsHeight = GetAttributeAsDouble(); } else if (name == XHeightAttribute) { face.XHeight = GetAttributeAsDouble(); } else if (name == DeviceFontNameAttribute) { face.DeviceFontName = GetAttributeValue(); } else { FailUnknownAttribute(); } } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } } ////// Parses a CharacterMetrics element, and advances the current position beyond the /// element. Adds a CharacterMetrics object to the given FamilyTypface. /// private void ParseCharacterMetricsElement(FamilyTypeface face) { string key = null; string metrics = null; if (_reader.MoveToFirstAttribute()) { do { if (_reader.NamespaceURI == XamlNamespace && _reader.LocalName == KeyAttribute) { key = GetAttributeValue(); } else if (IsCompositeFontAttribute() && _reader.LocalName == MetricsAttribute) { metrics = GetAttributeValue(); } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } if (key == null) FailMissingAttribute(KeyAttribute); if (metrics == null) FailMissingAttribute(MetricsAttribute); face.DeviceFontCharacterMetrics.Add( CharacterMetricsDictionary.ConvertKey(key), new CharacterMetrics(metrics) ); // There should be no child elements. ParseEmptyElement(); } ////// Parses the FontFamilyMap element, including its attributes and children, /// and advances to the next sibling element. /// private void ParseFamilyMapElement() { FontFamilyMap fmap = new FontFamilyMap(); // Parse the family map attributes. if (_reader.MoveToFirstAttribute()) { do { // Process attributes in the composite font namespace; ignore any others. if (IsCompositeFontAttribute()) { string name = _reader.LocalName; if (name == UnicodeAttribute) { fmap.Unicode = GetAttributeValue(); } else if (name == TargetAttribute) { fmap.Target = GetAttributeValue(); } else if (name == ScaleAttribute) { fmap.Scale = GetAttributeAsDouble(); } else if (name == LanguageAttribute) { fmap.Language = GetAttributeAsXmlLanguage(); } else { FailUnknownAttribute(); } } else if (!IsIgnorableAttribute()) { FailUnknownAttribute(); } } while (_reader.MoveToNextAttribute()); _reader.MoveToElement(); } _compositeFontInfo.FamilyMaps.Add(fmap); // There should be no child elements. ParseEmptyElement(); } ////// Advances past the current element and its children, throwing and exception /// if there are any child elements in the composite font namespace. /// private void ParseEmptyElement() { if (_reader.IsEmptyElement) { _reader.Read(); return; } _reader.Read(); while (MoveToContent() != XmlNodeType.EndElement) { if (_reader.NodeType == XmlNodeType.Element && _reader.NamespaceURI == CompositeFontNamespace) { FailUnknownElement(); } else { _reader.Skip(); } } _reader.ReadEndElement(); } ////// Determines whether the reader is positioned on an composite font attribute, /// which we define to me either (a) it has no namespace at all, or (b) it's in /// the composite font namespace. /// private bool IsCompositeFontAttribute() { string ns = _reader.NamespaceURI; return string.IsNullOrEmpty(ns) || ns == CompositeFontNamespace; } ////// Determines whether the attribute can be safely ignored, even if it /// has not been explicitly declared as ignorable via compatibility markup. /// Currently, we ignore attributes defined by the XML and XML namespaces /// standards. /// private bool IsIgnorableAttribute() { string ns = _reader.NamespaceURI; return ns == XmlNamespace || ns == XmlnsNamespace; } #region error reporting ////// Make sure the minimum required information is specified. /// private void VerifyCompositeFontInfo() { if (_compositeFontInfo.FamilyMaps.Count == 0) Fail(SR.Get(SRID.CompositeFontMissingElement, FamilyMapElement)); if (_compositeFontInfo.FamilyNames.Count == 0) Fail(SR.Get(SRID.CompositeFontMissingElement, StringElement)); } ////// Fail because of an XML exception. /// private void FailNotWellFormed(Exception x) { throw new FileFormatException(new Uri(_reader.BaseURI, UriKind.RelativeOrAbsolute), x); } ////// Fail because of an incorrect attribute value. /// private void FailAttributeValue() { Fail(SR.Get( SRID.CompositeFontAttributeValue1, _reader.LocalName)); } ////// Fail because of an incorrect attribute value with an inner exception. /// private void FailAttributeValue(Exception x) { Fail(SR.Get( SRID.CompositeFontAttributeValue2, _reader.LocalName, x.Message), x); } ////// Fail because of an unknown element. /// private void FailUnknownElement() { Fail(SR.Get( SRID.CompositeFontUnknownElement, _reader.LocalName, _reader.NamespaceURI)); } ////// Fail because of an unknown attribute. /// private void FailUnknownAttribute() { Fail(SR.Get( SRID.CompositeFontUnknownAttribute, _reader.LocalName, _reader.NamespaceURI)); } ////// Fail because a required attribute is not present. /// /// private void FailMissingAttribute(string name) { Fail(SR.Get(SRID.CompositeFontMissingAttribute, name)); } ////// Fail with a specified error message. /// private void Fail(string message) { Fail(message, null); } ////// Fail with a specified error message and inner exception. /// private void Fail(string message, Exception innerException) { string fileName = _reader.BaseURI; throw new FileFormatException(new Uri(fileName, UriKind.RelativeOrAbsolute), message, innerException); } #endregion private CompositeFontInfo _compositeFontInfo; private XmlReader _reader; // XML namespaces for which Mapping processing instructions have been read. For each entry, // the key is the XML namespace, and the value is either SystemClrNamespace (if the the // Mapping PI specifies "System" and "MSCORLIB") or String.Empty (any other Mapping). private Hashtable _namespaceMap; // Type converters for double and XmlLanguage types. private CultureInfo _englishUSCulture; private TypeConverter _doubleTypeConverter; private TypeConverter _xmlLanguageTypeConverter; private const string SystemClrNamespace = "System"; private const string CompositeFontNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/composite-font"; private const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; private const string XmlNamespace = "http://www.w3.org/XML/1998/namespace"; private const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; private const string FontFamilyElement = "FontFamily"; private const string BaselineAttribute = "Baseline"; private const string LineSpacingAttribute = "LineSpacing"; private const string FamilyNamesPropertyElement = "FontFamily.FamilyNames"; private const string StringElement = "String"; private const string FamilyTypefacesPropertyElement = "FontFamily.FamilyTypefaces"; private const string FamilyTypefaceElement = "FamilyTypeface"; private const string FamilyMapsPropertyElement = "FontFamily.FamilyMaps"; private const string FamilyMapElement = "FontFamilyMap"; private const string KeyAttribute = "Key"; private const string LanguageAttribute = "Language"; private const string NameAttribute = "Name"; private const string StyleAttribute = "Style"; private const string WeightAttribute = "Weight"; private const string StretchAttribute = "Stretch"; private const string UnderlinePositionAttribute = "UnderlinePosition"; private const string UnderlineThicknessAttribute = "UnderlineThickness"; private const string StrikethroughPositionAttribute = "StrikethroughPosition"; private const string StrikethroughThicknessAttribute = "StrikethroughThickness"; private const string CapsHeightAttribute = "CapsHeight"; private const string XHeightAttribute = "XHeight"; private const string UnicodeAttribute = "Unicode"; private const string TargetAttribute = "Target"; private const string ScaleAttribute = "Scale"; private const string DeviceFontNameAttribute = "DeviceFontName"; private const string DeviceFontCharacterMetricsPropertyElement = "FamilyTypeface.DeviceFontCharacterMetrics"; private const string CharacterMetricsElement = "CharacterMetrics"; private const string MetricsAttribute = "Metrics"; } } namespace MS.Internal.TextFormatting { ////// Partial class splitted from the original one in LineServices.cs. /// We do this to avoid bringing in TextFormatting namespace when /// building FontCacheServices.exe /// internal static partial class Constants { ////// Greatest multiple of em allowed in composite font file /// public const double GreatestMutiplierOfEm = 100; } } // 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
- GB18030Encoding.cs
- HttpListenerResponse.cs
- CustomErrorsSectionWrapper.cs
- DbConnectionPoolOptions.cs
- LOSFormatter.cs
- ReaderContextStackData.cs
- ToolStripStatusLabel.cs
- SessionSymmetricMessageSecurityProtocolFactory.cs
- EntityDesignerDataSourceView.cs
- CatalogPartCollection.cs
- GenericPrincipal.cs
- FixedTextSelectionProcessor.cs
- EmptyEnumerator.cs
- RawAppCommandInputReport.cs
- FormsAuthenticationConfiguration.cs
- _SslStream.cs
- DetailsViewModeEventArgs.cs
- InternalRelationshipCollection.cs
- CustomAttributeSerializer.cs
- DataDocumentXPathNavigator.cs
- OleDbConnectionFactory.cs
- ButtonStandardAdapter.cs
- IsolatedStorageFilePermission.cs
- WsdlInspector.cs
- PropertyRef.cs
- CodeDirectionExpression.cs
- GC.cs
- DataGridViewDataConnection.cs
- QuaternionRotation3D.cs
- TransactionTable.cs
- DocumentXPathNavigator.cs
- WmlPanelAdapter.cs
- WindowsStatic.cs
- DataControlHelper.cs
- ShaperBuffers.cs
- SmiGettersStream.cs
- XPathAxisIterator.cs
- __FastResourceComparer.cs
- ClientConfigurationHost.cs
- Span.cs
- ValueTypeFieldReference.cs
- SHA256Managed.cs
- typedescriptorpermissionattribute.cs
- TextFormattingConverter.cs
- Int16KeyFrameCollection.cs
- ProfileParameter.cs
- TextModifierScope.cs
- SmtpException.cs
- FlowDocumentFormatter.cs
- WmlPanelAdapter.cs
- SmtpCommands.cs
- HMACMD5.cs
- XPathNodeList.cs
- ping.cs
- WsatServiceCertificate.cs
- RequestResizeEvent.cs
- InputReportEventArgs.cs
- MainMenu.cs
- XmlSchemaExternal.cs
- TypeBinaryExpression.cs
- ClientBuildManager.cs
- CodeVariableReferenceExpression.cs
- StoreAnnotationsMap.cs
- LocalValueEnumerator.cs
- RegistrationContext.cs
- MailSettingsSection.cs
- SqlDataSourceCommandEventArgs.cs
- SystemIPGlobalProperties.cs
- MenuEventArgs.cs
- BridgeDataReader.cs
- XsltFunctions.cs
- CacheAxisQuery.cs
- HashMembershipCondition.cs
- sapiproxy.cs
- GPRECTF.cs
- BrowserTree.cs
- NativeMethodsCLR.cs
- AdornedElementPlaceholder.cs
- PolyLineSegment.cs
- DataGridTextBox.cs
- ResolveCriteriaCD1.cs
- _SafeNetHandles.cs
- RayMeshGeometry3DHitTestResult.cs
- SetterTriggerConditionValueConverter.cs
- SpecialTypeDataContract.cs
- CompositeCollection.cs
- StylusEditingBehavior.cs
- Filter.cs
- ObjectPropertyMapping.cs
- QueryStringParameter.cs
- RenderOptions.cs
- UnsafeNativeMethods.cs
- ManagementDateTime.cs
- ProcessHostMapPath.cs
- ZipIOLocalFileHeader.cs
- DataTableMapping.cs
- UInt64Converter.cs
- TraceEventCache.cs
- XsdDataContractImporter.cs
- StringFreezingAttribute.cs