Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Misc / GDI / WindowsGraphicsCacheManager.cs / 1305376 / WindowsGraphicsCacheManager.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- #if WGCM_TEST_SUITE // Enable tracking when built for the test suites. #define TRACK_HDC #define GDI_FONT_CACHE_TRACK #endif #if [....]_NAMESPACE namespace System.Windows.Forms.Internal #elif DRAWING_NAMESPACE namespace System.Drawing.Internal #else namespace System.Experimental.Gdi #endif { using System; using System.Collections.Generic; using System.Internal; using System.Diagnostics; using System.Drawing; using System.Threading; using Microsoft.Win32; using System.Runtime.Versioning; ////// Keeps a cache of some graphics primitives. /// Created to improve performance of TextRenderer.MeasureText methods that don't receive a WindowsGraphics. /// This class mantains a cache of MRU WindowsFont objects in the process. (See VSWhidbey#301492). /// #if [....]_PUBLIC_GRAPHICS_LIBRARY public #else internal #endif class WindowsGraphicsCacheManager { // From MSDN: Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization occurs only once, // when the class constructor executes, and therefore affects only one thread. // WindowsGraphics object used for measuring text based on the screen DC. TLS to avoid synchronization issues. [ThreadStatic] private static WindowsGraphics measurementGraphics; // Circular list implementing the WindowsFont per-process cache. private const int CacheSize = 10; [ThreadStatic] private static int currentIndex; [ThreadStatic] private static List> windowsFontCache; /// /// Static constructor since this is a utility class. /// static WindowsGraphicsCacheManager() { // } ////// Class is never instantiated, private constructor prevents the compiler from generating a default constructor. /// private WindowsGraphicsCacheManager() { } ////// Initializes the WindowsFontCache object. /// private static List> WindowsFontCache { get { if (windowsFontCache == null) { currentIndex = -1; windowsFontCache = new List >(CacheSize); } return windowsFontCache; } } /// /// Get the cached screen (primary monitor) memory dc. /// Users of this class should always use this property to get the WindowsGraphics and never cache it, it could be mistakenly /// disposed and we would recreate it if needed. /// Users should not dispose of the WindowsGraphics so it can be reused for the lifetime of the thread. /// public static WindowsGraphics MeasurementGraphics { [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { if (measurementGraphics == null || measurementGraphics.DeviceContext == null /*object disposed*/) { Debug.Assert( measurementGraphics == null || measurementGraphics.DeviceContext != null, "TLS MeasurementGraphics was disposed somewhere, enable TRACK_HDC macro to determine who did it, recreating it for now ..." ); #if TRACK_HDC //Debug.WriteLine( DbgUtil.StackTraceToStr(string.Format("Initializing MeasurementGraphics for thread: [0x{0:x8}]", Thread.CurrentThread.ManagedThreadId))); Debug.WriteLine( DbgUtil.StackTraceToStr("Initializing MeasurementGraphics")); #endif measurementGraphics = WindowsGraphics.CreateMeasurementWindowsGraphics(); } return measurementGraphics; } } #if OPTIMIZED_MEASUREMENTDC // in some cases, we dont want to demand create MeasurementGraphics, as creating it has // re-entrant side effects. internal static WindowsGraphics GetCurrentMeasurementGraphics() { return measurementGraphics; } #endif ////// Get the cached WindowsFont associated with the specified font if one exists, otherwise create one and /// add it to the cache. /// [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static WindowsFont GetWindowsFont(Font font) { return GetWindowsFont(font, WindowsFontQuality.Default); } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static WindowsFont GetWindowsFont(Font font, WindowsFontQuality fontQuality) { if( font == null ) { return null; } // First check if font is in the cache. int count = 0; int index = currentIndex; // Search by index of most recently added object. while( count < WindowsFontCache.Count ) { if (WindowsFontCache[index].Key.Equals(font)) // don't do shallow comparison, we could miss cloned fonts. { // We got a Font in the cache, let's see if we have a WindowsFont with the same quality as required by the caller. // WARNING: It is not expected that the WindowsFont is disposed externally since it is created by this class. Debug.Assert(WindowsFontCache[index].Value.Hfont != IntPtr.Zero, "Cached WindowsFont was disposed, enable GDI_FINALIZATION_WATCH to track who did it!"); WindowsFont wf = WindowsFontCache[index].Value; if(wf.Quality == fontQuality) { return wf; } } index--; count++; if( index < 0 ) { index = CacheSize - 1; } } // Font is not in the cache, let's add it. WindowsFont winFont = WindowsFont.FromFont(font, fontQuality); KeyValuePair newEntry = new KeyValuePair(font, winFont); currentIndex++; if (currentIndex == CacheSize) { currentIndex = 0; } if (WindowsFontCache.Count == CacheSize) // No more room, update current index. { WindowsFont wfont = null; // Go through the existing fonts in the cache, and see if any // are not in use by a DC. If one isn't, replace that. If // all are in use, new up a new font and do not cache it. bool finished = false; int startIndex = currentIndex; int loopIndex = startIndex + 1; while (!finished) { if (loopIndex >= CacheSize) { loopIndex = 0; } if (loopIndex == startIndex) { finished = true; } wfont = WindowsFontCache[loopIndex].Value; if (!DeviceContexts.IsFontInUse(wfont)) { currentIndex = loopIndex; finished = true; break; } else { loopIndex++; wfont = null; } } if (wfont != null) { WindowsFontCache[currentIndex] = newEntry; winFont.OwnedByCacheManager = true; #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Removing from cache: " + wfont); Debug.WriteLine( "Adding to cache: " + winFont ); #endif wfont.OwnedByCacheManager = false; wfont.Dispose(); } else { // do not cache font - caller is ALWAYS responsible for // disposing now. If it is owned by the CM, it will not // disposed. winFont.OwnedByCacheManager = false; #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Creating uncached font: " + winFont); #endif } } else { winFont.OwnedByCacheManager = true; WindowsFontCache.Add(newEntry); #if GDI_FONT_CACHE_TRACK Debug.WriteLine( "Adding to cache: " + winFont ); #endif } return winFont; } #if [....]_PUBLIC_GRAPHICS_LIBRARY /// The following methods are not needed in production code since the cached objects are meant to be reused and should not be explicitly disposed, /// left here for testing purposes. ////// public static void Reset() { ResetFontCache(); ResetMeasurementGraphics(); } ////// Dispose of all cached WindowsFont objects and reset the collection. /// public static void ResetFontCache() { if( WindowsFontCache.Count > 0 ) { for(int index = 0; index < WindowsFontCache.Count; index++ ) { WindowsFontCache[index].Value.Dispose(); } WindowsFontCache.Clear(); currentIndex = -1; #if GDI_FONT_CACHE_TRACK Debug.WriteLine( "Font cache reset. Count: " + WindowsFontCache.Count ); #endif } } ////// Dispose of cached memory dc. /// public static void ResetMeasurementGraphics() { if( measurementGraphics != null ) { #if TRACK_HDC //Debug.WriteLine( DbgUtil.StackTraceToStr(string.Format("Disposing measurement DC and WG for thread: [0x{0:x8}]", Thread.CurrentThread.ManagedThreadId))); Debug.WriteLine( DbgUtil.StackTraceToStr("Disposing measurement DC and WG")); #endif measurementGraphics.Dispose(); measurementGraphics = null; } } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- #if WGCM_TEST_SUITE // Enable tracking when built for the test suites. #define TRACK_HDC #define GDI_FONT_CACHE_TRACK #endif #if [....]_NAMESPACE namespace System.Windows.Forms.Internal #elif DRAWING_NAMESPACE namespace System.Drawing.Internal #else namespace System.Experimental.Gdi #endif { using System; using System.Collections.Generic; using System.Internal; using System.Diagnostics; using System.Drawing; using System.Threading; using Microsoft.Win32; using System.Runtime.Versioning; ////// Keeps a cache of some graphics primitives. /// Created to improve performance of TextRenderer.MeasureText methods that don't receive a WindowsGraphics. /// This class mantains a cache of MRU WindowsFont objects in the process. (See VSWhidbey#301492). /// #if [....]_PUBLIC_GRAPHICS_LIBRARY public #else internal #endif class WindowsGraphicsCacheManager { // From MSDN: Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization occurs only once, // when the class constructor executes, and therefore affects only one thread. // WindowsGraphics object used for measuring text based on the screen DC. TLS to avoid synchronization issues. [ThreadStatic] private static WindowsGraphics measurementGraphics; // Circular list implementing the WindowsFont per-process cache. private const int CacheSize = 10; [ThreadStatic] private static int currentIndex; [ThreadStatic] private static List> windowsFontCache; /// /// Static constructor since this is a utility class. /// static WindowsGraphicsCacheManager() { // } ////// Class is never instantiated, private constructor prevents the compiler from generating a default constructor. /// private WindowsGraphicsCacheManager() { } ////// Initializes the WindowsFontCache object. /// private static List> WindowsFontCache { get { if (windowsFontCache == null) { currentIndex = -1; windowsFontCache = new List >(CacheSize); } return windowsFontCache; } } /// /// Get the cached screen (primary monitor) memory dc. /// Users of this class should always use this property to get the WindowsGraphics and never cache it, it could be mistakenly /// disposed and we would recreate it if needed. /// Users should not dispose of the WindowsGraphics so it can be reused for the lifetime of the thread. /// public static WindowsGraphics MeasurementGraphics { [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { if (measurementGraphics == null || measurementGraphics.DeviceContext == null /*object disposed*/) { Debug.Assert( measurementGraphics == null || measurementGraphics.DeviceContext != null, "TLS MeasurementGraphics was disposed somewhere, enable TRACK_HDC macro to determine who did it, recreating it for now ..." ); #if TRACK_HDC //Debug.WriteLine( DbgUtil.StackTraceToStr(string.Format("Initializing MeasurementGraphics for thread: [0x{0:x8}]", Thread.CurrentThread.ManagedThreadId))); Debug.WriteLine( DbgUtil.StackTraceToStr("Initializing MeasurementGraphics")); #endif measurementGraphics = WindowsGraphics.CreateMeasurementWindowsGraphics(); } return measurementGraphics; } } #if OPTIMIZED_MEASUREMENTDC // in some cases, we dont want to demand create MeasurementGraphics, as creating it has // re-entrant side effects. internal static WindowsGraphics GetCurrentMeasurementGraphics() { return measurementGraphics; } #endif ////// Get the cached WindowsFont associated with the specified font if one exists, otherwise create one and /// add it to the cache. /// [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static WindowsFont GetWindowsFont(Font font) { return GetWindowsFont(font, WindowsFontQuality.Default); } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static WindowsFont GetWindowsFont(Font font, WindowsFontQuality fontQuality) { if( font == null ) { return null; } // First check if font is in the cache. int count = 0; int index = currentIndex; // Search by index of most recently added object. while( count < WindowsFontCache.Count ) { if (WindowsFontCache[index].Key.Equals(font)) // don't do shallow comparison, we could miss cloned fonts. { // We got a Font in the cache, let's see if we have a WindowsFont with the same quality as required by the caller. // WARNING: It is not expected that the WindowsFont is disposed externally since it is created by this class. Debug.Assert(WindowsFontCache[index].Value.Hfont != IntPtr.Zero, "Cached WindowsFont was disposed, enable GDI_FINALIZATION_WATCH to track who did it!"); WindowsFont wf = WindowsFontCache[index].Value; if(wf.Quality == fontQuality) { return wf; } } index--; count++; if( index < 0 ) { index = CacheSize - 1; } } // Font is not in the cache, let's add it. WindowsFont winFont = WindowsFont.FromFont(font, fontQuality); KeyValuePair newEntry = new KeyValuePair(font, winFont); currentIndex++; if (currentIndex == CacheSize) { currentIndex = 0; } if (WindowsFontCache.Count == CacheSize) // No more room, update current index. { WindowsFont wfont = null; // Go through the existing fonts in the cache, and see if any // are not in use by a DC. If one isn't, replace that. If // all are in use, new up a new font and do not cache it. bool finished = false; int startIndex = currentIndex; int loopIndex = startIndex + 1; while (!finished) { if (loopIndex >= CacheSize) { loopIndex = 0; } if (loopIndex == startIndex) { finished = true; } wfont = WindowsFontCache[loopIndex].Value; if (!DeviceContexts.IsFontInUse(wfont)) { currentIndex = loopIndex; finished = true; break; } else { loopIndex++; wfont = null; } } if (wfont != null) { WindowsFontCache[currentIndex] = newEntry; winFont.OwnedByCacheManager = true; #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Removing from cache: " + wfont); Debug.WriteLine( "Adding to cache: " + winFont ); #endif wfont.OwnedByCacheManager = false; wfont.Dispose(); } else { // do not cache font - caller is ALWAYS responsible for // disposing now. If it is owned by the CM, it will not // disposed. winFont.OwnedByCacheManager = false; #if GDI_FONT_CACHE_TRACK Debug.WriteLine("Creating uncached font: " + winFont); #endif } } else { winFont.OwnedByCacheManager = true; WindowsFontCache.Add(newEntry); #if GDI_FONT_CACHE_TRACK Debug.WriteLine( "Adding to cache: " + winFont ); #endif } return winFont; } #if [....]_PUBLIC_GRAPHICS_LIBRARY /// The following methods are not needed in production code since the cached objects are meant to be reused and should not be explicitly disposed, /// left here for testing purposes. ////// public static void Reset() { ResetFontCache(); ResetMeasurementGraphics(); } ////// Dispose of all cached WindowsFont objects and reset the collection. /// public static void ResetFontCache() { if( WindowsFontCache.Count > 0 ) { for(int index = 0; index < WindowsFontCache.Count; index++ ) { WindowsFontCache[index].Value.Dispose(); } WindowsFontCache.Clear(); currentIndex = -1; #if GDI_FONT_CACHE_TRACK Debug.WriteLine( "Font cache reset. Count: " + WindowsFontCache.Count ); #endif } } ////// Dispose of cached memory dc. /// public static void ResetMeasurementGraphics() { if( measurementGraphics != null ) { #if TRACK_HDC //Debug.WriteLine( DbgUtil.StackTraceToStr(string.Format("Disposing measurement DC and WG for thread: [0x{0:x8}]", Thread.CurrentThread.ManagedThreadId))); Debug.WriteLine( DbgUtil.StackTraceToStr("Disposing measurement DC and WG")); #endif measurementGraphics.Dispose(); measurementGraphics = null; } } #endif } } // 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
- EntityDataSourceUtil.cs
- CalendarButton.cs
- GroupBox.cs
- CollectionType.cs
- DiscoveryExceptionDictionary.cs
- IPeerNeighbor.cs
- RemoteWebConfigurationHost.cs
- SafeMILHandle.cs
- TouchesOverProperty.cs
- WebWorkflowRole.cs
- PeerReferralPolicy.cs
- autovalidator.cs
- TableCell.cs
- NullableDecimalSumAggregationOperator.cs
- PersonalizablePropertyEntry.cs
- DBSchemaRow.cs
- HwndKeyboardInputProvider.cs
- MarshalByRefObject.cs
- DispatcherTimer.cs
- SecurityException.cs
- PackWebResponse.cs
- DeviceContext2.cs
- BaseCAMarshaler.cs
- KeySpline.cs
- PageTrueTypeFont.cs
- PathTooLongException.cs
- EventItfInfo.cs
- WorkflowOwnershipException.cs
- CryptoConfig.cs
- KeyValueInternalCollection.cs
- CounterSampleCalculator.cs
- XamlToRtfWriter.cs
- EditorPartChrome.cs
- XmlNavigatorStack.cs
- ToolStripDropDownClosingEventArgs.cs
- TrackingWorkflowEventArgs.cs
- QilInvokeEarlyBound.cs
- FormatConvertedBitmap.cs
- _HeaderInfoTable.cs
- ZoneMembershipCondition.cs
- OracleTimeSpan.cs
- Empty.cs
- SchemaImporterExtension.cs
- SortedList.cs
- cookie.cs
- FunctionDetailsReader.cs
- User.cs
- JoinTreeNode.cs
- ContentFileHelper.cs
- XmlImplementation.cs
- ServiceEndpointElementCollection.cs
- ObjRef.cs
- ThreadAbortException.cs
- WebPartManager.cs
- PathFigureCollectionValueSerializer.cs
- TemplateKeyConverter.cs
- BindingMemberInfo.cs
- KeyedCollection.cs
- AddressAccessDeniedException.cs
- InkCanvasSelectionAdorner.cs
- MembershipPasswordException.cs
- RecognizerStateChangedEventArgs.cs
- DrawToolTipEventArgs.cs
- StorageComplexPropertyMapping.cs
- NegotiateStream.cs
- BlurBitmapEffect.cs
- XPathQilFactory.cs
- PeerApplication.cs
- ToolboxItemAttribute.cs
- StringReader.cs
- SoapConverter.cs
- SiteIdentityPermission.cs
- ListItemConverter.cs
- InfoCardProofToken.cs
- ScriptResourceInfo.cs
- RegexCompiler.cs
- SqlColumnizer.cs
- CroppedBitmap.cs
- DecimalConstantAttribute.cs
- AnonymousIdentificationSection.cs
- UInt16Converter.cs
- DefaultBinder.cs
- DataRowChangeEvent.cs
- PageEventArgs.cs
- Number.cs
- Paragraph.cs
- EdmValidator.cs
- WebPartMovingEventArgs.cs
- XmlUtilWriter.cs
- ExtensionFile.cs
- SegmentInfo.cs
- SiteMapHierarchicalDataSourceView.cs
- GlyphElement.cs
- DataBindingCollectionConverter.cs
- XamlDesignerSerializationManager.cs
- HtmlHead.cs
- MenuItemStyle.cs
- Attributes.cs
- FormViewModeEventArgs.cs
- CustomAttributeBuilder.cs