745 lines
21 KiB
C
745 lines
21 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
misc.c
|
|
|
|
Abstract:
|
|
|
|
This file implements the NT console server font routines.
|
|
|
|
Author:
|
|
|
|
Therese Stowell (thereses) 22-Jan-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef DEBUG_PRINT
|
|
ULONG gDebugFlag = 0 ;
|
|
// ULONG gDebugFlag = _DBGOUTPUT | _DBGCHARS | _DBGFONTS | _DBGFONTS2 ;
|
|
#endif
|
|
|
|
PFONT_INFO FontInfo = NULL;
|
|
ULONG FontInfoLength;
|
|
ULONG NumberOfFonts;
|
|
BOOL gbEnumerateFaces = FALSE;
|
|
|
|
|
|
#define FE_ABANDONFONT 0
|
|
#define FE_SKIPFONT 1
|
|
#define FE_FONTOK 2
|
|
|
|
/*
|
|
* Initial default fonts and face names
|
|
*/
|
|
PFACENODE gpFaceNames = NULL;
|
|
|
|
/*
|
|
* TTPoints -- Initial font pixel heights for TT fonts
|
|
*/
|
|
SHORT TTPoints[] = {
|
|
5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72
|
|
};
|
|
#if defined(FE_SB)
|
|
/*
|
|
* TTPointsDbcs -- Initial font pixel heights for TT fonts of DBCS.
|
|
* So, This list except odd point size because font width is (SBCS:DBCS != 1:2).
|
|
*/
|
|
SHORT TTPointsDbcs[] = {
|
|
6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72
|
|
};
|
|
#endif
|
|
|
|
|
|
typedef struct _FONTENUMDATA {
|
|
HDC hDC;
|
|
BOOL bFindFaces;
|
|
ULONG ulFE;
|
|
PSHORT pTTPoints;
|
|
UINT nTTPoints;
|
|
} FONTENUMDATA, *PFONTENUMDATA;
|
|
|
|
|
|
PFACENODE
|
|
AddFaceNode(PFACENODE *ppStart, LPTSTR ptsz) {
|
|
PFACENODE pNew;
|
|
PFACENODE *ppTmp;
|
|
int cb;
|
|
|
|
/*
|
|
* Is it already here?
|
|
*/
|
|
for (ppTmp = ppStart; *ppTmp; ppTmp = &((*ppTmp)->pNext)) {
|
|
if (_tcscmp(((*ppTmp)->atch), ptsz) == 0) {
|
|
// already there !
|
|
return *ppTmp;
|
|
}
|
|
}
|
|
|
|
cb = (_tcslen(ptsz) + 1) * sizeof(TCHAR);
|
|
pNew = (PFACENODE)HeapAlloc(RtlProcessHeap(),0,sizeof(FACENODE) + cb);
|
|
if (pNew == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
pNew->pNext = NULL;
|
|
pNew->dwFlag = 0;
|
|
_tcscpy(pNew->atch, ptsz);
|
|
*ppTmp = pNew;
|
|
return pNew;
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyFaceNodes( VOID ) {
|
|
PFACENODE pNext;
|
|
PFACENODE pTmp;
|
|
|
|
pTmp = gpFaceNames;
|
|
while (pTmp != NULL) {
|
|
pNext = pTmp->pNext;
|
|
HeapFree(RtlProcessHeap(), 0, pTmp);
|
|
pTmp = pNext;
|
|
}
|
|
gpFaceNames = NULL;
|
|
}
|
|
|
|
|
|
int
|
|
AddFont(
|
|
ENUMLOGFONT *pelf,
|
|
NEWTEXTMETRIC *pntm,
|
|
int nFontType,
|
|
HDC hDC,
|
|
PFACENODE pFN
|
|
)
|
|
|
|
/*++
|
|
|
|
Add the font desribed by the LOGFONT structure to the font table if
|
|
it's not already there.
|
|
|
|
--*/
|
|
|
|
{
|
|
HFONT hFont;
|
|
TEXTMETRIC tm;
|
|
LONG nFont;
|
|
COORD SizeToShow;
|
|
COORD SizeActual;
|
|
COORD SizeWant;
|
|
BYTE tmFamily;
|
|
SIZE Size;
|
|
LPTSTR ptszFace = pelf->elfLogFont.lfFaceName;
|
|
|
|
/* get font info */
|
|
SizeWant.X = (SHORT)pelf->elfLogFont.lfWidth;
|
|
SizeWant.Y = (SHORT)pelf->elfLogFont.lfHeight;
|
|
|
|
CreateBoldFont:
|
|
pelf->elfLogFont.lfQuality = DEFAULT_QUALITY;
|
|
hFont = CreateFontIndirect(&pelf->elfLogFont);
|
|
if (!hFont) {
|
|
DBGFONTS((" REJECT font (can't create)\n"));
|
|
return FE_SKIPFONT; // same font in other sizes may still be suitable
|
|
}
|
|
|
|
DBGFONTS2((" hFont = %lx\n", hFont));
|
|
|
|
//
|
|
// BUGBUG
|
|
// For reasons unbeknownst to me, removing this code causes GDI
|
|
// to yack, claiming that the font is owned by another process.
|
|
//
|
|
|
|
SelectObject(hDC, hFont);
|
|
GetTextMetrics(hDC, &tm);
|
|
|
|
GetTextExtentPoint32(hDC, TEXT("0"), 1, &Size);
|
|
SizeActual.X = (SHORT)Size.cx;
|
|
SizeActual.Y = (SHORT)(tm.tmHeight + tm.tmExternalLeading);
|
|
DBGFONTS2((" actual size %d,%d\n", SizeActual.X, SizeActual.Y));
|
|
tmFamily = tm.tmPitchAndFamily;
|
|
if (TM_IS_TT_FONT(tmFamily) && (SizeWant.Y >= 0)) {
|
|
SizeToShow = SizeWant;
|
|
if (SizeWant.X == 0) {
|
|
// Asking for zero width height gets a default aspect-ratio width.
|
|
// It's better to show that width rather than 0.
|
|
SizeToShow.X = SizeActual.X;
|
|
}
|
|
} else {
|
|
SizeToShow = SizeActual;
|
|
}
|
|
|
|
//
|
|
// The size shouldn't be zero. This is to help catch Windows Bug #332453.
|
|
//
|
|
ASSERT(SizeActual.X != 0 && SizeActual.Y != 0 && "If you hit this please e-mail jasonsch");
|
|
|
|
DBGFONTS2((" SizeToShow = (%d,%d), SizeActual = (%d,%d)\n",
|
|
SizeToShow.X, SizeToShow.Y, SizeActual.X, SizeActual.Y));
|
|
|
|
//
|
|
// BUGBUG
|
|
// There's a GDI bug - this assert fails occasionally.
|
|
//ASSERT (tm.tmMaxCharWidth == pntm->tmMaxCharWidth);
|
|
|
|
/*
|
|
* NOW, determine whether this font entry has already been cached
|
|
* LATER : it may be possible to do this before creating the font, if
|
|
* we can trust the dimensions & other info from pntm.
|
|
* Sort by size:
|
|
* 1) By pixelheight (negative Y values)
|
|
* 2) By height (as shown)
|
|
* 3) By width (as shown)
|
|
*/
|
|
for (nFont = 0; nFont < (LONG)NumberOfFonts; ++nFont) {
|
|
COORD SizeShown;
|
|
|
|
if (FontInfo[nFont].hFont == NULL) {
|
|
DBGFONTS(("! Font %x has a NULL hFont\n", nFont));
|
|
continue;
|
|
}
|
|
|
|
if (FontInfo[nFont].SizeWant.X > 0) {
|
|
SizeShown.X = FontInfo[nFont].SizeWant.X;
|
|
} else {
|
|
SizeShown.X = FontInfo[nFont].Size.X;
|
|
}
|
|
|
|
if (FontInfo[nFont].SizeWant.Y > 0) {
|
|
// This is a font specified by cell height.
|
|
SizeShown.Y = FontInfo[nFont].SizeWant.Y;
|
|
} else {
|
|
SizeShown.Y = FontInfo[nFont].Size.Y;
|
|
if (FontInfo[nFont].SizeWant.Y < 0) {
|
|
// This is a TT font specified by character height.
|
|
if (SizeWant.Y < 0 && SizeWant.Y > FontInfo[nFont].SizeWant.Y) {
|
|
// Requested pixelheight is smaller than this one.
|
|
DBGFONTS(("INSERT %d pt at %x, before %d pt\n",
|
|
-SizeWant.Y, nFont, -FontInfo[nFont].SizeWant.Y));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DBGFONTS((" SizeShown(%x) = (%d,%d)\n",nFont,SizeShown.X,SizeShown.Y));
|
|
|
|
if (SIZE_EQUAL(SizeShown, SizeToShow) &&
|
|
FontInfo[nFont].Family == tmFamily &&
|
|
FontInfo[nFont].Weight == tm.tmWeight &&
|
|
_tcscmp(FontInfo[nFont].FaceName, ptszFace) == 0) {
|
|
/*
|
|
* Already have this font
|
|
*/
|
|
DBGFONTS2((" Already have the font\n"));
|
|
DeleteObject(hFont);
|
|
return FE_FONTOK;
|
|
}
|
|
|
|
|
|
if ((SizeToShow.Y < SizeShown.Y) ||
|
|
(SizeToShow.Y == SizeShown.Y && SizeToShow.X < SizeShown.X)) {
|
|
/*
|
|
* This new font is smaller than nFont
|
|
*/
|
|
DBGFONTS(("INSERT at %x, SizeToShow = (%d,%d)\n", nFont,
|
|
SizeToShow.X,SizeToShow.Y));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we have to grow our font table, do it
|
|
*/
|
|
if (NumberOfFonts == FontInfoLength) {
|
|
PFONT_INFO Temp;
|
|
|
|
FontInfoLength += FONT_INCREMENT;
|
|
Temp = (PFONT_INFO)HeapReAlloc(RtlProcessHeap(), 0, FontInfo,
|
|
sizeof(FONT_INFO) * FontInfoLength);
|
|
if (Temp == NULL) {
|
|
FontInfoLength -= FONT_INCREMENT;
|
|
return FE_ABANDONFONT; // no point enumerating more - no memory!
|
|
}
|
|
FontInfo = Temp;
|
|
}
|
|
|
|
/*
|
|
* The font we are adding should be inserted into the list,
|
|
* if it is smaller than the last one.
|
|
*/
|
|
if (nFont < (LONG)NumberOfFonts) {
|
|
RtlMoveMemory(&FontInfo[nFont+1],
|
|
&FontInfo[nFont],
|
|
sizeof(FONT_INFO) * (NumberOfFonts - nFont));
|
|
}
|
|
|
|
/*
|
|
* Store the font info
|
|
*/
|
|
FontInfo[nFont].hFont = hFont;
|
|
FontInfo[nFont].Family = tmFamily;
|
|
FontInfo[nFont].Size = SizeActual;
|
|
if (TM_IS_TT_FONT(tmFamily)) {
|
|
FontInfo[nFont].SizeWant = SizeWant;
|
|
} else {
|
|
FontInfo[nFont].SizeWant.X = 0;
|
|
FontInfo[nFont].SizeWant.Y = 0;
|
|
}
|
|
FontInfo[nFont].Weight = tm.tmWeight;
|
|
FontInfo[nFont].FaceName = pFN->atch;
|
|
#if defined(FE_SB)
|
|
FontInfo[nFont].tmCharSet = tm.tmCharSet;
|
|
#endif
|
|
|
|
++NumberOfFonts;
|
|
|
|
/*
|
|
* If this is a true type font, create a bold version too.
|
|
*/
|
|
if (nFontType == TRUETYPE_FONTTYPE && !IS_BOLD(FontInfo[nFont].Weight)) {
|
|
pelf->elfLogFont.lfWeight = FW_BOLD;
|
|
goto CreateBoldFont;
|
|
}
|
|
|
|
return FE_FONTOK; // and continue enumeration
|
|
}
|
|
|
|
|
|
VOID
|
|
InitializeFonts( VOID )
|
|
{
|
|
EnumerateFonts(EF_DEFFACE); // Just the Default font
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyFonts( VOID )
|
|
{
|
|
ULONG FontIndex;
|
|
|
|
if (FontInfo != NULL) {
|
|
for (FontIndex = 0; FontIndex < NumberOfFonts; FontIndex++) {
|
|
DeleteObject(FontInfo[FontIndex].hFont);
|
|
}
|
|
HeapFree(RtlProcessHeap(), 0, FontInfo);
|
|
FontInfo = NULL;
|
|
NumberOfFonts = 0;
|
|
}
|
|
|
|
DestroyFaceNodes();
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns bit combination
|
|
* FE_ABANDONFONT - do not continue enumerating this font
|
|
* FE_SKIPFONT - skip this font but keep enumerating
|
|
* FE_FONTOK - font was created and added to cache or already there
|
|
*/
|
|
int
|
|
FontEnum(
|
|
ENUMLOGFONT *pelf,
|
|
NEWTEXTMETRIC *pntm,
|
|
int nFontType,
|
|
PFONTENUMDATA pfed
|
|
)
|
|
|
|
/*++
|
|
|
|
Is called exactly once by GDI for each font in the system. This
|
|
routine is used to store the FONT_INFO structure.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i;
|
|
LPTSTR ptszFace = pelf->elfLogFont.lfFaceName;
|
|
PFACENODE pFN;
|
|
|
|
DBGFONTS((" FontEnum \"%ls\" (%d,%d) weight 0x%lx(%d) %x -- %s\n",
|
|
ptszFace,
|
|
pelf->elfLogFont.lfWidth, pelf->elfLogFont.lfHeight,
|
|
pelf->elfLogFont.lfWeight, pelf->elfLogFont.lfWeight,
|
|
pelf->elfLogFont.lfCharSet,
|
|
pfed->bFindFaces ? "Finding Faces" : "Creating Fonts"));
|
|
|
|
//
|
|
// reject variable width and italic fonts, also tt fonts with neg ac
|
|
//
|
|
|
|
|
|
if
|
|
(
|
|
!(pelf->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ||
|
|
(pelf->elfLogFont.lfItalic) ||
|
|
!(pntm->ntmFlags & NTM_NONNEGATIVE_AC)
|
|
)
|
|
{
|
|
if (! IsAvailableTTFont(ptszFace)) {
|
|
DBGFONTS((" REJECT face (dbcs, variable pitch, italic, or neg a&c)\n"));
|
|
return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* reject TT fonts for whoom family is not modern, that is do not use
|
|
* FF_DONTCARE // may be surprised unpleasantly
|
|
* FF_DECORATIVE // likely to be symbol fonts
|
|
* FF_SCRIPT // cursive, inappropriate for console
|
|
* FF_SWISS OR FF_ROMAN // variable pitch
|
|
*/
|
|
|
|
if ((nFontType == TRUETYPE_FONTTYPE) &&
|
|
((pelf->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN)) {
|
|
DBGFONTS((" REJECT face (TT but not FF_MODERN)\n"));
|
|
return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT;
|
|
}
|
|
|
|
/*
|
|
* reject non-TT fonts that aren't OEM
|
|
*/
|
|
if ((nFontType != TRUETYPE_FONTTYPE) &&
|
|
#if defined(FE_SB)
|
|
(!gfFESystem || !IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet)) &&
|
|
#endif
|
|
(pelf->elfLogFont.lfCharSet != OEM_CHARSET)) {
|
|
DBGFONTS((" REJECT face (not TT nor OEM)\n"));
|
|
return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT;
|
|
}
|
|
|
|
/*
|
|
* reject non-TT fonts that are virtical font
|
|
*/
|
|
if ((nFontType != TRUETYPE_FONTTYPE) &&
|
|
(ptszFace[0] == TEXT('@'))) {
|
|
DBGFONTS((" REJECT face (not TT and TATEGAKI)\n"));
|
|
return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT;
|
|
}
|
|
|
|
/*
|
|
* reject non-TT fonts that aren't Terminal
|
|
*/
|
|
if (gfFESystem && (nFontType != TRUETYPE_FONTTYPE) &&
|
|
(_tcscmp(ptszFace, TEXT("Terminal")) != 0)) {
|
|
DBGFONTS((" REJECT face (not TT nor Terminal)\n"));
|
|
return pfed->bFindFaces ? FE_SKIPFONT : FE_ABANDONFONT;
|
|
}
|
|
|
|
/*
|
|
* reject Far East TT fonts that aren't Far East charset.
|
|
*/
|
|
if (IsAvailableTTFont(ptszFace) &&
|
|
!IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet) &&
|
|
!IsAvailableTTFontCP(ptszFace,0)
|
|
) {
|
|
DBGFONTS((" REJECT face (Far East TT and not Far East charset)\n"));
|
|
return FE_SKIPFONT; // should be enumerate next charset.
|
|
}
|
|
|
|
/*
|
|
* Add or find the facename
|
|
*/
|
|
pFN = AddFaceNode(&gpFaceNames, ptszFace);
|
|
if (pFN == NULL) {
|
|
return FE_ABANDONFONT;
|
|
}
|
|
|
|
if (pfed->bFindFaces) {
|
|
DWORD dwFontType;
|
|
if (nFontType == TRUETYPE_FONTTYPE) {
|
|
DBGFONTS(("NEW TT FACE %ls\n", ptszFace));
|
|
dwFontType = EF_TTFONT;
|
|
} else if (nFontType == RASTER_FONTTYPE) {
|
|
DBGFONTS(("NEW OEM FACE %ls\n",ptszFace));
|
|
dwFontType = EF_OEMFONT;
|
|
}
|
|
pFN->dwFlag |= dwFontType | EF_NEW;
|
|
#if defined(FE_SB)
|
|
if (IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet))
|
|
pFN->dwFlag |= EF_DBCSFONT;
|
|
#endif
|
|
return FE_SKIPFONT;
|
|
}
|
|
|
|
|
|
if (IS_BOLD(pelf->elfLogFont.lfWeight)) {
|
|
DBGFONTS2((" A bold font (weight %d)\n", pelf->elfLogFont.lfWeight));
|
|
// return FE_SKIPFONT;
|
|
}
|
|
|
|
/*
|
|
* Add the font to the table. If this is a true type font, add the
|
|
* sizes from the array. Otherwise, just add the size we got.
|
|
*/
|
|
if (nFontType & TRUETYPE_FONTTYPE) {
|
|
for (i = 0; i < pfed->nTTPoints; i++) {
|
|
pelf->elfLogFont.lfHeight = pfed->pTTPoints[i];
|
|
pelf->elfLogFont.lfWidth = 0;
|
|
pelf->elfLogFont.lfWeight = 400;
|
|
pfed->ulFE |= AddFont(pelf, pntm, nFontType, pfed->hDC, pFN);
|
|
if (pfed->ulFE & FE_ABANDONFONT) {
|
|
return FE_ABANDONFONT;
|
|
}
|
|
}
|
|
} else {
|
|
pfed->ulFE |= AddFont(pelf, pntm, nFontType, pfed->hDC, pFN);
|
|
if (pfed->ulFE & FE_ABANDONFONT) {
|
|
return FE_ABANDONFONT;
|
|
}
|
|
}
|
|
|
|
return FE_FONTOK; // and continue enumeration
|
|
}
|
|
|
|
BOOL
|
|
DoFontEnum(
|
|
HDC hDC,
|
|
LPTSTR ptszFace,
|
|
PSHORT pTTPoints,
|
|
UINT nTTPoints)
|
|
{
|
|
BOOL bDeleteDC = FALSE;
|
|
FONTENUMDATA fed;
|
|
LOGFONT LogFont;
|
|
|
|
DBGFONTS(("DoFontEnum \"%ls\"\n", ptszFace));
|
|
if (hDC == NULL) {
|
|
hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
|
|
bDeleteDC = TRUE;
|
|
}
|
|
|
|
fed.hDC = hDC;
|
|
fed.bFindFaces = (ptszFace == NULL);
|
|
fed.ulFE = 0;
|
|
fed.pTTPoints = pTTPoints;
|
|
fed.nTTPoints = nTTPoints;
|
|
RtlZeroMemory(&LogFont, sizeof(LOGFONT));
|
|
LogFont.lfCharSet = DEFAULT_CHARSET;
|
|
if (ptszFace)
|
|
_tcscpy(LogFont.lfFaceName, ptszFace);
|
|
/*
|
|
* EnumFontFamiliesEx function enumerates one font in every face in every character set.
|
|
*/
|
|
EnumFontFamiliesEx(hDC, &LogFont, (FONTENUMPROC)FontEnum, (LPARAM)&fed, 0);
|
|
if (bDeleteDC) {
|
|
DeleteDC(hDC);
|
|
}
|
|
return (fed.ulFE & FE_FONTOK) != 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
RemoveFace(LPTSTR ptszFace)
|
|
{
|
|
DWORD i;
|
|
int nToRemove = 0;
|
|
|
|
DBGFONTS(("RemoveFace %ls\n", ptszFace));
|
|
//
|
|
// Delete & Remove fonts with Face Name == ptszFace
|
|
//
|
|
for (i = 0; i < NumberOfFonts; i++) {
|
|
if (_tcscmp(FontInfo[i].FaceName, ptszFace) == 0) {
|
|
BOOL bDeleted = DeleteObject(FontInfo[i].hFont);
|
|
DBGPRINT(("RemoveFace: hFont %lx was %sdeleted\n",
|
|
FontInfo[i].hFont, bDeleted ? "" : "NOT "));
|
|
FontInfo[i].hFont = NULL;
|
|
nToRemove++;
|
|
} else if (nToRemove > 0) {
|
|
/*
|
|
* Shuffle from FontInfo[i] down nToRemove slots.
|
|
*/
|
|
RtlMoveMemory(&FontInfo[i - nToRemove],
|
|
&FontInfo[i],
|
|
sizeof(FONT_INFO)*(NumberOfFonts - i));
|
|
NumberOfFonts -= nToRemove;
|
|
i -= nToRemove;
|
|
nToRemove = 0;
|
|
}
|
|
}
|
|
NumberOfFonts -= nToRemove;
|
|
}
|
|
|
|
TCHAR DefaultFaceName[LF_FACESIZE];
|
|
COORD DefaultFontSize;
|
|
BYTE DefaultFontFamily;
|
|
ULONG DefaultFontIndex = 0;
|
|
ULONG CurrentFontIndex = 0;
|
|
|
|
NTSTATUS
|
|
EnumerateFonts(
|
|
DWORD Flags)
|
|
{
|
|
TEXTMETRIC tm;
|
|
HDC hDC;
|
|
PFACENODE pFN;
|
|
ULONG ulOldEnumFilter;
|
|
BOOL bEnumOEMFace = TRUE;
|
|
DWORD FontIndex;
|
|
DWORD dwFontType = 0;
|
|
|
|
DBGFONTS(("EnumerateFonts %lx\n", Flags));
|
|
|
|
dwFontType = (EF_TTFONT|EF_OEMFONT|EF_DEFFACE) & Flags;
|
|
|
|
if (FontInfo == NULL) {
|
|
//
|
|
// allocate memory for the font array
|
|
//
|
|
NumberOfFonts = 0;
|
|
|
|
FontInfo = (PFONT_INFO)HeapAlloc(RtlProcessHeap(),0,sizeof(FONT_INFO) * INITIAL_FONTS);
|
|
if (FontInfo == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
FontInfoLength = INITIAL_FONTS;
|
|
}
|
|
|
|
hDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
|
|
|
|
// Before enumeration, turn off font enumeration filters.
|
|
ulOldEnumFilter = SetFontEnumeration(0);
|
|
SetFontEnumeration(ulOldEnumFilter & ~FE_FILTER_TRUETYPE);
|
|
|
|
if (Flags & EF_DEFFACE) {
|
|
SelectObject(hDC, GetStockObject(OEM_FIXED_FONT));
|
|
GetTextMetrics(hDC, &tm);
|
|
GetTextFace(hDC, LF_FACESIZE, DefaultFaceName);
|
|
|
|
DefaultFontSize.X = (SHORT)(tm.tmMaxCharWidth);
|
|
DefaultFontSize.Y = (SHORT)(tm.tmHeight+tm.tmExternalLeading);
|
|
DefaultFontFamily = tm.tmPitchAndFamily;
|
|
#if !defined(FE_SB)
|
|
DBGFONTS(("Default (OEM) Font %ls (%d,%d)\n", DefaultFaceName,
|
|
DefaultFontSize.X, DefaultFontSize.Y));
|
|
#else
|
|
if (IS_ANY_DBCS_CHARSET(tm.tmCharSet))
|
|
DefaultFontSize.X /= 2;
|
|
DBGFONTS(("Default (OEM) Font %ls (%d,%d) CharSet 0x%02X\n", DefaultFaceName,
|
|
DefaultFontSize.X, DefaultFontSize.Y,
|
|
tm.tmCharSet));
|
|
#endif
|
|
|
|
// Make sure we are going to enumerate the OEM face.
|
|
pFN = AddFaceNode(&gpFaceNames, DefaultFaceName);
|
|
if (pFN)
|
|
pFN->dwFlag |= EF_DEFFACE | EF_OEMFONT;
|
|
}
|
|
|
|
if (gbEnumerateFaces) {
|
|
/*
|
|
* Set the EF_OLD bit and clear the EF_NEW bit
|
|
* for all previously available faces
|
|
*/
|
|
for (pFN = gpFaceNames; pFN; pFN = pFN->pNext) {
|
|
pFN->dwFlag |= EF_OLD;
|
|
pFN->dwFlag &= ~EF_NEW;
|
|
}
|
|
|
|
//
|
|
// Use DoFontEnum to get the names of all the suitable Faces
|
|
// All facenames found will be put in gpFaceNames with
|
|
// the EF_NEW bit set.
|
|
//
|
|
DoFontEnum(hDC, NULL, TTPoints, 1);
|
|
gbEnumerateFaces = FALSE;
|
|
}
|
|
|
|
// Use DoFontEnum to get all fonts from the system. Our FontEnum
|
|
// proc puts just the ones we want into an array
|
|
//
|
|
for (pFN = gpFaceNames; pFN; pFN = pFN->pNext) {
|
|
DBGFONTS(("\"%ls\" is %s%s%s%s%s%s\n", pFN->atch,
|
|
pFN->dwFlag & EF_NEW ? "NEW " : " ",
|
|
pFN->dwFlag & EF_OLD ? "OLD " : " ",
|
|
pFN->dwFlag & EF_ENUMERATED ? "ENUMERATED " : " ",
|
|
pFN->dwFlag & EF_OEMFONT ? "OEMFONT " : " ",
|
|
pFN->dwFlag & EF_TTFONT ? "TTFONT " : " ",
|
|
pFN->dwFlag & EF_DEFFACE ? "DEFFACE " : " "));
|
|
|
|
if ((pFN->dwFlag & (EF_OLD|EF_NEW)) == EF_OLD) {
|
|
// The face is no longer available
|
|
RemoveFace(pFN->atch);
|
|
pFN->dwFlag &= ~EF_ENUMERATED;
|
|
continue;
|
|
}
|
|
if ((pFN->dwFlag & dwFontType) == 0) {
|
|
// not the kind of face we want
|
|
continue;
|
|
}
|
|
if (pFN->dwFlag & EF_ENUMERATED) {
|
|
// we already enumerated this face
|
|
continue;
|
|
}
|
|
|
|
if (pFN->dwFlag & EF_TTFONT) {
|
|
#if defined(FE_SB)
|
|
if (gfFESystem && !IsAvailableTTFontCP(pFN->atch,0))
|
|
DoFontEnum(hDC, pFN->atch, TTPointsDbcs, NELEM(TTPointsDbcs));
|
|
else
|
|
#endif
|
|
DoFontEnum(hDC, pFN->atch, TTPoints, NELEM(TTPoints));
|
|
} else {
|
|
DoFontEnum(hDC, pFN->atch, NULL, 0);
|
|
|
|
// If we find that the face just enumerated is the same as OEM,
|
|
// reset flag so we don't try to enumerate it again.
|
|
|
|
if (!_tcsncmp(pFN->atch, DefaultFaceName, LF_FACESIZE)) {
|
|
bEnumOEMFace = FALSE;
|
|
}
|
|
}
|
|
pFN->dwFlag |= EF_ENUMERATED;
|
|
}
|
|
|
|
|
|
// After enumerating fonts, restore the font enumeration filter.
|
|
SetFontEnumeration(ulOldEnumFilter);
|
|
|
|
DeleteDC(hDC);
|
|
|
|
#if defined(FE_SB)
|
|
if (gfFESystem )
|
|
{
|
|
for (FontIndex = 0; FontIndex < NumberOfFonts; FontIndex++) {
|
|
if (FontInfo[FontIndex].Size.X == DefaultFontSize.X &&
|
|
FontInfo[FontIndex].Size.Y == DefaultFontSize.Y &&
|
|
IS_ANY_DBCS_CHARSET(FontInfo[FontIndex].tmCharSet) &&
|
|
FontInfo[FontIndex].Family == DefaultFontFamily) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
for (FontIndex = 0; FontIndex < NumberOfFonts; FontIndex++) {
|
|
if (FontInfo[FontIndex].Size.X == DefaultFontSize.X &&
|
|
FontInfo[FontIndex].Size.Y == DefaultFontSize.Y &&
|
|
FontInfo[FontIndex].Family == DefaultFontFamily) {
|
|
break;
|
|
}
|
|
}
|
|
#if defined(FE_SB)
|
|
}
|
|
#endif
|
|
ASSERT(FontIndex < NumberOfFonts);
|
|
if (FontIndex < NumberOfFonts) {
|
|
DefaultFontIndex = FontIndex;
|
|
} else {
|
|
DefaultFontIndex = 0;
|
|
}
|
|
DBGFONTS(("EnumerateFonts : DefaultFontIndex = %ld\n", DefaultFontIndex));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|