Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / FontFace / FontFamilyIdentifier.cs / 1305600 / FontFamilyIdentifier.cs
//---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // Description: FontFamilyIdentifier type // // History: // 5/6/2005 : niklasb - 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- StringResourceManager.cs
- SyndicationItem.cs
- _LocalDataStore.cs
- EntityException.cs
- JavaScriptSerializer.cs
- SQLMembershipProvider.cs
- GridViewCellAutomationPeer.cs
- UInt32Converter.cs
- UInt32.cs
- SplineKeyFrames.cs
- Maps.cs
- SymbolResolver.cs
- NullableFloatAverageAggregationOperator.cs
- XamlPathDataSerializer.cs
- panel.cs
- FormattedTextSymbols.cs
- StringFormat.cs
- ComponentCommands.cs
- Hash.cs
- ViewKeyConstraint.cs
- FreeFormDragDropManager.cs
- EntryWrittenEventArgs.cs
- Cursor.cs
- XmlQueryStaticData.cs
- ContractMapping.cs
- HebrewCalendar.cs
- Drawing.cs
- Stylesheet.cs
- SQLDateTime.cs
- OleAutBinder.cs
- CompoundFileReference.cs
- CqlGenerator.cs
- XmlSchemaParticle.cs
- PixelFormatConverter.cs
- WinEventTracker.cs
- BoolExpr.cs
- CapabilitiesAssignment.cs
- RegexCapture.cs
- FlowNode.cs
- Serialization.cs
- EnumType.cs
- Speller.cs
- XmlSerializerFactory.cs
- AvTrace.cs
- WebPartHelpVerb.cs
- PartialCachingAttribute.cs
- AssemblyCache.cs
- IdentityValidationException.cs
- KeyManager.cs
- HashStream.cs
- SrgsElement.cs
- GenericIdentity.cs
- UiaCoreTypesApi.cs
- returneventsaver.cs
- DataGridViewCellEventArgs.cs
- QueryPrefixOp.cs
- WmiInstallComponent.cs
- EventBookmark.cs
- ProfileSection.cs
- SqlUDTStorage.cs
- SessionStateUtil.cs
- TransformerTypeCollection.cs
- TextDecorationUnitValidation.cs
- PropertyMetadata.cs
- CollectionChange.cs
- ImageMap.cs
- StylusPointProperties.cs
- PropertyStore.cs
- ParseChildrenAsPropertiesAttribute.cs
- RelationshipDetailsCollection.cs
- QuaternionAnimation.cs
- MultiPartWriter.cs
- XmlSchemaComplexType.cs
- BitmapMetadataBlob.cs
- WebPartZoneBase.cs
- InstanceHandleReference.cs
- WinEventWrap.cs
- ProviderException.cs
- HandleCollector.cs
- PageThemeCodeDomTreeGenerator.cs
- ApplicationServiceManager.cs
- TextFormatterImp.cs
- CancellationHandlerDesigner.cs
- odbcmetadatafactory.cs
- ComboBox.cs
- RegexMatchCollection.cs
- DynamicFilter.cs
- XamlToRtfWriter.cs
- HtmlPanelAdapter.cs
- BitmapFrameEncode.cs
- OpCodes.cs
- DataStreams.cs
- CodeIdentifier.cs
- SqlRowUpdatingEvent.cs
- BooleanConverter.cs
- WebBrowserBase.cs
- TypeReference.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- Figure.cs
- ProcessThreadCollection.cs