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
- MsmqIntegrationBindingCollectionElement.cs
- StreamingContext.cs
- BamlReader.cs
- SizeChangedEventArgs.cs
- MaterializeFromAtom.cs
- AppDomainUnloadedException.cs
- StickyNoteContentControl.cs
- XmlILAnnotation.cs
- ReadOnlyAttribute.cs
- Window.cs
- ItemCollection.cs
- KeyedQueue.cs
- BindingFormattingDialog.cs
- cache.cs
- SchemaImporterExtensionsSection.cs
- Vector3dCollection.cs
- Currency.cs
- TextRange.cs
- DispatcherTimer.cs
- MappingSource.cs
- TabControlAutomationPeer.cs
- GreenMethods.cs
- CacheSection.cs
- NativeRecognizer.cs
- CrossAppDomainChannel.cs
- XmlEncodedRawTextWriter.cs
- DoubleAnimationUsingKeyFrames.cs
- DataGridViewComboBoxColumnDesigner.cs
- TypeDescriptorFilterService.cs
- FontEmbeddingManager.cs
- CorrelationKey.cs
- WebMessageFormatHelper.cs
- DataServiceKeyAttribute.cs
- WinEventTracker.cs
- RelationshipNavigation.cs
- TextChangedEventArgs.cs
- WebAdminConfigurationHelper.cs
- PageThemeBuildProvider.cs
- XmlNamespaceMappingCollection.cs
- ButtonBase.cs
- QilPatternFactory.cs
- FormViewPagerRow.cs
- FormViewDesigner.cs
- CancelEventArgs.cs
- ApplyTemplatesAction.cs
- TableLayoutSettings.cs
- DataGridViewRowHeightInfoNeededEventArgs.cs
- IteratorDescriptor.cs
- isolationinterop.cs
- MatrixConverter.cs
- WebConvert.cs
- ComplusEndpointConfigContainer.cs
- SqlCacheDependencyDatabaseCollection.cs
- ParagraphResult.cs
- XpsColorContext.cs
- WebBrowserNavigatingEventHandler.cs
- HttpDebugHandler.cs
- ClientType.cs
- ProtocolsSection.cs
- DataGridViewColumn.cs
- Int64Animation.cs
- SHA512Managed.cs
- Parser.cs
- ScrollBarAutomationPeer.cs
- _ServiceNameStore.cs
- FlowDocumentReaderAutomationPeer.cs
- TextTreeRootNode.cs
- XPathNodeIterator.cs
- MetadataArtifactLoaderFile.cs
- TypeDelegator.cs
- ChameleonKey.cs
- XmlSignificantWhitespace.cs
- ListViewCancelEventArgs.cs
- LineGeometry.cs
- JumpList.cs
- EasingQuaternionKeyFrame.cs
- TextEditorContextMenu.cs
- JsonWriter.cs
- ScrollChrome.cs
- XPathDocumentIterator.cs
- RemoteCryptoRsaServiceProvider.cs
- LayoutEditorPart.cs
- SystemFonts.cs
- PeerObject.cs
- TreeNodeBindingCollection.cs
- MessageAction.cs
- SingleAnimationBase.cs
- DesignTimeValidationFeature.cs
- DeferredTextReference.cs
- BitmapScalingModeValidation.cs
- EventToken.cs
- ScrollItemProviderWrapper.cs
- EntitySqlQueryCacheKey.cs
- ConfigurationPropertyCollection.cs
- FileLevelControlBuilderAttribute.cs
- SqlWebEventProvider.cs
- Renderer.cs
- TCPClient.cs
- Stylesheet.cs
- DispatchChannelSink.cs