📄 font.cpp
字号:
BOOL CCcs::MakeFont(
HDC hdc, //@parm HDC into which font will be selected
const CCharFormat * const pcf, //@parm description of desired logical font
const LONG yPerInch)
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::MakeFont");
_bConvertMode = pcf->bInternalEffects & CFEI_RUNISDBCS
? CM_LOWBYTE : CM_NONE;
_hdc = hdc;
// Computes font height
AssertSz(pcf->yHeight <= INT_MAX, "It's too big");
// Roundoff can result in a height of zero, which is bad.
// If this happens, use the minimum legal height.
_lf.lfHeight = -(MulDiv(pcf->yHeight, yPerInch, LY_PER_INCH));
if(_lf.lfHeight > 0)
_lf.lfHeight = -_lf.lfHeight; //FUTURE: do something more intelligent...
if(!_lf.lfHeight)
_lf.lfHeight--; // round error, make this a minimum legal height of -1.
_lf.lfWidth = 0;
if( pcf->wWeight != 0 )
{
_lf.lfWeight = pcf->wWeight;
}
else
{
_lf.lfWeight = (pcf->dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
#ifdef MACPORTStyle
_lf.lfWeight |= (pcf->dwEffects & CFE_OUTLINE) ? FW_OUTLINE : _lf.lfWeight;
_lf.lfWeight |= (pcf->dwEffects & CFE_SHADOW) ? FW_SHADOW : _lf.lfWeight;
#endif
}
_lf.lfItalic = (pcf->dwEffects & CFE_ITALIC) != 0;
_lf.lfUnderline = 0;
_lf.lfStrikeOut = 0;
_lf.lfCharSet = _bConvertMode == CM_LOWBYTE ? ANSI_CHARSET : pcf->bCharSet;
_lf.lfEscapement = 0;
_lf.lfOrientation = 0;
_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS | CLIP_DFA_OVERRIDE;
_lf.lfQuality = DEFAULT_QUALITY;
_lf.lfPitchAndFamily = pcf->bPitchAndFamily;
// If the run is DBCS, that means the font's codepage is not available in
// this system. Use the English ANSI codepage instead so we will display
// ANSI characters correctly. NOTE: _wCodePage is only used for Win95.
_wCodePage = (WORD)GetCodePage(_lf.lfCharSet);
wcscpy(_lf.lfFaceName, pcf->szFaceName);
_bUnderlineType = CFU_UNDERLINENONE;
if ((pcf->dwEffects & CFE_UNDERLINE) != 0)
{
_bUnderlineType = CFU_UNDERLINE;
if (pcf->bUnderlineType)
{
_bUnderlineType = pcf->bUnderlineType;
}
}
_fStrikeOut = (pcf->dwEffects & CFE_STRIKEOUT) != 0;
// Reader! A bundle of spagghetti code lies ahead of you!
// But go on boldly, for these spagghetti are seasoned with
// lots of comments, and ... good luck to you...
BOOL fTweakedCharSet = FALSE;
HFONT hfontOriginalCharset = NULL;
BYTE bOriginalCharset = _lf.lfCharSet;
WCHAR szNewFaceName[LF_FACESIZE];
if (NULL == GetFontWithMetrics(szNewFaceName))
{
AssertSz(0, "GetFontWithMetrics failed");
return FALSE;
}
if (0 != wcscmp(szNewFaceName, _lf.lfFaceName))
{
BOOL fCorrectFont = FALSE;
if (_lf.lfCharSet == SYMBOL_CHARSET)
{
// #1. if the face changed, and the specified charset was SYMBOL,
// but the face name exists and suports ANSI, we give preference
// to the face name
_lf.lfCharSet = ANSI_CHARSET;
fTweakedCharSet = TRUE;
hfontOriginalCharset = _hfont;
GetFontWithMetrics(szNewFaceName);
if (0 == wcscmp(szNewFaceName, _lf.lfFaceName))
// that's right, ANSI is the asnwer
fCorrectFont = TRUE;
else
// no, fall back by default
// the charset we got was right
_lf.lfCharSet = bOriginalCharset;
}
else if (_lf.lfCharSet == DEFAULT_CHARSET && _bCharSet == DEFAULT_CHARSET)
{
// #2. If we got the "default" font back, we don't know what it means
// (could be anything) so we veryfy that this guy's not SYMBOL
// (symbol is never default, but the OS could be lying to us!!!)
// we would like to veryfy more like whether it actually gave us
// Japanese instead of ANSI and labeled it "default"...
// but SYMBOL is the least we can do
_lf.lfCharSet = SYMBOL_CHARSET;
wcscpy(_lf.lfFaceName, szNewFaceName);
fTweakedCharSet = TRUE;
hfontOriginalCharset = _hfont;
GetFontWithMetrics(szNewFaceName);
if (0 == wcscmp(szNewFaceName, _lf.lfFaceName))
// that's right, it IS symbol!
// 'correct' the font to the 'true' one,
// and we'll get fMappedToSymbol
fCorrectFont = TRUE;
// always restore the charset name, we didn't want to
// question he original choice of charset here
_lf.lfCharSet = bOriginalCharset;
}
else if ( _bConvertMode != CM_LOWBYTE && IsFECharset(_lf.lfCharSet)
&& (!OnWinNTFE() || !OnWin95FE()))
{
if (_bCharSet != _lf.lfCharSet && (VER_PLATFORM_WIN32_WINDOWS == dwPlatformId))
{
// on Win95, when rendering to PS driver,
// it will give us something other than what we asked.
// We have to try some known font we got from GDI
switch (_lf.lfCharSet)
{
case CHINESEBIG5_CHARSET:
wcscpy(_lf.lfFaceName, lfBig5FaceName);
break;
case SHIFTJIS_CHARSET:
wcscpy(_lf.lfFaceName, lfJapaneseFaceName);
break;
case HANGEUL_CHARSET:
wcscpy(_lf.lfFaceName, lfHangulFaceName);
break;
case GB2312_CHARSET:
wcscpy(_lf.lfFaceName, lfGB2312FaceName);
break;
}
}
else
{
// this is a FE Font (from Lang pack) on a nonFEsystem
wcscpy(_lf.lfFaceName, szNewFaceName);
}
hfontOriginalCharset = _hfont;
GetFontWithMetrics(szNewFaceName);
if (0 == wcscmp(szNewFaceName, _lf.lfFaceName))
{
// that's right, it IS the FE font we want!
// 'correct' the font to the 'true' one.
fCorrectFont = TRUE;
// if (VER_PLATFORM_WIN32_WINDOWS == dwPlatformId)
// {
// save up the GDI font names for later printing use
switch (_lf.lfCharSet)
{
case CHINESEBIG5_CHARSET:
wcscpy(lfBig5FaceName, _lf.lfFaceName);
break;
case SHIFTJIS_CHARSET:
wcscpy(lfJapaneseFaceName, _lf.lfFaceName);
break;
case HANGEUL_CHARSET:
wcscpy(lfHangulFaceName, _lf.lfFaceName);
break;
case GB2312_CHARSET:
wcscpy(lfGB2312FaceName, _lf.lfFaceName);
break;
}
// }
}
fTweakedCharSet = TRUE;
}
if (hfontOriginalCharset)
{
// either keep the old font or the new one
if (fCorrectFont)
{
DeleteObject(hfontOriginalCharset);
hfontOriginalCharset = NULL;
}
else
{
// fall back to the original font
DeleteObject(_hfont);
_hfont = hfontOriginalCharset;
hfontOriginalCharset = NULL;
GetTextMetrics();
}
}
}
RetryCreateFont:
{
// could be that we just plain symply get mapped to symbol.
// avoid it
BOOL fMappedToSymbol = (_bCharSet == SYMBOL_CHARSET &&
_lf.lfCharSet != SYMBOL_CHARSET);
BOOL fChangedCharset = (_bCharSet != _lf.lfCharSet &&
_lf.lfCharSet != DEFAULT_CHARSET);
if (fChangedCharset || fMappedToSymbol)
{
// Here, the system did not preserve the font language or mapped
// our non-symbol font onto a symbol font,
// which will look awful when displayed.
// Giving us a symbol font when we asked for a non-symbol one
// (default can never be symbol) is very bizzare and means
// that either the font name is not known or the system
// has gone complete nuts here.
// The charset language takes priority over the font name.
// Hence, I would argue that nothing can be done to save the
// situation at this point, and we have to
// delete the font name and retry
// let's tweak it a bit
fTweakedCharSet = TRUE;
if (0 == wcscmp(_lf.lfFaceName, szFontOfChoice))
{
// we've been here already
// no font with an appropriate charset is on the system
// try getting the ANSI one for the original font name
// next time around, we'll null out the name as well!!
if (_lf.lfCharSet == ANSI_CHARSET)
{
TRACEINFOSZ("Asking for ANSI ARIAL and not getting it?!");
// those Win95 guys have definitely outbugged me
goto GetOutOfHere;
}
DeleteObject(_hfont);
wcscpy(_lf.lfFaceName, pcf->szFaceName);
_lf.lfCharSet = ANSI_CHARSET;
}
else
{
DeleteObject(_hfont);
wcscpy(_lf.lfFaceName, szFontOfChoice);
}
GetFontWithMetrics(szNewFaceName);
goto RetryCreateFont;
}
}
GetOutOfHere:
if(fTweakedCharSet || _bConvertMode == CM_LOWBYTE)
{
// we must preserve the original charset value, since it is used in Compare()
_lf.lfCharSet = bOriginalCharset;
wcscpy(_lf.lfFaceName, pcf->szFaceName);
}
if (hfontOriginalCharset)
DeleteObject(hfontOriginalCharset);
// if we're really really stuck, just get the system font and hope for the best.
if( _hfont == 0 )
{
_hfont = (HFONT)GetStockObject(SYSTEM_FONT);
}
return _hfont != 0;
}
/*
* BOOL CCcs::GetFontWithMetrics (szNewFaceName)
*
* @mfunc
* Get metrics used by the measurer and renderer and the new face name.
*/
BOOL CCcs::GetFontWithMetrics (
WCHAR* szNewFaceName)
{
// we want to keep _lf untouched as it is used in Compare().
_hfont = CreateFontIndirect(&_lf);
if (_hfont)
{
// FUTURE (alexgo) if a font was not created then we may want to select
// a default one.
// If we do this, then BE SURE not to overwrite the values of _lf as
// it is used to match with a pcf in our Compare().
//
// get text metrics, in logical units, that are constant for this font,
// regardless of the hdc in use.
GetTextMetrics();
HFONT hfontOld = SelectFont(_hdc, _hfont);
GetTextFace(_hdc, LF_FACESIZE, szNewFaceName);
SelectFont(_hdc, hfontOld);
}
return (_hfont != NULL);
}
/*
* BOOL CCcs::GetTextMetrics ( )
*
* @mfunc
* Get metrics used by the measurer and renderer.
*
* @comm
* These are in logical coordinates which are dependent
* on the mapping mode and font selected into the hdc.
*/
BOOL CCcs::GetTextMetrics ()
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::GetTextMetrics");
BOOL fRes = TRUE;
HFONT hfontOld;
TEXTMETRIC tm;
AssertSz(_hfont, "No font has been created.");
AssertSz(_hfont, "CCcs::Fill - CCcs has no font");
if ( GetCurrentObject( _hdc, OBJ_FONT ) != _hfont )
{
hfontOld = (HFONT)SelectObject(_hdc, _hfont);
if(!hfontOld)
{
fRes = FALSE;
DestroyFont();
goto cleanup;
}
}
else
hfontOld = 0;
if(!W32->GetTextMetrics(_hdc, &tm))
{
fRes = FALSE;
DestroyFont();
goto cleanup;
}
// the metrics, in logical units, dependent on the map mode and font.
_yHeight = (SHORT) tm.tmHeight;
_yDescent = (SHORT) tm.tmDescent;
_xAveCharWidth = (SHORT) tm.tmAveCharWidth;
_xOverhangAdjust= (SHORT) tm.tmOverhang;
_xOverhang = 0;
_xUnderhang = 0;
if ( _lf.lfItalic )
{
_xOverhang = SHORT ( (tm.tmAscent + 1) >> 2 );
_xUnderhang = SHORT ( (tm.tmDescent + 1) >> 2 );
}
// if fix pitch, the tm bit is clear
_fFixPitchFont = !(TMPF_FIXED_PITCH & tm.tmPitchAndFamily);
_xDefDBCWidth = 0;
_bCharSet = tm.tmCharSet;
// If SYMBOL_CHARSET is used, use the A APIs with the low bytes of the
// characters in the run
if(_bCharSet == SYMBOL_CHARSET)
_bConvertMode = CM_LOWBYTE;
else if (_bConvertMode == CM_NONE)
{
_bConvertMode = W32->DetermineConvertMode( tm.tmCharSet );
}
CalcUnderlineInfo(&tm);
cleanup:
if(hfontOld)
SelectFont(_hdc, hfontOld);
return fRes;
}
/*
* BOOL CCcs::CalcUnderlineInfo ( )
*
* @mfunc
* Calculate underline & strike out offsets
*
* @rdesc
* None.
*/
void CCcs::CalcUnderlineInfo(
TEXTMETRIC *ptm) //@parm text metric for the font
{
W32->CalcUnderlineInfo (this, ptm);
}
/*
* CCcs::DestroyFont
*
* @mfunc
* Destroy font handle for this CCcs
*
*/
VOID CCcs::DestroyFont()
{
TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::DestroyFont");
// clear out any old font
if(_hfont)
{
DeleteObject(_hfont);
_hfont = 0;
}
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -