Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlClientPermission.cs
- ToolStripItemRenderEventArgs.cs
- Vector3D.cs
- WebScriptServiceHostFactory.cs
- DataGridViewImageCell.cs
- SelectorAutomationPeer.cs
- EventManager.cs
- DataPointer.cs
- NameScopePropertyAttribute.cs
- PersonalizationStateQuery.cs
- RelationshipSet.cs
- AutomationElementIdentifiers.cs
- DataGridRowsPresenter.cs
- PageAsyncTask.cs
- XmlSerializerImportOptions.cs
- Grammar.cs
- RootNamespaceAttribute.cs
- MetadataItemEmitter.cs
- Classification.cs
- JsonCollectionDataContract.cs
- IsolatedStorageFilePermission.cs
- Module.cs
- TabControlEvent.cs
- MoveSizeWinEventHandler.cs
- webeventbuffer.cs
- TextWriterEngine.cs
- DurationConverter.cs
- UidManager.cs
- UriExt.cs
- regiisutil.cs
- dtdvalidator.cs
- HttpContextServiceHost.cs
- OperatingSystemVersionCheck.cs
- EventWaitHandleSecurity.cs
- DocumentViewer.cs
- ContractMapping.cs
- HelpProvider.cs
- XhtmlBasicLabelAdapter.cs
- FileDialog_Vista_Interop.cs
- EncoderReplacementFallback.cs
- CompositeScriptReference.cs
- BindingNavigator.cs
- RoleServiceManager.cs
- ContractCodeDomInfo.cs
- Calendar.cs
- InvokeProviderWrapper.cs
- WebPartUserCapability.cs
- PolyQuadraticBezierSegment.cs
- QuotedPairReader.cs
- ComponentResourceManager.cs
- infer.cs
- XmlSchemaChoice.cs
- ColorMatrix.cs
- ParameterReplacerVisitor.cs
- RequestDescription.cs
- ConfigXmlSignificantWhitespace.cs
- BoundColumn.cs
- BlurBitmapEffect.cs
- RoleServiceManager.cs
- TextTreeRootTextBlock.cs
- PropertyBuilder.cs
- SamlEvidence.cs
- CompilerTypeWithParams.cs
- InputScopeAttribute.cs
- DbConnectionInternal.cs
- ComplexTypeEmitter.cs
- DecoratedNameAttribute.cs
- ToolStripDropDownItem.cs
- WithParamAction.cs
- FixedSOMLineCollection.cs
- SimpleFieldTemplateUserControl.cs
- TransformCollection.cs
- OracleDateTime.cs
- UniqueIdentifierService.cs
- DefaultPrintController.cs
- ManagementInstaller.cs
- XsltConvert.cs
- ForeignKeyConstraint.cs
- CurrentChangedEventManager.cs
- CookieProtection.cs
- DigestTraceRecordHelper.cs
- TouchPoint.cs
- LogConverter.cs
- PointAnimationBase.cs
- SolidColorBrush.cs
- BordersPage.cs
- WebPartEditorCancelVerb.cs
- BitmapEffectOutputConnector.cs
- SqlDelegatedTransaction.cs
- FactoryRecord.cs
- XmlHierarchicalDataSourceView.cs
- Parser.cs
- ContainerControl.cs
- AddInProcess.cs
- StyleSelector.cs
- Resources.Designer.cs
- Compiler.cs
- XmlBinaryReader.cs
- DataViewSetting.cs
- Cast.cs