Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Misc / GDI / WindowsGraphicsCacheManager.cs / 1 / 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 WINFORMS_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;
///
/// 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 WINFORMS_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
{
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.
///
public static WindowsFont GetWindowsFont(Font font)
{
return GetWindowsFont(font, WindowsFontQuality.Default);
}
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 WINFORMS_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 WINFORMS_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;
///
/// 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 WINFORMS_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
{
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.
///
public static WindowsFont GetWindowsFont(Font font)
{
return GetWindowsFont(font, WindowsFontQuality.Default);
}
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 WINFORMS_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
- ToolboxItemLoader.cs
- PolicyStatement.cs
- ImagingCache.cs
- PointIndependentAnimationStorage.cs
- SimplePropertyEntry.cs
- PropertyPushdownHelper.cs
- DiscoveryClientDuplexChannel.cs
- DoubleCollection.cs
- OlePropertyStructs.cs
- FrameworkContentElement.cs
- DataGridViewButtonColumn.cs
- Menu.cs
- XPathScanner.cs
- Size.cs
- updateconfighost.cs
- RangeBaseAutomationPeer.cs
- FolderLevelBuildProviderAppliesToAttribute.cs
- UrlPath.cs
- RouteUrlExpressionBuilder.cs
- PointAnimationBase.cs
- TableLayout.cs
- TextElement.cs
- SqlUtil.cs
- Manipulation.cs
- StreamingContext.cs
- ErrorEventArgs.cs
- OSFeature.cs
- WebControlsSection.cs
- ZipIOBlockManager.cs
- FontUnitConverter.cs
- CheckBoxAutomationPeer.cs
- StylusButton.cs
- ReflectionPermission.cs
- TypeUsage.cs
- RemoteWebConfigurationHostServer.cs
- MethodSignatureGenerator.cs
- PointIndependentAnimationStorage.cs
- ToolStripOverflow.cs
- ApplicationInfo.cs
- CodeDomDesignerLoader.cs
- UInt32.cs
- loginstatus.cs
- TileBrush.cs
- ListMarkerLine.cs
- AuthorizationRule.cs
- XpsPackagingException.cs
- StyleCollectionEditor.cs
- DataContractSet.cs
- SoapAttributeAttribute.cs
- BasicExpressionVisitor.cs
- PropertyDescriptorCollection.cs
- ByteAnimationUsingKeyFrames.cs
- NotifyParentPropertyAttribute.cs
- _LazyAsyncResult.cs
- SocketElement.cs
- TextLineResult.cs
- Root.cs
- WinFormsSecurity.cs
- CatalogPart.cs
- ContentElementAutomationPeer.cs
- PropertyEntry.cs
- ManipulationDeltaEventArgs.cs
- Msmq4SubqueuePoisonHandler.cs
- ResourceExpressionBuilder.cs
- ItemChangedEventArgs.cs
- CursorConverter.cs
- ModelVisual3D.cs
- KeyGestureConverter.cs
- DataObjectSettingDataEventArgs.cs
- AmbiguousMatchException.cs
- DesignOnlyAttribute.cs
- TransactionChannelFaultConverter.cs
- FrameworkTemplate.cs
- FlowDocumentPaginator.cs
- WindowsGraphics2.cs
- SQLRoleProvider.cs
- DBSchemaTable.cs
- PtsCache.cs
- Visual3D.cs
- ExponentialEase.cs
- BitmapSizeOptions.cs
- AnimationLayer.cs
- RequestCachingSection.cs
- View.cs
- ContractMethodParameterInfo.cs
- ETagAttribute.cs
- BaseTemplateBuildProvider.cs
- clipboard.cs
- _IPv4Address.cs
- DefaultTextStore.cs
- XmlNodeChangedEventArgs.cs
- NativeCompoundFileAPIs.cs
- SuppressMessageAttribute.cs
- StaticResourceExtension.cs
- SrgsRulesCollection.cs
- PerformanceCounterPermission.cs
- SoapIgnoreAttribute.cs
- Timeline.cs
- CopyAction.cs
- HandleExceptionArgs.cs