📄 font.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* @doc INTERNAL
*
* @module FONT.C -- font cache |
*
* includes font cache, char width cache;
* create logical font if not in cache, look up
* character widths on an as needed basis (this
* has been abstracted away into a separate class
* so that different char width caching algos can
* be tried.) <nl>
*
* Owner: <nl>
* David R. Fulmer <nl>
* Christian Fortini <nl>
* Jon Matousek <nl>
*
* History: <nl>
* 7/26/95 jonmat cleanup and reorganization, factored out
* char width caching code into a separate class.
*
*/
#include "_common.h"
#include "_font.h"
#include "_rtfconv.h" // Needed for GetCodePage
#include <intsafe.h>
#define CLIP_DFA_OVERRIDE 0x40 // Used to disable Korea & Taiwan font association
ASSERTDATA
// corresponds to yHeightCharPtsMost in richedit.h
#define yHeightCharMost 32760
// NOTE: this is global across all instances in the same process.
static CFontCache *__fc;
WCHAR lfJapaneseFaceName[LF_FACESIZE];
WCHAR lfHangulFaceName[LF_FACESIZE];
WCHAR lfBig5FaceName[LF_FACESIZE];
WCHAR lfGB2312FaceName[LF_FACESIZE];
/*
* InitFontCache ()
*
* @mfunc
* Initializes font cache.
*
* @devnote
* This is exists so reinit.cpp doesn't have to know all about the
* font cache.
*/
BOOL InitFontCache()
{
// GuyBark Jupiter: Beware of oom.
if(!(__fc = new CFontCache))
{
return FALSE;
}
__fc->Init();
return TRUE;
}
/*
* FreeFontCachet ()
*
* @mfunc
* Frees font cache.
*
* @devnote
* This is exists so reinit.cpp doesn't have to know all about the
* font cache.
*/
void FreeFontCache()
{
__fc->Free();
delete __fc;
__fc = NULL;
}
/*
* CFontCache & fc()
*
* @func
* initialize the global __fc.
* @comm
* current #defined to store 16 logical fonts and
* respective character widths.
*
*/
CFontCache & fc()
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "fc");
return *__fc;
}
// =================================== CFontCache ====================================
/*
* CFontCache::Init ()
*
* @mfunc
* Initializes font cache.
*
* @devnote
* This is not a constructor because something bad seems to happen
* if we try to contruct a global object.
*/
void CFontCache::Init ()
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::CFontCache");
_dwAgeNext = 0;
}
/*
* CFontCache::Free ()
*
* @mfunc
* Frees resources attached to font cache.
*
* @devnote
* This is not a constructor because something bad seems to happen
* if we try to call a destructor on a global object.
*/
void CFontCache::Free ()
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::~CFontCache");
}
/*
* CCcs* CFontCache::GetCcs(hdc, pcf, lZoomNumerator, lZoomDenominator, yPixelsPerInch)
*
* @mfunc
* Search the font cache for a matching logical font and return it.
* If a match is not found in the cache, create one.
*
* @rdesc
* A logical font matching the given CHARFORMAT info.
*/
CCcs* CFontCache::GetCcs(
HDC hdc, //@parm HDC into which font will be selected
const CCharFormat *const pcf, //@parm description of desired logical font
const LONG lZoomNumerator, //@parm Zoom numerator for getting display font
const LONG lZoomDenominator, //@parm Zoom denominator for getting
const LONG yPerInch) //@parm Y pixels per inch
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::GetCcs");
CLock lock;
// display font
const CCcs * const pccsMost = &_rgccs[cccsMost - 1];
CCcs * pccs;
LONG lfHeight;
BYTE bCrc;
SHORT hashKey;
// Duplicate the format structure because we might need to change some of the
// values by the zoom factor
// and in the case of sub superscript
CCharFormat cf = *pcf;
//FUTURE igorzv
//Take subscript size, subscript offset, superscript offset, superscript size
// from the OUTLINETEXMETRIC
// change cf.yHeight in the case of sub superscript
if (cf.dwEffects & (CFE_SUPERSCRIPT | CFE_SUBSCRIPT))
{
if (cf.dwEffects & CFE_SUBSCRIPT)
{
cf.yOffset-=cf.yHeight/5;
}
else
{
cf.yOffset += cf.yHeight/2;
}
cf.yHeight = 2*cf.yHeight/3;
}
// We only adjust the size if we need to.
if (lZoomNumerator != lZoomDenominator)
{
cf.yHeight = MulDiv(cf.yHeight, lZoomNumerator, lZoomDenominator);
cf.yOffset = MulDiv(cf.yOffset, lZoomNumerator, lZoomDenominator);
}
// calculate lfHeight used for Compare().
lfHeight = -MulDiv(cf.yHeight, yPerInch, LY_PER_INCH);
bCrc = cf.bCRC;
Assert(0 != bCrc); // Wasn't computed?
if(!lfHeight)
lfHeight--; // round error, make this a minimum legal height of -1.
// check our hash before going sequential.
hashKey = bCrc & QUICKCRCSEARCHSIZE;
if ( bCrc == quickCrcSearch[hashKey].bCrc )
{
pccs = quickCrcSearch[hashKey].pccs;
if(pccs && pccs->_bCrc == bCrc && pccs->_fValid )
{
if(pccs->Compare( &cf, lfHeight ))
{
goto matched;
}
}
}
quickCrcSearch[hashKey].bCrc = bCrc;
// squentially search ccs for same character format
for(pccs = &_rgccs[0]; pccs <= pccsMost; pccs++)
{
if( pccs->_bCrc == bCrc && pccs->_fValid )
{
if(!pccs->Compare( &cf, lfHeight ))
continue;
matched:
//$ FUTURE: make this work even with wrap around of dwAgeNext
// Mark as most recently used if it isn't already in use.
if(pccs->_dwAge != _dwAgeNext - 1)
pccs->_dwAge = _dwAgeNext++;
pccs->_dwRefCount++; // bump up ref. count
// setup the font to be used for this hdc.
pccs->_hdc = hdc;
// the same font can be used at different offsets.
pccs->_yOffset = cf.yOffset ? (cf.yOffset * yPerInch / LY_PER_INCH) : 0;
quickCrcSearch[hashKey].pccs = pccs;
return pccs;
}
}
// we did not find a match, init a new font cache.
pccs = GrabInitNewCcs ( hdc, &cf, yPerInch );
quickCrcSearch[hashKey].pccs = pccs;
return pccs;
}
/*
* CCcs* CFontCache::GrabInitNewCcs(hdc, pcf)
*
* @mfunc
* create a logical font and store it in our cache.
*
*/
CCcs* CFontCache::GrabInitNewCcs(
HDC hdc, //@parm HDC into which font will be selected
const CCharFormat * const pcf, //@parm description of desired logical font
const LONG yPerInch) //@parm Y Pixels per Inch
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::GrabInitNewCcs");
DWORD dwAgeOldest = 0xffffffff;
CCcs * pccs;
const CCcs * const pccsMost = &_rgccs[cccsMost - 1];
CCcs * pccsOldest = NULL;
// look for unused entry and oldest in use entry
for(pccs = &_rgccs[0]; pccs <= pccsMost && pccs->_fValid; pccs++)
if(pccs->_dwRefCount == 0 && pccs->_dwAge < dwAgeOldest)
{
dwAgeOldest = pccs->_dwAge;
pccsOldest = pccs;
}
if(pccs > pccsMost) // Didn't find an unused entry, use oldest entry
{
pccs = pccsOldest;
if(!pccs)
{
AssertSz(FALSE, "CFontCache::GrabInitNewCcs oldest entry is NULL");
return NULL;
}
}
pccs->_pfc = this;
// Initialize new CCcs
if(!pccs->Init(hdc, pcf, yPerInch) )
{
return NULL;
}
pccs->_dwRefCount++;
return pccs;
}
// ============================= CCcs class ===================================================
/*
* BOOL CCcs::Init()
*
* @mfunc
* Init one font cache object. The global font cache stores
* individual CCcs objects.
*/
BOOL CCcs::Init (
HDC hdc, //@parm HDC into which font will be selected
const CCharFormat * const pcf, //@parm description of desired logical font
const LONG yPerInch) //@parm Y pixels per inch
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::Init");
if ( _fValid ) Free(); // recycle already in-use fonts.
if( MakeFont(hdc, pcf, yPerInch) )
{
_bCrc = pcf->bCRC;
_yCfHeight = pcf->yHeight;
Assert(0 != _bCrc);
if( pcf->yOffset ) // offset for super/sub script.
{
_yOffset = pcf->yOffset * yPerInch / LY_PER_INCH;
}
else
_yOffset = 0;
_dwAge = _pfc->_dwAgeNext++;
_fValid = TRUE; // successfully created a new font cache.
}
return _fValid;
}
/*
* void CCcs::Free ()
*
* @mfunc
* Free any dynamic memory allocated by an individual font's cache.
*
*/
void CCcs::Free ()
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::Free");
Assert(_fValid);
_widths.Free();
if(_hfont)
DestroyFont();
_fValid = FALSE;
_dwRefCount = 0;
}
/*
* BOOL CCcs::CheckFillWidths ()
*
* @mfunc
* Check existence, load nonexistent width information.
*/
BOOL CCcs::CheckFillWidths (
TCHAR ch, //@parm the TCHAR character in question.
LONG &rlWidth ) //@parm the width to use
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::CheckFillWidths");
if ( !_widths.CheckWidth(ch, rlWidth) )
{
return FillWidths(ch, rlWidth);
}
return TRUE;
}
/*
* CCcs::FillWidths (ch, rlWidth)
*
* @mfunc
* Fill in this CCcs with metrics info for given device
*
* @rdesc
* TRUE if OK, FALSE if failed
*/
BOOL CCcs::FillWidths(
TCHAR ch, //@parm The TCHAR character we need a width for.
LONG &rlWidth) //@parm the width of the character
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::FillWidths");
BOOL fRes = FALSE;
HFONT hfontOld;
AssertSz(_hfont, "CCcs::Fill - CCcs has no font");
// The mapping mode for the HDC is set before we get here.
hfontOld = (HFONT)GetCurrentObject( _hdc, OBJ_FONT );
if ( hfontOld == _hfont || (hfontOld = (HFONT)SelectObject(_hdc, _hfont)) )
{
// fill up the width info.
fRes = _widths.FillWidth ( _hdc, ch, _xOverhangAdjust, rlWidth,
_wCodePage, _bConvertMode, _xAveCharWidth, _xDefDBCWidth, _fFixPitchFont );
}
// restore the original mapping mode and font.
//
if(hfontOld && hfontOld != _hfont)
SelectFont(_hdc, hfontOld);
return fRes;
}
/*
* BOOL CCcs::MakeFont(hdc, pcf)
*
* @mfunc
* Wrapper, setup for CreateFontIndirect() to create the font to be
* selected into the HDC.
*
* @rdesc
* TRUE if OK, FALSE if allocation failure
*/
#define szFontOfChoice TEXT("Arial")
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -