Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / FontFace / FontFamilyIdentifier.cs / 1 / FontFamilyIdentifier.cs
//---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // Description: FontFamilyIdentifier type // // History: // 5/6/2005 : [....] - Created // //--------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Security; using System.Text; using System.Windows; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Utility; using MS.Internal; using MS.Internal.Shaping; using MS.Internal.FontCache; using MS.Internal.TextFormatting; namespace MS.Internal.FontFace { ////// The FontFamilyIdentifier value type encapsulates a friendly name and base Uri /// and provides access to the corresponding canonical name(s) via an indexer. /// // // The friendly name is a string in the format passed to the FontFamily constructor and the // corresponding type converter. It comprises one or more font family references separated by // commas (with literal commas escaped by doubling). Each font family reference comprises a // family name and an optional location. // // Pseudo-BNF: // // friendlyName = ESCAPED(fontFamilyReference) *( "," ESCAPED(fontFamilyReference) ) // fontFamilyReference = [ location "#" ] escapedFamilyName // location = "" | relativeUri | absoluteUri // // where ESCAPED(fontFamilyReference) denotes a fontFamilyReference in which comma characters (",") // have been replaced by doubled commas (",,"). // // Both the location (if present) and the escapedFamilyName may contain hexadecimal escape // sequences in the form %XX as in URI references. // // The location may be an empty string so "#ARIAL" is a valid font family reference; // in fact it is the normalized form of "Arial". // // Canonicalization // // Canonicalization is the process of converting a font family reference to an absolute URI // which specifies the font family location, plus a fragment which specifies the family name. // The family name is converted to uppercase (since family names are not case-sensitive) but // the rest of the URI is not. // // The process for canonicalizing the entire friendly name is as follows: // // 1. Split the friendly name into font family references. // Treat single commas (",") as delimiters, and unescape double commas (",,"). // // 2. Convert each font family reference to a normalized form. // See Util.NormalizeFontFamilyReference. // // 3. Canonicalize the normalized font family reference. // See Util.GetCanonicalUriForFamily. // // This is essentially what the Canonicalize method does, with addition of caching the resulting // canonical names in the TypefaceMetricsCache. To save working set, the result of canonicalization // is stored as a single null-delimited string rather than an array of strings. // // Since canonicalization is potentially expensive, we do not always canonicalize the entire // friendly name. In this case, the indexer canonicalizes the requested font family reference // on demand. However, we still cache the result in the TypefaceMetricsCache. // internal struct FontFamilyIdentifier { ////// FontFamilyIdentifier constructor /// /// friendly name in the format passed to /// FontFamily constructor and type converter. /// Base Uri used to resolve the location part of a font family reference /// if one exists and is relative internal FontFamilyIdentifier(string friendlyName, Uri baseUri) { _friendlyName = friendlyName; _baseUri = baseUri; _tokenCount = (friendlyName != null) ? -1 : 0; _canonicalReferences = null; } ////// Create a FontFamilyIdentifier by concatenating two existing identifiers. /// internal FontFamilyIdentifier(FontFamilyIdentifier first, FontFamilyIdentifier second) { first.Canonicalize(); second.Canonicalize(); _friendlyName = null; _tokenCount = first._tokenCount + second._tokenCount; _baseUri = null; if (first._tokenCount == 0) { _canonicalReferences = second._canonicalReferences; } else if (second._tokenCount == 0) { _canonicalReferences = first._canonicalReferences; } else { _canonicalReferences = new CanonicalFontFamilyReference[_tokenCount]; int i = 0; foreach (CanonicalFontFamilyReference family in first._canonicalReferences) { _canonicalReferences[i++] = family; } foreach (CanonicalFontFamilyReference family in second._canonicalReferences) { _canonicalReferences[i++] = family; } } } internal string Source { get { return _friendlyName; } } internal Uri BaseUri { get { return _baseUri; } } public bool Equals(FontFamilyIdentifier other) { if (_friendlyName == other._friendlyName && _baseUri == other._baseUri) return true; int c = Count; if (other.Count != c) return false; if (c != 0) { Canonicalize(); other.Canonicalize(); for (int i = 0; i < c; ++i) { if (!_canonicalReferences[i].Equals(other._canonicalReferences[i])) return false; } } return true; } public override bool Equals(object obj) { return obj is FontFamilyIdentifier && Equals((FontFamilyIdentifier)obj); } public override int GetHashCode() { int hash = 1; if (Count != 0) { Canonicalize(); foreach (CanonicalFontFamilyReference family in _canonicalReferences) { hash = HashFn.HashMultiply(hash) + family.GetHashCode(); } } return HashFn.HashScramble(hash); } internal int Count { get { // negative value represents uninitialized count if (_tokenCount < 0) { _tokenCount = CountTokens(_friendlyName); } return _tokenCount; } } internal CanonicalFontFamilyReference this[int tokenIndex] { get { if (tokenIndex < 0 || tokenIndex >= Count) throw new ArgumentOutOfRangeException("tokenIndex"); // Have we already been canonicalized? if (_canonicalReferences != null) { // We have already canonicalized. This is typically the case for longer-lived // identifiers such as belong to FontFamily objects. return _canonicalReferences[tokenIndex]; } else { // We have not already canonicalized. This is probably a short-lived object so // it's not worthwhile to canonicalize all the names up front and cache them for // later use. Just canonicalize each name as we need it. // find the Nth font family reference. int i, length; int j = FindToken(_friendlyName, 0, out i, out length); for (int k = 0; k < tokenIndex; ++k) { j = FindToken(_friendlyName, j, out i, out length); } // canonicalize just this font family reference return GetCanonicalReference(i, length); } } } ////// Critical - as it accesses canonical names as raw strings /// Safe - as information is not returned but stored in SecurityCritical _canonicalReferences field /// [SecurityCritical, SecurityTreatAsSafe] internal void Canonicalize() { if (_canonicalReferences != null) return; int count = this.Count; if (count == 0) return; // First look up the entire friendly name in the cache; this may enable us to // save working set by sharing the same array of may equal FontFamilyIdentifier. BasedFriendlyName hashKey = new BasedFriendlyName(_baseUri, _friendlyName); CanonicalFontFamilyReference[] canonicalReferences = TypefaceMetricsCache.ReadonlyLookup(hashKey) as CanonicalFontFamilyReference[]; if (canonicalReferences == null) { // We need to construct a new array. canonicalReferences = new CanonicalFontFamilyReference[count]; // Add the first canonical family reference. int i, length; int j = FindToken(_friendlyName, 0, out i, out length); canonicalReferences[0] = GetCanonicalReference(i, length); // Add subsequent family references. for (int k = 1; k < count; ++k) { j = FindToken(_friendlyName, j, out i, out length); canonicalReferences[k] = GetCanonicalReference(i, length); } // Add the array to the cache. TypefaceMetricsCache.Add(hashKey, canonicalReferences); } // for thread safety, we assign to the field only after the array is fully initialized _canonicalReferences = canonicalReferences; } #region Friendly name parsing methods private static int CountTokens(string friendlyName) { int count = 0; int i, length; int j = FindToken(friendlyName, 0, out i, out length); while (j >= 0) { // Limit the number of family names in a single string. if (++count == MaxFamilyNamePerFamilyMapTarget) break; j = FindToken(friendlyName, j, out i, out length); } return count; } ////// Scans the specified friendly name starting at the specified index and gets the index and /// length of the first token it finds. /// /// friendly name containing zero or more comma-delimited tokens /// character index to scan from /// receives the index of the token (or zero if none) /// receives the length of the token (or zero if none) ///If a token was found, the return value is a positive integer specifying where to begin /// scanning for the next token; if no token was found, the return value is -1. private static int FindToken(string friendlyName, int i, out int tokenIndex, out int tokenLength) { int length = friendlyName.Length; while (i < length) { // skip leading whitespace while (i < length && char.IsWhiteSpace(friendlyName[i])) ++i; int begin = i; // find delimiter or end of string while (i < length) { if (friendlyName[i] == FamilyNameDelimiter) { if (i + 1 < length && friendlyName[i + 1] == FamilyNameDelimiter) { // Don't treat double commas as the family name delimiter. i += 2; } else { break; // single comma delimiter } } else if (friendlyName[i] == '\0') { break; // might as well treat null as a delimiter too } else { ++i; } } // exclude trailing whitespace int end = i; while (end > begin && char.IsWhiteSpace(friendlyName[end - 1])) --end; // make sure it's not an empty string if (begin < end) { tokenIndex = begin; tokenLength = end - begin; return i + 1; } // continue after delimiter ++i; } // no token tokenIndex = length; tokenLength = 0; return -1; } private CanonicalFontFamilyReference GetCanonicalReference(int startIndex, int length) { string normalizedString = Util.GetNormalizedFontFamilyReference(_friendlyName, startIndex, length); // For caching normalized names, we use a different type of key which does not compare equal // to the keys we used for caching friendly names. BasedNormalizedName hashKey = new BasedNormalizedName(_baseUri, normalizedString); // Look up the normalized string and base URI in the cache? CanonicalFontFamilyReference canonicalReference = TypefaceMetricsCache.ReadonlyLookup(hashKey) as CanonicalFontFamilyReference; // Do we already have a cached font family reference? if (canonicalReference == null) { // Not in cache. Construct a new font family reference. canonicalReference = CanonicalFontFamilyReference.Create(_baseUri, normalizedString); // Add it to the cache. TypefaceMetricsCache.Add(hashKey, canonicalReference); } return canonicalReference; } #endregion #region BasedFriendlyName and BasedNormalizedName ////// BasedFriendlyName represents a friendly name with an associated URI or use as a hash key. /// private sealed class BasedFriendlyName : BasedName { public BasedFriendlyName(Uri baseUri, string name) : base(baseUri, name) { } public override int GetHashCode() { // Specify a different seed than BasedNormalizedName return InternalGetHashCode(1); } public override bool Equals(object obj) { // Only compare equal to other BasedFriendlyName objects return InternalEquals(obj as BasedFriendlyName); } } ////// BasedNormalizedName represents a normalized name with an associated URI or use as a hash key. /// private sealed class BasedNormalizedName : BasedName { public BasedNormalizedName(Uri baseUri, string name) : base(baseUri, name) { } public override int GetHashCode() { // Specify a different seed than BasedFriendlyName return InternalGetHashCode(int.MaxValue); } public override bool Equals(object obj) { // Only compare equal to other BasedNormalizedName objects return InternalEquals(obj as BasedNormalizedName); } } ////// BasedName implements shared functionality of BasedFriendlyName and BasedNormalizedName. /// The reason for the two derived classes (and for not just using Pair) is that we don't /// want these two different types of keys to compare equal. /// private abstract class BasedName { private Uri _baseUri; private string _name; protected BasedName(Uri baseUri, string name) { _baseUri = baseUri; _name = name; } public abstract override int GetHashCode(); public abstract override bool Equals(object obj); protected int InternalGetHashCode(int seed) { int hash = seed; if (_baseUri != null) hash += HashFn.HashMultiply(_baseUri.GetHashCode()); if (_name != null) hash = HashFn.HashMultiply(hash) + _name.GetHashCode(); return HashFn.HashScramble(hash); } protected bool InternalEquals(BasedName other) { return other != null && other._baseUri == _baseUri && other._name == _name; } } #endregion private string _friendlyName; private Uri _baseUri; private int _tokenCount; private CanonicalFontFamilyReference[] _canonicalReferences; internal const char FamilyNameDelimiter = ','; internal const int MaxFamilyNamePerFamilyMapTarget = 32; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- OdbcHandle.cs
- PointHitTestParameters.cs
- RadioButtonBaseAdapter.cs
- WebPartCloseVerb.cs
- SymLanguageVendor.cs
- EdgeProfileValidation.cs
- UserUseLicenseDictionaryLoader.cs
- SignatureToken.cs
- BrowserTree.cs
- XamlStyleSerializer.cs
- VisualStyleRenderer.cs
- UInt16.cs
- XmlAttributeCollection.cs
- ContextConfiguration.cs
- HttpListenerRequestUriBuilder.cs
- SmtpFailedRecipientException.cs
- Missing.cs
- TrustSection.cs
- Dynamic.cs
- DrawingVisualDrawingContext.cs
- InputLangChangeEvent.cs
- TreeView.cs
- HTTPNotFoundHandler.cs
- ConstraintEnumerator.cs
- WebPartCatalogCloseVerb.cs
- RawStylusInputCustomDataList.cs
- CancelEventArgs.cs
- _ServiceNameStore.cs
- CacheEntry.cs
- ComboBox.cs
- XmlLangPropertyAttribute.cs
- GacUtil.cs
- WebPartExportVerb.cs
- TransformationRules.cs
- shaperfactory.cs
- InnerItemCollectionView.cs
- CookielessHelper.cs
- UrlMapping.cs
- HttpResponseHeader.cs
- CollectionViewGroup.cs
- SpellerError.cs
- wgx_exports.cs
- __TransparentProxy.cs
- AnyAllSearchOperator.cs
- Expander.cs
- MenuCommands.cs
- PingOptions.cs
- AutoResizedEvent.cs
- AttributeProviderAttribute.cs
- Form.cs
- DrawingGroupDrawingContext.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- ColorConvertedBitmap.cs
- Pair.cs
- MobileControlsSectionHandler.cs
- AttachedPropertyDescriptor.cs
- TreeNodeSelectionProcessor.cs
- XmlSchemaSimpleType.cs
- AutomationPatternInfo.cs
- Font.cs
- PrintSchema.cs
- WorkflowMessageEventArgs.cs
- IntegerCollectionEditor.cs
- MessageFilter.cs
- PopupRoot.cs
- TextBoxDesigner.cs
- XmlSerializerNamespaces.cs
- TargetParameterCountException.cs
- Util.cs
- securitycriticaldata.cs
- SystemWebExtensionsSectionGroup.cs
- QuaternionValueSerializer.cs
- WebPartExportVerb.cs
- SystemDiagnosticsSection.cs
- Int64Animation.cs
- ParameterCollectionEditor.cs
- TimerElapsedEvenArgs.cs
- BamlMapTable.cs
- TimeSpanSecondsOrInfiniteConverter.cs
- CollectionsUtil.cs
- MetadataPropertyAttribute.cs
- SqlTrackingQuery.cs
- FontResourceCache.cs
- MaskedTextBoxTextEditorDropDown.cs
- CompilerResults.cs
- RequestNavigateEventArgs.cs
- controlskin.cs
- BuildProvider.cs
- BooleanStorage.cs
- Assert.cs
- DataContractJsonSerializerOperationBehavior.cs
- RenderDataDrawingContext.cs
- Style.cs
- ManifestResourceInfo.cs
- SiteIdentityPermission.cs
- HandlerFactoryCache.cs
- LogicalExpr.cs
- WebPartZoneCollection.cs
- SmtpFailedRecipientException.cs
- SolidBrush.cs