/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ /////////////////////////////////////////////////////////////////////////////// // // // plWinFontCache Class Header // // I've stopped keeping track, there are far too many reasons already to // // hate Microsoft. Anyway, this class keeps track of various Win32 fonts we // // allocate because Win98/ME seems to have problems re-allocating the exact // // same freaking goddamn font over and over again. I mean, you'd think // // there'd be a rule somewhere about deterministic behavior when calling // // the exact same function with the exact same parameters over and over... // // Oh, wait... // // // // Cyan, Inc. // // // //// Version History ////////////////////////////////////////////////////////// // // // 11.25.2002 mcn - Created. // // // /////////////////////////////////////////////////////////////////////////////// #include "hsTypes.h" #include "hsWindows.h" #include "plWinFontCache.h" #include "plStatusLog/plStatusLog.h" #include "plFile/hsFiles.h" #include "plGImage/plDynSurfaceWriter.h" #if HS_BUILD_FOR_WIN32 #include const char* plWinFontCache::kCustFontExtension = ".prf"; plWinFontCache::plWinFontCache() { fInShutdown = false; fCustFontDir = nil; } plWinFontCache::~plWinFontCache() { fInShutdown = true; Clear(); delete [] fCustFontDir; } plWinFontCache &plWinFontCache::GetInstance( void ) { static plWinFontCache cache; return cache; } HFONT plWinFontCache::IFindFont( const char *face, int height, int weight, hsBool italic, UInt32 quality ) { int i; for( i = 0; i < fFontCache.GetCount(); i++ ) { // Do other tests first, since they're cheaper if( fFontCache[ i ].fHeight == height && fFontCache[ i ].fWeight == weight && fFontCache[ i ].fItalic == italic && fFontCache[ i ].fQuality == quality ) { if( strcmp( fFontCache[ i ].fFace, face ) == 0 ) return fFontCache[ i ].fFont; } } return nil; } HFONT plWinFontCache::IMakeFont( const char *face, int height, int weight, hsBool italic, UInt32 quality ) { plFontRecord myRec; int i; // Find a cached name for us for( i = 0; i < fFontNameCache.GetCount(); i++ ) { if( strcmp( face, fFontNameCache[ i ] ) == 0 ) break; } if( i == fFontNameCache.GetCount() ) fFontNameCache.Append( hsStrcpy( face ) ); myRec.fFace = fFontNameCache[ i ]; myRec.fHeight = height; myRec.fWeight = weight; myRec.fItalic = italic; myRec.fQuality = quality; myRec.fFont = CreateFont( height, 0, 0, 0, weight, italic ? TRUE : FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, face ); if( myRec.fFont != nil ) { //#ifdef HS_DEBUGGING #if 1 LOGFONT fontInfo; if( GetObject( myRec.fFont, sizeof( fontInfo ), &fontInfo ) ) { const char *err = nil; if( fontInfo.lfQuality != quality ) err = "Quality of created font does not match"; if( fontInfo.lfHeight != height ) err = "Height of created font does not match"; if( fontInfo.lfWeight != weight ) err = "Weight of created font does not match"; if( fontInfo.lfItalic != italic ) err = "Italic-ness of created font does not match"; if( stricmp( fontInfo.lfFaceName, face ) != 0 ) err = "Face of created font does not match"; if( err != nil ) { static bool triedClearing = false; if( fontInfo.lfQuality != quality ) { plStatusLog::AddLineS( "pipeline.log", "ERROR: CreateFont() failed to return proper font (%s). Using what was given...", err ); } else { plStatusLog::AddLineS( "pipeline.log", "ERROR: CreateFont() failed to return proper font (%s). %s", err, triedClearing ? "" : "Clearing cache and retrying..." ); if( !triedClearing ) { triedClearing = true; // Didn't work, so get rid of it DeleteObject( myRec.fFont ); // Clear all fonts and try again Clear(); // Make sure we reload our custom fonts tho ILoadCustomFonts(); // Try again HFONT font = IMakeFont( face, height, weight, italic, quality ); triedClearing = false; return font; } } } } #endif fFontCache.Append( myRec ); } else { plStatusLog::AddLineS( "pipeline.log", "ERROR: CreateFont() call FAILED (face: %s, size: %d %s %s)", face, -height, weight == FW_BOLD ? "bold" : "", italic ? "italic" : "" ); } return myRec.fFont; } HFONT plWinFontCache::GetMeAFont( const char *face, int height, int weight, hsBool italic, UInt32 quality ) { HFONT font = IFindFont( face, height, weight, italic, quality ); if( font == nil ) font = IMakeFont( face, height, weight, italic, quality ); return font; } void plWinFontCache::Clear( void ) { int i; if( !fInShutdown ) plStatusLog::AddLineS( "pipeline.log", "** Clearing Win32 font cache **" ); for( i = 0; i < fFontCache.GetCount(); i++ ) DeleteObject( fFontCache[ i ].fFont ); fFontCache.Reset(); for( i = 0; i < fFontNameCache.GetCount(); i++ ) delete [] fFontNameCache[ i ]; fFontNameCache.Reset(); for( i = 0; i < fCustFonts.GetCount(); i++ ) { #if (_WIN32_WINNT >= 0x0500) if( plDynSurfaceWriter::CanHandleLotsOfThem() ) RemoveFontResourceEx( fCustFonts[ i ]->fFilename, FR_PRIVATE, 0 ); else #endif if( RemoveFontResource( fCustFonts[ i ]->fFilename ) == 0 ) { int q= 0; DWORD e = GetLastError(); } delete fCustFonts[ i ]; } fCustFonts.Reset(); } void plWinFontCache::FreeFont( HFONT font ) { // Currently a no-op, but should do some sort of ref-counting } void plWinFontCache::LoadCustomFonts( const char *dir ) { delete [] fCustFontDir; fCustFontDir = ( dir != nil ) ? hsStrcpy( dir ) : nil; ILoadCustomFonts(); } void plWinFontCache::ILoadCustomFonts( void ) { if( fCustFontDir == nil ) return; // Iterate through all the custom fonts in our dir hsFolderIterator iter( fCustFontDir ); char fileName[ kFolderIterator_MaxPath ]; int numAdded; while( iter.NextFileSuffix( kCustFontExtension ) ) { iter.GetPathAndName( fileName ); // Note that this call can be translated as "does my OS suck?" #if (_WIN32_WINNT >= 0x0500) if( plDynSurfaceWriter::CanHandleLotsOfThem() ) numAdded = AddFontResourceEx( fileName, FR_PRIVATE, 0 ); else #endif numAdded = AddFontResource( fileName ); if( numAdded > 0 ) { plStatusLog::AddLineS( "pipeline.log", "WinFontCache: Added custom font %s, %d fonts", fileName, numAdded ); fCustFonts.Append( TRACKED_NEW plCustFont( fileName ) ); } else { plStatusLog::AddLineS( "pipeline.log", "WinFontCache: Unable to load custom font %s", fileName ); } } } #endif