int FontEnumForV2Console(ENUMLOGFONT *pelf, NEWTEXTMETRIC *pntm, int nFontType, LPARAM lParam) { UINT i; LPCWSTR pwszFace = pelf->elfLogFont.lfFaceName; BOOL const fIsEastAsianCP = IsEastAsianCP(GetACP()); LPCWSTR pwszCharSet; switch (pelf->elfLogFont.lfCharSet) { case ANSI_CHARSET: pwszCharSet = L"ANSI"; break; case CHINESEBIG5_CHARSET: pwszCharSet = L"Chinese Big5"; break; case EASTEUROPE_CHARSET: pwszCharSet = L"East Europe"; break; case GREEK_CHARSET: pwszCharSet = L"Greek"; break; case MAC_CHARSET: pwszCharSet = L"Mac"; break; case RUSSIAN_CHARSET: pwszCharSet = L"Russian"; break; case SYMBOL_CHARSET: pwszCharSet = L"Symbol"; break; case BALTIC_CHARSET: pwszCharSet = L"Baltic"; break; case DEFAULT_CHARSET: pwszCharSet = L"Default"; break; case GB2312_CHARSET: pwszCharSet = L"Chinese GB2312"; break; case HANGUL_CHARSET: pwszCharSet = L"Korean Hangul"; break; case OEM_CHARSET: pwszCharSet = L"OEM"; break; case SHIFTJIS_CHARSET: pwszCharSet = L"Japanese Shift-JIS"; break; case TURKISH_CHARSET: pwszCharSet = L"Turkish"; break; default: pwszCharSet = L"Unknown"; break; } wprintf(L"Enum'd font: '%ls' (X: %d, Y: %d) weight 0x%lx (%d) charset %s \r\n", pelf->elfLogFont.lfFaceName, pelf->elfLogFont.lfWidth, pelf->elfLogFont.lfHeight, pelf->elfLogFont.lfWeight, pelf->elfLogFont.lfWeight, pwszCharSet); // reject non-monospaced fonts if (!(pelf->elfLogFont.lfPitchAndFamily & FIXED_PITCH)) { wprintf(L"Rejecting non-monospaced font. \r\n"); return CONTINUE_ENUM; } // reject non-modern or italic TT fonts if ((nFontType == TRUETYPE_FONTTYPE) && (((pelf->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN) || pelf->elfLogFont.lfItalic)) { wprintf(L"Rejecting non-FF_MODERN or Italic TrueType font.\r\n"); return CONTINUE_ENUM; } // reject non-TT fonts that aren't OEM if ((nFontType != TRUETYPE_FONTTYPE) && (!fIsEastAsianCP || !IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet)) && (pelf->elfLogFont.lfCharSet != OEM_CHARSET)) { wprintf(L"Rejecting raster font that isn't OEM_CHARSET.\r\n"); return CONTINUE_ENUM; } // reject fonts that are vertical if (pwszFace[0] == TEXT('@')) { wprintf(L"Rejecting font face designed for vertical text.\r\n"); return CONTINUE_ENUM; } // reject non-TT fonts that aren't terminal if ((nFontType != TRUETYPE_FONTTYPE) && (0 != lstrcmp(pwszFace, L"Terminal"))) { wprintf(L"Rejecting raster font that isn't 'Terminal'.\r\n"); return CONTINUE_ENUM; } // reject East Asian TT fonts that aren't East Asian charset. if (fIsEastAsianCP && !IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet)) { wprintf(L"Rejecting East Asian TrueType font that isn't marked with East Asian charsets.\r\n"); return CONTINUE_ENUM; } // reject East Asian TT fonts on non-East Asian systems if (!fIsEastAsianCP && IS_ANY_DBCS_CHARSET(pelf->elfLogFont.lfCharSet)) { wprintf(L"Rejecting East Asian TrueType font when Windows non-Unicode codepage isn't from CJK country.\r\n"); return CONTINUE_ENUM; } if (nFontType & TRUETYPE_FONTTYPE) { for (i = 0; i < ARRAYSIZE(TTPoints); i++) { pelf->elfLogFont.lfHeight = TTPoints[i]; // If it's an East Asian enum, skip all odd height fonts. if (fIsEastAsianCP && (pelf->elfLogFont.lfHeight % 2) != 0) { continue; } pelf->elfLogFont.lfWidth = 0; pelf->elfLogFont.lfWeight = pntm->tmWeight; AddFont(pelf, pntm, nFontType, (HDC)lParam); } } else { AddFont(pelf, pntm, nFontType, (HDC)lParam); } return CONTINUE_ENUM; // and continue enumeration }
BOOL IsUnicodeFullWidth( IN WCHAR wch ) { if (0x20 <= wch && wch <= 0x7e) /* ASCII */ return FALSE; else if (0x3041 <= wch && wch <= 0x3094) /* Hiragana */ return TRUE; else if (0x30a1 <= wch && wch <= 0x30f6) /* Katakana */ return TRUE; else if (0x3105 <= wch && wch <= 0x312c) /* Bopomofo */ return TRUE; else if (0x3131 <= wch && wch <= 0x318e) /* Hangul Elements */ return TRUE; else if (0xac00 <= wch && wch <= 0xd7a3) /* Korean Hangul Syllables */ return TRUE; else if (0xff01 <= wch && wch <= 0xff5e) /* Fullwidth ASCII variants */ return TRUE; else if (0xff61 <= wch && wch <= 0xff9f) /* Halfwidth Katakana variants */ return FALSE; else if ( (0xffa0 <= wch && wch <= 0xffbe) || (0xffc2 <= wch && wch <= 0xffc7) || (0xffca <= wch && wch <= 0xffcf) || (0xffd2 <= wch && wch <= 0xffd7) || (0xffda <= wch && wch <= 0xffdc) ) /* Halfwidth Hangule variants */ return FALSE; else if (0xffe0 <= wch && wch <= 0xffe6) /* Fullwidth symbol variants */ return TRUE; else if (0x4e00 <= wch && wch <= 0x9fa5) /* Han Ideographic */ return TRUE; else if (0xf900 <= wch && wch <= 0xfa2d) /* Han Ideographic Compatibility */ return TRUE; else { #if 0 /* * Hack this block for I don't know FONT of Console Window. * * If you would like perfect result from IsUnicodeFullWidth routine, * then you should enable this block and * you should know FONT of Console Window. */ INT Width; TEXTMETRIC tmi; /* Unknown character */ GetTextMetricsW(hDC, &tmi); if (IS_ANY_DBCS_CHARSET(tmi.tmCharSet)) tmi.tmMaxCharWidth /= 2; GetCharWidth32(hDC, wch, wch, &Width); if (Width == tmi.tmMaxCharWidth) return FALSE; else if (Width == tmi.tmMaxCharWidth*2) return TRUE; #else ULONG MultiByteSize; RtlUnicodeToMultiByteSize(&MultiByteSize, &wch, sizeof(WCHAR)); if (MultiByteSize == 2) return TRUE ; else return FALSE ; #endif } ASSERT(FALSE); return FALSE; #if 0 ULONG MultiByteSize; RtlUnicodeToMultiByteSize(&MultiByteSize, &wch, sizeof(WCHAR)); if (MultiByteSize == 2) return TRUE ; else return FALSE ; #endif }
/* * Returns bit combination * FE_ABANDONFONT - do not continue enumerating this font * FE_FONTOK - font was created and added to cache or already there */ int CALLBACK FontEnum( LPENUMLOGFONTW lpLogFont, LPNEWTEXTMETRICW lpTextMetric, int nFontType, LPARAM lParam ) /*++ Is called exactly once by GDI for each font in the system. This routine is used to store the FONT_INFO structure. --*/ { PFONTENUMDC pfed = (PFONTENUMDC)lParam; HDC hDC = pfed->hDC; BOOL bFindFaces = pfed->bFindFaces; HFONT hFont; TEXTMETRICW tmi; LONG nFont; LONG nFontNew; COORD SizeToShow; COORD SizeActual; COORD SizeWant; BYTE tmFamily; SIZE Size; LPWSTR pwszFace = lpLogFont->elfLogFont.lfFaceName; PFACENODE pFN; DBGFONTS((" FontEnum \"%ls\" (%d,%d) weight 0x%lx(%d) -- %s\n", pwszFace, lpLogFont->elfLogFont.lfWidth, lpLogFont->elfLogFont.lfHeight, lpLogFont->elfLogFont.lfWeight, lpLogFont->elfLogFont.lfWeight, bFindFaces ? "Finding Faces" : "Creating Fonts")); // // reject variable width and italic fonts, also tt fonts with neg ac // also reject DBCS fonts because they are never really fixed pitch // they can be "binary" pitch meaning SBCS widths are the same as all // other SBCS widths and DBCS widhts the same as all DBCS widhts // (but DBCS widths won't be the same as SBCS widths) if ( !(lpLogFont->elfLogFont.lfPitchAndFamily & FIXED_PITCH) || (lpLogFont->elfLogFont.lfItalic) || !(((NTMW_INTERNAL *)lpTextMetric)->tmd.fl & TMD_NONNEGATIVE_AC) || (IS_ANY_DBCS_CHARSET(lpLogFont->elfLogFont.lfCharSet)) ) { DBGFONTS((" REJECT face (variable pitch, italic, or neg a&c)\n")); return bFindFaces ? TRUE : FALSE; // unsuitable font } if (nFontType == TRUETYPE_FONTTYPE) { lpLogFont->elfLogFont.lfHeight = pfed->TTPointSize; lpLogFont->elfLogFont.lfWidth = 0; lpLogFont->elfLogFont.lfWeight = FW_NORMAL; } /* * 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) && ((lpLogFont->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN)) { DBGFONTS((" REJECT face (TT but not FF_MODERN)\n")); return bFindFaces ? TRUE : FALSE; // unsuitable font } /* * reject non-TT fonts that aren't OEM */ if ((nFontType != TRUETYPE_FONTTYPE) && (lpLogFont->elfLogFont.lfCharSet != OEM_CHARSET)) { DBGFONTS((" REJECT face (not TT nor OEM)\n")); return bFindFaces ? TRUE : FALSE; // unsuitable font } /* * Add or find the facename */ pFN = AddFaceNode(&gpFaceNames, pwszFace); if (pFN == NULL) { return FALSE; } if (bFindFaces) { if (nFontType == TRUETYPE_FONTTYPE) { DBGFONTS(("NEW TT FACE %ls\n", pwszFace)); pFN->dwFlag |= EF_TTFONT; } else if (nFontType == RASTER_FONTTYPE) { DBGFONTS(("NEW OEM FACE %ls\n",pwszFace)); pFN->dwFlag |= EF_OEMFONT; } return 0; } if (IS_BOLD(lpLogFont->elfLogFont.lfWeight)) { DBGFONTS2((" A bold font (weight %d)\n", lpLogFont->elfLogFont.lfWeight)); // return 0; } /* get font info */ SizeWant.Y = (SHORT)lpLogFont->elfLogFont.lfHeight; SizeWant.X = (SHORT)lpLogFont->elfLogFont.lfWidth; CreateBoldFont: lpLogFont->elfLogFont.lfQuality = NONANTIALIASED_QUALITY; hFont = CreateFontIndirectW(&lpLogFont->elfLogFont); ASSERT(hFont); if (!hFont) { DBGFONTS((" REJECT font (can't create)\n")); return 0; // same font in other sizes may still be suitable } DBGFONTS2((" hFont = %lx\n", hFont)); // // for reasons unbeknownst to me, removing this code causes GDI // to yack, claiming that the font is owned by another process. // SelectObject(hDC,hFont); if (!GetTextMetricsW(hDC, &tmi)) { tmi = *((LPTEXTMETRICW)lpTextMetric); } if (GetTextExtentPoint32W(hDC, L"0", 1, &Size)) { SizeActual.X = (SHORT)Size.cx; } else { SizeActual.X = (SHORT)(tmi.tmMaxCharWidth); } SizeActual.Y = (SHORT)(tmi.tmHeight + tmi.tmExternalLeading); DBGFONTS2((" actual size %d,%d\n", SizeActual.X, SizeActual.Y)); tmFamily = tmi.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; } DBGFONTS2((" SizeToShow = (%d,%d), SizeActual = (%d,%d)\n", SizeToShow.X, SizeToShow.Y, SizeActual.X, SizeActual.Y)); // there's a GDI bug - this assert fails occasionally //ASSERT (tmi.tmw.tmMaxCharWidth == lpTextMetric->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 lpTextMetric. * 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)); nFontNew = nFont; goto InsertNewFont; } } } // DBGFONTS((" SizeShown(%x) = (%d,%d)\n",nFont,SizeShown.X,SizeShown.Y)); if (SIZE_EQUAL(SizeShown, SizeToShow) && FontInfo[nFont].Family == tmFamily && FontInfo[nFont].Weight == tmi.tmWeight && wcscmp(FontInfo[nFont].FaceName, pwszFace) == 0) { /* * Already have this font */ DBGFONTS2((" Already have the font\n")); DeleteObject(hFont); pfed->ulFE |= FE_FONTOK; return TRUE; } 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)); nFontNew = nFont; goto InsertNewFont; } } /* * The font we are adding should be appended to the list, * since it is bigger (or equal) to the last one. */ nFontNew = (LONG)NumberOfFonts; InsertNewFont: // at nFontNew // ASSERT ((lpTextMetric->tmPitchAndFamily & 1) == 0); /* If we have to grow our font table, do it */ if (NumberOfFonts == FontInfoLength) { PFONT_INFO Temp; FontInfoLength += FONT_INCREMENT; Temp = (PFONT_INFO)HeapReAlloc(pConHeap,MAKE_TAG( FONT_TAG ),FontInfo,sizeof(FONT_INFO) * FontInfoLength); ASSERT(Temp); if (Temp == NULL) { FontInfoLength -= FONT_INCREMENT; return FALSE; } FontInfo = Temp; } if (nFontNew < (LONG)NumberOfFonts) { RtlMoveMemory(&FontInfo[nFontNew+1], &FontInfo[nFontNew], sizeof(FONT_INFO)*(NumberOfFonts - nFontNew)); } /* * Store the font info */ FontInfo[nFontNew].hFont = hFont; FontInfo[nFontNew].Family = tmFamily; FontInfo[nFontNew].Size = SizeActual; if (TM_IS_TT_FONT(tmFamily)) { FontInfo[nFontNew].SizeWant = SizeWant; } else { FontInfo[nFontNew].SizeWant.X = 0; FontInfo[nFontNew].SizeWant.Y = 0; } FontInfo[nFontNew].Weight = tmi.tmWeight; FontInfo[nFont].FaceName = pFN->awch; ++NumberOfFonts; if (nFontType == TRUETYPE_FONTTYPE && !IS_BOLD(FontInfo[nFontNew].Weight)) { lpLogFont->elfLogFont.lfWeight = FW_BOLD; goto CreateBoldFont; } pfed->ulFE |= FE_FONTOK; // and continue enumeration return TRUE; }