2025-04-27 07:49:33 -04:00

298 lines
7.8 KiB
C

/******************************Module*Header*******************************\
* Module Name: ftchar.c
*
* Test all the characters in a font at all sizes to see if any of them
* fault the system. This is meant to be a very long extensive test to
* validate a font in NT. Please add more tests if you like.
*
* Created: 22-Mar-1994 13:21:30
* Author: Patrick Haluptzok patrickh
*
* Copyright (c) 1993 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
// tt stuff
#include "tt.h"
#define SIZEOF_CMAPTABLE (3 * sizeof(uint16))
#define OFF_segCountX2 6
#define OFF_endCount 14
#define RIP(x) {DbgPrint(x); DbgBreakPoint();}
#define ASSERTGDI(x,y) if(!(x)) RIP(y)
/******************************Public*Routine******************************\
* BYTE * pjMapTable(FILEVIEW *pfvw)
*
* History:
* 25-Mar-1994 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BYTE * pjMapTable(sfnt_char2IndexDirectory * pcmap, BOOL *pbSymbol)
{
BYTE *pjMap = NULL;
sfnt_platformEntry * pplat, * pplatEnd;
if (pcmap->version != 0) // no need to swap bytes, 0 == be 0
{
DbgPrint("ft! CMAP version number\n");
return NULL;
}
// find the first sfnt_platformEntry with platformID == PLAT_ID_MS,
// if there was no MS mapping table, we are out of here.
pplat = &pcmap->platform[0];
pplatEnd = pplat + SWAPW(pcmap->numTables);
for ( ; pplat < pplatEnd; pplat++)
{
if ((pplat->platformID == 0x300) && (pplat->specificID == 0x100))
{
pjMap = (BYTE *)pcmap + SWAPL(pplat->offset);
*pbSymbol = FALSE;
break;
}
}
if (!pjMap)
{
// reinit and try as symbol font:
pplat = &pcmap->platform[0];
pplatEnd = pplat + SWAPW(pcmap->numTables);
for ( ; pplat < pplatEnd; pplat++)
{
if ((pplat->platformID == 0x300) && (pplat->specificID == 0x0000))
{
pjMap = (BYTE *)pcmap + SWAPL(pplat->offset);
*pbSymbol = TRUE;
break;
}
}
}
return pjMap;
}
void vTestChar(HWND hwnd)
{
CHOOSEFONT cf; /* common dialog box structure */
LOGFONT lf; /* logical-font structure */
HDC hdc; /* display DC handle */
HFONT hfont; /* new logical-font handle */
HFONT hfontOld; /* original logical-font handle */
COLORREF crOld; /* original text color */
UINT ulSize, ulSizeMax;
TEXTMETRICW tmw;
DWORD cjCMAP,cjCMAP1;
DWORD dwCMAP = 0;
BYTE *pjCMAP, *pjMap;
WCHAR wcFirst, wcLast;
uint16 * pstartCount, *ps, *pe, *peEnd;
uint16 * pendCount;
uint16 * pendCountEnd;
uint16 cRuns, cRunsDbg;
ULONG cGlyphs;
BOOL bSymbol;
WCHAR wcBias;
memcpy((char *)&dwCMAP, "cmap", 4);
cf.lStructSize = sizeof (CHOOSEFONT);
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_FORCEFONTEXIST;
cf.rgbColors = RGB(255, 0, 0);
cf.nFontType = SCREEN_FONTTYPE;
/*
* Display the dialog box, allow the user to
* choose a font, and render the text in the
* window with that selection.
*/
if (!ChooseFont(&cf))
{
DbgPrint("Font selection failed\n");
return;
}
hdc = GetDC(hwnd);
GdiSetBatchLimit(1);
crOld = SetTextColor(hdc, cf.rgbColors);
//!!!!!!!!!!!!!!!!!!
// Hack, the way to specify the size
ulSizeMax = labs(lf.lfHeight);
hfont = CreateFontIndirect(&lf);
hfontOld = SelectObject(hdc, hfont);
GetTextMetricsW(hdc,&tmw);
cjCMAP = GetFontData(hdc, dwCMAP,0,NULL,0);
if (cjCMAP == -1)
{
DbgPrint("ft:GetFontData, get size failed\n");
return;
}
if (!(pjCMAP = malloc(cjCMAP)))
{
DbgPrint("ft:malloc\n");
return;
}
cjCMAP1 = GetFontData(hdc, dwCMAP,0,pjCMAP,cjCMAP);
if ((cjCMAP1 == -1) || (cjCMAP != cjCMAP1))
{
DbgPrint("ft:GetFontData, get cmap table failed\n");
free(pjCMAP);
return;
}
// see if the unicode cmap table exists :
pjMap = pjMapTable((sfnt_char2IndexDirectory *)pjCMAP, &bSymbol);
if (!pjMap)
{
DbgPrint("ft: no Unicode cmap table failed\n");
free(pjCMAP);
return;
}
wcBias = (WCHAR)(bSymbol ? 0xf000 : 0);
SelectObject(hdc, hfontOld);
DeleteObject(hfont);
cRuns = BE_UINT16(pjMap + OFF_segCountX2) >> 1;
// get the pointer to the beginning of the array of endCount code points
pendCount = (uint16 *)(pjMap + OFF_endCount);
// the final endCode has to be 0xffff;
// if this is not the case, there is a bug in the tt file or in our code:
ASSERTGDI(pendCount[cRuns - 1] == 0xFFFF,
"TTFD! pendCount[cRuns - 1] != 0xFFFF\n");
// Get the pointer to the beginning of the array of startCount code points
// For resons known only to tt designers, startCount array does not
// begin immediately after the end of endCount array, i.e. at
// &pendCount[cRuns]. Instead, they insert an uint16 padding which has to
// set to zero and the startCount array begins after the padding. This
// padding in no way helps alignment of the structure
// ASSERTGDI(pendCount[cRuns] == 0, "TTFD!_padding != 0\n");
pstartCount = &pendCount[cRuns + 1];
// here we shall check if the last run is just a terminator for the
// array of runs or a real nontrivial run. If just a terminator, there is no
// need to report it. This will save some memory in the cache plus
// pifi->wcLast will represent the last glyph that is truly supported in
// font:
if ((pstartCount[cRuns-1] == 0xffff) && (cRuns > 1))
cRuns -= 1; // do not report trivial run
pendCountEnd = &pendCount[cRuns];
// print cmap table summary
// reset these for every size
DbgPrint("\n\n cmap table summary: cRuns = %ld\n\n", cRuns);
ps = pstartCount;
pe = pendCount;
peEnd = pendCountEnd;
cGlyphs = 0;
cRunsDbg = 0;
for ( ; pe < peEnd; ps++, pe++, cRunsDbg++) // loop over ranges
{
ULONG cGlyphsInRun;
wcFirst = SWAPW(*ps);
wcLast = SWAPW(*pe);
DbgPrint("Run %ld: wcFirst = %d, wcLast = %d \n",cRunsDbg,wcFirst,wcLast);
cGlyphsInRun = (ULONG)(wcLast - wcFirst + 1);
cGlyphs += cGlyphsInRun;
}
DbgPrint("Glyphs in font: %ld\n", cGlyphs);
// loop through the sizes:
for (ulSize = 1; ulSize < ulSizeMax; ulSize++)
{
lf.lfHeight = -(LONG)ulSize;
hfont = CreateFontIndirect(&lf);
hfontOld = SelectObject(hdc, hfont);
// DbgPrint("Doing size %ld pixels per Em\n", ulSize);
// reset these for every size
ps = pstartCount;
pe = pendCount;
peEnd = pendCountEnd;
cGlyphs = 0;
cRunsDbg = 0;
for ( ; pe < peEnd; ps++, pe++, cRunsDbg++) // loop over ranges
{
ULONG cGlyphsInRun;
WCHAR wc;
wcFirst = SWAPW(*ps);
wcLast = SWAPW(*pe);
cGlyphsInRun = (ULONG)(wcLast - wcFirst + 1);
cGlyphs += cGlyphsInRun;
for ( ; wcFirst <= wcLast; wcFirst++)
{
wc = wcFirst - wcBias;
if (!TextOutW(hdc,0,0,&wc,1))
{
DbgPrint("ft: Bad glyph 0x%d, size = %ld ppem\n",wcFirst,ulSize);
}
}
}
SelectObject(hdc, hfontOld);
DeleteObject(hfont);
}
ReleaseDC(hwnd, hdc);
free(pjCMAP);
}