//============================================================================== KERNINGPAIR* getKerningPairs (int& numKPs_) { if (kps == 0) { numKPs = GetKerningPairs (dc, 0, 0); kps.calloc (numKPs); GetKerningPairs (dc, numKPs, kps); } numKPs_ = numKPs; return kps; }
void createKerningPairs (HDC dc, const float height) { HeapBlock<KERNINGPAIR> rawKerning; const DWORD numKPs = GetKerningPairs (dc, 0, 0); rawKerning.calloc (numKPs); GetKerningPairs (dc, numKPs, rawKerning); kerningPairs.ensureStorageAllocated ((int) numKPs); for (DWORD i = 0; i < numKPs; ++i) { KerningPair kp; kp.glyph1 = getGlyphForChar (dc, rawKerning[i].wFirst); kp.glyph2 = getGlyphForChar (dc, rawKerning[i].wSecond); const int standardWidth = getGlyphWidth (dc, kp.glyph1); kp.kerning = (standardWidth + rawKerning[i].iKernAmount) / height; kerningPairs.add (kp); kp.glyph2 = -1; // add another entry for the standard width version.. kp.kerning = standardWidth / height; kerningPairs.add (kp); } }
bool CFont::Init() { HDC hDC = CreateCompatibleDC(0); int iXdpi, iYdpi; iXdpi = GetDeviceCaps(hDC, LOGPIXELSX); iYdpi = GetDeviceCaps(hDC, LOGPIXELSY); LOGFONT lf; lf.lfHeight = m_iSizePt * iYdpi / 72; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = FW_DONTCARE; lf.lfItalic = false; lf.lfUnderline = false; lf.lfStrikeOut = false; lf.lfCharSet = ANSI_CHARSET; lf.lfOutPrecision = OUT_TT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = ANTIALIASED_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; strcpy(lf.lfFaceName, m_sTypeface.m_pBuf); HFONT hFont = CreateFontIndirect(&lf); SelectObject(hDC, hFont); TEXTMETRIC tm; bool bRes; bRes = !!GetTextMetrics(hDC, &tm); m_iAscent = tm.tmAscent; m_iDescent = tm.tmDescent; m_iHeight = tm.tmHeight; m_iInternalLead = tm.tmInternalLeading; m_iExternalLead = tm.tmExternalLeading; m_iAverageWidth = tm.tmAveCharWidth; // m_iMaxWidth = tm.tmMaxCharWidth; m_iFirstChar = tm.tmFirstChar; int iChars = tm.tmLastChar - tm.tmFirstChar + 1; float fCols, fRows; ABC abc[MAX_CHARS]; bRes = !!GetCharABCWidths(hDC, tm.tmFirstChar, tm.tmLastChar, abc + tm.tmFirstChar); int i; m_iMaxWidth = 0; for (i = 0; i < tm.tmFirstChar; i++) m_Chars[i].ch = 0; while (i <= tm.tmLastChar) { m_Chars[i].ch = i; m_Chars[i].iA = abc[i].abcA; m_Chars[i].iB = abc[i].abcB; m_Chars[i].iC = abc[i].abcC; m_iMaxWidth = Util::Max(m_iMaxWidth, m_Chars[i].iB); i++; } while (i < MAX_CHARS) { m_Chars[i].ch = 0; i++; } int iKernPairs; KERNINGPAIR *pKernPairs; iKernPairs = GetKerningPairs(hDC, 0, 0); pKernPairs = new KERNINGPAIR[iKernPairs]; GetKerningPairs(hDC, iKernPairs, pKernPairs); for (i = 0; i < iKernPairs; i++) m_KerningPairs.Add(TKerningPair((char) pKernPairs[i].wFirst, (char) pKernPairs[i].wSecond, pKernPairs[i].iKernAmount)); delete [] pKernPairs; fRows = sqrt(iChars * m_iMaxWidth / (float) m_iHeight); fCols = fRows * m_iHeight / (float) m_iMaxWidth; m_iCellCols = (int) ceil(fCols); m_iCellRows = (int) ceil(fRows); if (m_iCellCols > m_iCellRows) { if (m_iCellCols * (m_iCellRows - 1) >= iChars) m_iCellRows--; } else if ((m_iCellCols - 1) * m_iCellRows >= iChars) m_iCellCols--; ASSERT(m_iCellRows * m_iCellCols >= iChars); BITMAPINFO bmi; bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = m_iCellCols * m_iMaxWidth; bmi.bmiHeader.biHeight = -m_iCellRows * m_iHeight; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 0; bmi.bmiHeader.biXPelsPerMeter = (int) (iXdpi / 2.54f * 100); bmi.bmiHeader.biYPelsPerMeter = (int) (iYdpi / 2.54f * 100); bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; HBITMAP hBmp = CreateDIBSection(hDC, &bmi, 0, 0, 0, 0); SelectObject(hDC, hBmp); HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0)); SelectObject(hDC, hBrush); Rectangle(hDC, 0, 0, m_iCellCols * m_iMaxWidth, m_iCellRows * m_iHeight); SetTextColor(hDC, RGB(255, 255, 255)); SetBkColor(hDC, RGB(0, 0, 0)); SetBkMode(hDC, TRANSPARENT); SetTextAlign(hDC, TA_TOP | TA_LEFT | TA_NOUPDATECP); for (int iRow = 0; iRow < m_iCellRows; iRow++) for (int iCol = 0; iCol < m_iCellCols; iCol++) { RECT rc; char chBuf[2] = { m_iFirstChar + iRow * m_iCellCols + iCol, 0 }; if (!m_Chars[(uint8_t) chBuf[0]].ch) continue; rc.left = iCol * m_iMaxWidth - m_Chars[(uint8_t) chBuf[0]].iA; rc.top = iRow * m_iHeight; rc.right = rc.left + m_iMaxWidth; rc.bottom = rc.top + m_iHeight; // DrawText(hDC, chBuf, 1, &rc, DT_LEFT | DT_TOP); TextOut(hDC, rc.left, rc.top, chBuf, 1); } bRes = !!GdiFlush(); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = m_iCellCols * m_iMaxWidth; bmi.bmiHeader.biHeight = -m_iCellRows * m_iHeight; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 0; bmi.bmiHeader.biXPelsPerMeter = (int) (iXdpi / 2.54f * 100); bmi.bmiHeader.biYPelsPerMeter = (int) (iYdpi / 2.54f * 100); bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; int iSize = bmi.bmiHeader.biWidth * abs(bmi.bmiHeader.biHeight) * bmi.bmiHeader.biBitCount / 8; uint8_t *pBuf = new uint8_t[iSize]; bRes = !!GetDIBits(hDC, hBmp, 0, abs(bmi.bmiHeader.biHeight), pBuf, &bmi, DIB_RGB_COLORS); for (i = 0; i < iSize; i += 4) // Util::Swap(pBuf[i], pBuf[i + 2]); pBuf[i / 4] = pBuf[i]; m_pTexture = new CTexture(); bRes = m_pTexture->Init(bmi.bmiHeader.biWidth, abs(bmi.bmiHeader.biHeight), DXGI_FORMAT_R8_UNORM, 1, pBuf, bmi.bmiHeader.biWidth /* * bmi.bmiHeader.biBitCount / 8*/, 0); /* ID3D11Resource *pTexRes = 0; m_pTexture->m_pTextureView->GetResource(&pTexRes); D3DX11SaveTextureToFile(CGraphics::Get()->m_pDeviceContext, pTexRes, D3DX11_IFF_BMP, "font.bmp"); SAFE_RELEASE(pTexRes); */ delete [] pBuf; DeleteObject(hBrush); DeleteObject(hBmp); DeleteObject(hFont); DeleteDC(hDC); if (!InitModel()) return false; return true; }
int CFontGen::SaveFont(const char *szFile) { if( isWorking ) return -1; // The pages must be generated first if( !arePagesGenerated ) return -1; // Create a memory dc HDC dc = CreateCompatibleDC(0); HFONT font = CreateFont(0); HFONT oldFont = (HFONT)SelectObject(dc, font); // Determine the size needed for the char int height, base; TEXTMETRIC tm; GetTextMetrics(dc, &tm); // Round up to make sure fractional pixels are covered height = (int)ceil(float(tm.tmHeight)/aa); base = (int)ceil(float(tm.tmAscent)/aa); // Save the character attributes FILE *f; string filename = szFile; if( _stricmp(filename.substr(filename.length() - 4).c_str(), ".fnt") == 0 ) filename = filename.substr(0, filename.length() - 4); errno_t e = fopen_s(&f, (filename + ".fnt").c_str(), "wb"); if( e != 0 || f == 0 ) return -1; // Get the filename without path int r = filename.rfind('\\'); string filenameonly; if( r != -1 ) filenameonly = filename.substr(r+1); else filenameonly = filename; if( outBitDepth != 32 ) fourChnlPacked = false; int numPages = pages.size(); // Determine the number of digits needed for the page file id int numDigits = numPages > 1 ? int(log10(float(numPages-1))+1) : 1; if( fontDescFormat == 1 ) { fprintf(f, "<?xml version=\"1.0\"?>\r\n"); fprintf(f, "<font>\r\n"); fprintf(f, " <info face=\"%s\" size=\"%d\" bold=\"%d\" italic=\"%d\" charset=\"%s\" unicode=\"%d\" stretchH=\"%d\" smooth=\"%d\" aa=\"%d\" padding=\"%d,%d,%d,%d\" spacing=\"%d,%d\" outline=\"%d\"/>\r\n", fontName.c_str(), fontSize, isBold, isItalic, useUnicode ? "" : GetCharSetName(charSet).c_str(), useUnicode, scaleH, useSmoothing, aa, paddingUp, paddingRight, paddingDown, paddingLeft, spacingHoriz, spacingVert, outlineThickness); fprintf(f, " <common lineHeight=\"%d\" base=\"%d\" scaleW=\"%d\" scaleH=\"%d\" pages=\"%d\" packed=\"%d\" alphaChnl=\"%d\" redChnl=\"%d\" greenChnl=\"%d\" blueChnl=\"%d\"/>\r\n", int(ceilf(height*float(scaleH)/100.0f)), int(ceilf(base*float(scaleH)/100.0f)), outWidth, outHeight, numPages, fourChnlPacked, alphaChnl, redChnl, greenChnl, blueChnl); fprintf(f, " <pages>\r\n"); for( int n = 0; n < numPages; n++ ) fprintf(f, " <page id=\"%d\" file=\"%s_%0*d.%s\" />\r\n", n, filenameonly.c_str(), numDigits, n, textureFormat.c_str()); fprintf(f, " </pages>\r\n"); } else if( fontDescFormat == 0 ) { fprintf(f, "info face=\"%s\" size=%d bold=%d italic=%d charset=\"%s\" unicode=%d stretchH=%d smooth=%d aa=%d padding=%d,%d,%d,%d spacing=%d,%d outline=%d\r\n", fontName.c_str(), fontSize, isBold, isItalic, useUnicode ? "" : GetCharSetName(charSet).c_str(), useUnicode, scaleH, useSmoothing, aa, paddingUp, paddingRight, paddingDown, paddingLeft, spacingHoriz, spacingVert, outlineThickness); fprintf(f, "common lineHeight=%d base=%d scaleW=%d scaleH=%d pages=%d packed=%d alphaChnl=%d redChnl=%d greenChnl=%d blueChnl=%d\r\n", int(ceilf(height*float(scaleH)/100.0f)), int(ceilf(base*float(scaleH)/100.0f)), outWidth, outHeight, numPages, fourChnlPacked, alphaChnl, redChnl, greenChnl, blueChnl); for( int n = 0; n < numPages; n++ ) fprintf(f, "page id=%d file=\"%s_%0*d.%s\"\r\n", n, filenameonly.c_str(), numDigits, n, textureFormat.c_str()); } else { // Write the magic word and file version fwrite("BMF", 3, 1, f); fputc(3, f); // Write the info block #pragma pack(push) #pragma pack(1) struct infoBlock { int blockSize; unsigned short fontSize; char reserved :4; char bold :1; char italic :1; char unicode :1; char smooth :1; unsigned char charSet; unsigned short stretchH; char aa; unsigned char paddingUp; unsigned char paddingRight; unsigned char paddingDown; unsigned char paddingLeft; unsigned char spacingHoriz; unsigned char spacingVert; unsigned char outline; char fontName[1]; } info; #pragma pack(pop) info.blockSize = sizeof(info) + fontName.length() - 4; info.fontSize = fontSize; info.reserved = 0; info.bold = isBold; info.italic = isItalic; info.unicode = useUnicode; info.smooth = useSmoothing; info.charSet = charSet; info.stretchH = scaleH; info.aa = aa; info.paddingUp = paddingUp; info.paddingRight = paddingRight; info.paddingDown = paddingDown; info.paddingLeft = paddingLeft; info.spacingHoriz = spacingHoriz; info.spacingVert = spacingVert; info.outline = outlineThickness; fputc(1, f); fwrite(&info, sizeof(info)-1, 1, f); fwrite(fontName.c_str(), fontName.length()+1, 1, f); // Write the common block #pragma pack(push) #pragma pack(1) struct commonBlock { int blockSize; unsigned short lineHeight; unsigned short base; unsigned short scaleW; unsigned short scaleH; unsigned short pages; unsigned char packed:1; unsigned char reserved:7; unsigned char alphaChnl; unsigned char redChnl; unsigned char greenChnl; unsigned char blueChnl; } common; #pragma pack(pop) common.blockSize = sizeof(common) - 4; common.lineHeight = int(ceilf(height*float(scaleH)/100.0f)); common.base = int(ceilf(base*float(scaleH)/100.0f)); common.scaleW = outWidth; common.scaleH = outHeight; common.pages = numPages; common.reserved = 0; common.packed = fourChnlPacked; common.alphaChnl = alphaChnl; common.redChnl = redChnl; common.greenChnl = greenChnl; common.blueChnl = blueChnl; fputc(2, f); fwrite(&common, sizeof(common), 1, f); // Write the page block fputc(3, f); int size = (filenameonly.length() + numDigits + 2 + textureFormat.length() + 1)*numPages; fwrite(&size, sizeof(size), 1, f); for( int n = 0; n < numPages; n++ ) { fprintf(f, "%s_%0*d.%s", filenameonly.c_str(), numDigits, n, textureFormat.c_str()); fputc(0, f); } } const int maxChars = useUnicode ? maxUnicodeChar+1 : 256; // Count the number of characters that will be written int numChars = 0; int n; for( n = 0; n < maxChars; n++ ) if( chars[n] ) numChars++; if( invalidCharGlyph ) numChars++; if( fontDescFormat == 0 ) fprintf(f, "chars count=%d\r\n", numChars); else if( fontDescFormat == 1 ) fprintf(f, " <chars count=\"%d\">\r\n", numChars); else if( fontDescFormat == 2 ) { fputc(4, f); // Determine the size of this block int size = (4+2+2+2+2+2+2+2+1+1)*numChars; fwrite(&size, 4, 1, f); } if( invalidCharGlyph ) { if( fontDescFormat == 1 ) fprintf(f, " <char id=\"%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xoffset=\"%d\" yoffset=\"%d\" xadvance=\"%d\" page=\"%d\" chnl=\"%d\" />\r\n", -1, invalidCharGlyph->m_x, invalidCharGlyph->m_y, invalidCharGlyph->m_width, invalidCharGlyph->m_height, invalidCharGlyph->m_xoffset, invalidCharGlyph->m_yoffset, invalidCharGlyph->m_advance, invalidCharGlyph->m_page, invalidCharGlyph->m_chnl); else if( fontDescFormat == 0 ) fprintf(f, "char id=%-4d x=%-5d y=%-5d width=%-5d height=%-5d xoffset=%-5d yoffset=%-5d xadvance=%-5d page=%-2d chnl=%-2d\r\n", -1, invalidCharGlyph->m_x, invalidCharGlyph->m_y, invalidCharGlyph->m_width, invalidCharGlyph->m_height, invalidCharGlyph->m_xoffset, invalidCharGlyph->m_yoffset, invalidCharGlyph->m_advance, invalidCharGlyph->m_page, invalidCharGlyph->m_chnl); else { #pragma pack(push) #pragma pack(1) struct charBlock { DWORD id; WORD x; WORD y; WORD width; WORD height; short xoffset; short yoffset; short xadvance; char page; char channel; } charInfo; #pragma pack(pop) charInfo.id = -1; charInfo.x = invalidCharGlyph->m_x; charInfo.y = invalidCharGlyph->m_y; charInfo.width = invalidCharGlyph->m_width; charInfo.height = invalidCharGlyph->m_height; charInfo.xoffset = invalidCharGlyph->m_xoffset; charInfo.yoffset = invalidCharGlyph->m_yoffset; charInfo.xadvance = invalidCharGlyph->m_advance; charInfo.page = invalidCharGlyph->m_page; charInfo.channel = invalidCharGlyph->m_chnl; fwrite(&charInfo, sizeof(charInfo), 1, f); } } for( n = 0; n < maxChars; n++ ) { if( chars[n] ) { int page, chnl; page = chars[n]->m_page; chnl = chars[n]->m_chnl; if( fontDescFormat == 1 ) fprintf(f, " <char id=\"%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xoffset=\"%d\" yoffset=\"%d\" xadvance=\"%d\" page=\"%d\" chnl=\"%d\" />\r\n", n, chars[n]->m_x, chars[n]->m_y, chars[n]->m_width, chars[n]->m_height, chars[n]->m_xoffset, chars[n]->m_yoffset, chars[n]->m_advance, page, chnl); else if( fontDescFormat == 0 ) fprintf(f, "char id=%-4d x=%-5d y=%-5d width=%-5d height=%-5d xoffset=%-5d yoffset=%-5d xadvance=%-5d page=%-2d chnl=%-2d\r\n", n, chars[n]->m_x, chars[n]->m_y, chars[n]->m_width, chars[n]->m_height, chars[n]->m_xoffset, chars[n]->m_yoffset, chars[n]->m_advance, page, chnl); else { #pragma pack(push) #pragma pack(1) struct charBlock { DWORD id; WORD x; WORD y; WORD width; WORD height; short xoffset; short yoffset; short xadvance; char page; char channel; } charInfo; #pragma pack(pop) charInfo.id = n; charInfo.x = chars[n]->m_x; charInfo.y = chars[n]->m_y; charInfo.width = chars[n]->m_width; charInfo.height = chars[n]->m_height; charInfo.xoffset = chars[n]->m_xoffset; charInfo.yoffset = chars[n]->m_yoffset; charInfo.xadvance = chars[n]->m_advance; charInfo.page = page; charInfo.channel = chnl; fwrite(&charInfo, sizeof(charInfo), 1, f); } } } if( fontDescFormat == 1 ) fprintf(f, " </chars>\r\n"); // Save the kerning pairs as well vector<KERNINGPAIR> pairs; if( useUnicode ) { // TODO: How do I obtain the kerning pairs for // the characters in the higher planes? int num = GetKerningPairsW(dc, 0, 0); if( num > 0 ) { pairs.resize(num); GetKerningPairsW(dc, num, &pairs[0]); } } else { int num = GetKerningPairs(dc, 0, 0); if( num > 0 ) { pairs.resize(num); GetKerningPairs(dc, num, &pairs[0]); } } if( pairs.size() == 0 ) { // Build a list of all selected chars vector<UINT> chars; chars.reserve(GetNumCharsSelected()); for( UINT n = 0; n <= maxUnicodeChar; n++ ) { if( selected[n] ) { chars.push_back(n); if( chars.size() == GetNumCharsSelected() ) break; } } GetKerningPairsFromGPOS(dc, pairs, chars); } if( pairs.size() > 0 ) { // Count the number of kerning pairs int count = 0; for( unsigned int n = 0; n < pairs.size(); n++ ) { if( pairs[n].wFirst < maxChars && pairs[n].wSecond < maxChars && !disabled[pairs[n].wFirst] && !disabled[pairs[n].wSecond] && selected[pairs[n].wFirst] && selected[pairs[n].wSecond] && pairs[n].iKernAmount/aa ) { count++; } } if( fontDescFormat == 0 ) fprintf(f, "kernings count=%d\r\n", count); else if( fontDescFormat == 1 ) fprintf(f, " <kernings count=\"%d\">\r\n", count); else if( fontDescFormat == 2 ) { fputc(5, f); // Determine the size of the block int size = count*10; fwrite(&size, 4, 1, f); } } // It's been reported that for Chinese WinXP the kerning pairs for // non-unicode charsets may contain characters > 255, so we need to // filter for this. for( unsigned int n = 0; n < pairs.size(); n++ ) { if( pairs[n].wFirst < maxChars && pairs[n].wSecond < maxChars && !disabled[pairs[n].wFirst] && !disabled[pairs[n].wSecond] && selected[pairs[n].wFirst] && selected[pairs[n].wSecond] && pairs[n].iKernAmount/aa ) { if( fontDescFormat == 1 ) fprintf(f, " <kerning first=\"%d\" second=\"%d\" amount=\"%d\" />\r\n", pairs[n].wFirst, pairs[n].wSecond, pairs[n].iKernAmount/aa); else if( fontDescFormat == 0 ) fprintf(f, "kerning first=%-3d second=%-3d amount=%-4d\r\n", pairs[n].wFirst, pairs[n].wSecond, pairs[n].iKernAmount/aa); else { #pragma pack(push) #pragma pack(1) struct kerningBlock { DWORD first; DWORD second; short amount; } kerning; #pragma pack(pop) kerning.first = pairs[n].wFirst; kerning.second = pairs[n].wSecond; kerning.amount = pairs[n].iKernAmount/aa; fwrite(&kerning, sizeof(kerning), 1, f); } } } if( pairs.size() > 0 && fontDescFormat == 1 ) fprintf(f, " </kernings>\r\n"); if( fontDescFormat == 1 ) fprintf(f, "</font>\r\n"); fclose(f); SelectObject(dc, oldFont); DeleteObject(font); DeleteDC(dc); // Save the image file for( n = 0; n < (signed)pages.size(); n++ ) { string str = acStringFormat("%s_%0*d.%s", filename.c_str(), numDigits, n, textureFormat.c_str()); acImage::Image image; image.width = outWidth; image.height = outHeight; if( outBitDepth == 32 ) { image.pitch = image.width*4; image.format = acImage::PF_A8R8G8B8; } else { image.pitch = image.width; image.format = acImage::PF_A8; } image.data = new BYTE[image.pitch * image.height]; // Generate the output texture for saving pages[n]->GenerateOutputTexture(); cImage *page = pages[n]->GetPageImage(); if( outBitDepth == 8 ) { // Write image data for( int y = 0; y < outHeight; y++ ) { for( int x = 0; x < outWidth; x++ ) { DWORD pixel = page->pixels[y*outWidth + x]; image.data[y*image.pitch + x] = (BYTE)(pixel>>24); } } } else { // Write image data for( int y = 0; y < outHeight; y++ ) { for( int x = 0; x < outWidth; x++ ) { DWORD pixel = page->pixels[y*outWidth + x]; *(DWORD*)&image.data[y*image.pitch + x*4] = pixel; } } } if( textureFormat == "tga" ) acImage::SaveTga(str.c_str(), image); else if( textureFormat == "png" ) acImage::SavePng(str.c_str(), image); else if( textureFormat == "dds" ) acImage::SaveDds(str.c_str(), image, textureCompression); }
FONTENUMPROC FontFunc( LOGFONT *plf, TEXTMETRIC *ptm, int iType, FTPARAM *pftp ) { HFONT hf, hfOld; int cPair, // number of kerning pairs cPairCopied, // number of pairs coppied to buffer iSpace, // space between successive lines y; // current y-coordinate char ach[100]; // scratch space HBRUSH hbOld; TEXTMETRIC tm; y = 20; iSpace = (int) (ptm->tmHeight + ptm->tmExternalLeading); hf = CreateFontIndirect(plf); if (hf == 0) { DbgPrint("FontFunc -- CreateFontIndirect failed\n"); } hfOld = SelectObject(pftp->hdc,hf); if (hfOld == 0) { DbgPrint("FontFunc -- Select Object failed\n"); } cPair = GetKerningPairs(pftp->hdc, 0, (KERNINGPAIR*) NULL); if (cPair != 0) { HANDLE hMem; PVOID pvMem; hMem = LocalAlloc(LMEM_FIXED,cPair * sizeof(KERNINGPAIR)); if (hMem == 0) { DbgPrint("FontFunc -- LocalAlloc failed\n"); return(0); } if (hMem) { pvMem = LocalLock(hMem); if (pvMem == NULL) { DbgPrint("FontFunc -- LocalLock failed\n"); return(0); } if (pvMem != NULL) { KERNINGPAIR *pkpTooBig; KERNINGPAIR *pkp = (KERNINGPAIR*) pvMem; cPairCopied = GetKerningPairs(pftp->hdc, cPair, pkp); pkpTooBig = pkp + cPairCopied; hbOld = SelectObject(pftp->hdc,GetStockObject(WHITE_BRUSH)); PatBlt( pftp->hdc, pftp->prect->left, pftp->prect->top + y, pftp->prect->right - pftp->prect->left, pftp->prect->bottom - pftp->prect->top, PATCOPY ); SelectObject(pftp->hdc,hbOld); wsprintf(ach,"%s has %d kerning pairs",plf->lfFaceName,cPair); TextOut(pftp->hdc,0,y,ach,strlen(ach)); y += iSpace; wsprintf(ach," wFirst wSecond iKernAmount"); TextOut(pftp->hdc,0,y,ach,strlen(ach)); y += iSpace; while (pkp < pkpTooBig && (y + ptm->tmHeight < (int) pftp->prect->bottom)) { wsprintf( ach, " %-#6lx %-#6lx %d", pkp->wFirst, pkp->wSecond, pkp->iKernAmount ); TextOut(pftp->hdc,0,y,ach,strlen(ach)); y += iSpace; pkp += 1; } vSleep(1); } LocalUnlock(hMem); } } SelectObject(pftp->hdc,hfOld); DeleteObject(hf); UNREFERENCED_PARAMETER(iType); return(1); }