Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2084 lines
60 KiB

/*++
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
pfmconv.c
Abstract:
Windows NT utilities to handle new font format
Environment:
Windows NT Universal printer driver
Revision History:
10/31/96 -eigos-
Created it.
--*/
#include "precomp.h"
//
// Internal macros
//
#define DRIVERINFO_VERSION_WIN31 0x0100
#define DRIVERINFO_VERSION_SIMULATE 0x0150
#define DRIVERINFO_VERSION 0x0200
#define FONT_SIM_NO_ITALIC 1
#define FONT_SIM_NO_BOLD 2
#define FONT_SIM_DJ_BOLD 4
//
// HP DeskJet permutation flags
//
#define HALF_PITCH 0x01
#define DOUBLE_PITCH 0x02
#define HALF_HEIGHT 0x04
#define MAKE_BOLD 0x08
#define BASE_BOLD_MASK 0x30
#define BASE_BOLD_SHIFT 4
#define BASE_BOLD_ADD_0 0x00
#define BASE_BOLD_ADD_1 0x10
#define BASE_BOLD_ADD_2 0x20
#define BASE_BOLD_ADD_3 0x30
// 6/6/97 yasuho: Some PFM have -1 value in wPrivateData.
#define DO_DJFONTSIMBOLD(pFInData) ((pFInData->DI.wPrivateData != 0xFFFF) && (pFInData->DI.wPrivateData & MAKE_BOLD))
#define DO_FONTSIM(pFInData) \
(((pFInData)->DI.sVersion == DRIVERINFO_VERSION_WIN31) || \
((pFInData)->DI.sVersion == DRIVERINFO_VERSION_SIMULATE) || \
IS_DBCSCHARSET((pFInData)->PFMH.dfCharSet) )
#define DWORD_ALIGN(p) ((((ULONG)(p)) + 3) & ~3)
#define IS_DBCSCTTTYPE(sCTT) \
( ((sCTT) == CTT_JIS78) \
|| ((sCTT) == CTT_JIS78_ANK) \
|| ((sCTT) == CTT_JIS83) \
|| ((sCTT) == CTT_JIS83_ANK) \
|| ((sCTT) == CTT_NS86) \
|| ((sCTT) == CTT_TCA) \
|| ((sCTT) == CTT_BIG5) \
|| ((sCTT) == CTT_ISC))
#define CTT_TYPE_TO_CHARSET(sCTT) \
(((sCTT) == CTT_JIS78) ? SHIFTJIS_CHARSET : \
(((sCTT) == CTT_JIS78_ANK) ? SHIFTJIS_CHARSET : \
(((sCTT) == CTT_JIS83) ? SHIFTJIS_CHARSET : \
(((sCTT) == CTT_JIS83_ANK) ? SHIFTJIS_CHARSET : \
(((sCTT) == CTT_NS86) ? CHINESEBIG5_CHARSET : \
(((sCTT) == CTT_TCA) ? CHINESEBIG5_CHARSET : \
(((sCTT) == CTT_BIG5) ? CHINESEBIG5_CHARSET : \
(((sCTT) == CTT_ISC) ? HANGEUL_CHARSET : 1))))))))
#define OUTPUT_VERBOSE 0x00000001
#define BBITS 8
#define DWBITS (BBITS * sizeof( DWORD ))
#define DW_MASK (DWBITS - 1)
//
// Definitions
//
extern DWORD gdwOutputFlags;
typedef VOID (*VPRINT) (char*,...);
//
// Internal function prorotypes
//
BOOL BCreateWidthTable( IN HANDLE, IN PWORD, IN WORD, IN WORD, IN PSHORT, OUT PWIDTHTABLE *, OUT PDWORD);
BOOL BCreateKernData( IN HANDLE, IN w3KERNPAIR*, IN DWORD, OUT PKERNDATA*, OUT PDWORD);
WORD WGetGlyphHandle(PUNI_GLYPHSETDATA, WORD);
PUNI_GLYPHSETDATA PGetDefaultGlyphset( IN HANDLE, IN WORD, IN WORD, IN DWORD);
LONG LCtt2Cc(IN SHORT, IN SHORT);
//
//
// PFM file handling functions
//
//
BOOL
BFontInfoToIFIMetric(
IN HANDLE hHeap,
IN FONTIN *pFInData,
IN PWSTR pwstrUniqNm,
IN DWORD dwCodePageOfFacenameConv,
IN OUT PIFIMETRICS *ppIFI,
IN OUT PDWORD pdwSize,
IN DWORD dwFlags)
/*++
Routine Description:
Convert the Win 3.1 format PFM data to NT's IFIMETRICS. This is
typically done before the minidrivers are built, so that they
can include IFIMETRICS, and thus have less work to do at run time.
Arguments:
pFInData - Font data info for conversion
pwstrUniqNm - Unique name component
Return Value:
TRUE if successfull, otherwise FALSE.
--*/
{
FONTSIM *pFontSim;
FONTDIFF *pfdiffBold = 0, *pfdiffItalic = 0, *pfdiffBoldItalic = 0;
PIFIEXTRA pIFIExtra;
FWORD fwdExternalLeading;
INT icWChar; /* Number of WCHARS to add */
INT icbAlloc; /* Number of bytes to allocate */
INT iI; /* Loop index */
INT iCount; /* Number of characters in Win 3.1 font */
WCHAR *pwchTmp; /* For string manipulations */
WCHAR awcAttrib[ 256 ]; /* Generate attributes + BYTE -> WCHAR */
BYTE abyte[ 256 ]; /* Used (with above) to get wcLastChar etc */
WORD fsFontSim = 0;
INT cFontDiff;
UINT uiCodePage;
CHARSETINFO ci;
//
// Calculate the size of three face names buffer
//
icWChar = 3 * strlen( pFInData->pBase + pFInData->PFMH.dfFace );
//
// Produce the desired attributes: Italic, Bold, Light etc.
// This is largely guesswork, and there should be a better method.
// Write out an empty string
//
awcAttrib[ 0 ] = L'\0';
awcAttrib[ 1 ] = L'\0';
if( pFInData->PFMH.dfItalic )
{
StringCchCatW( awcAttrib, CCHOF(awcAttrib), L" Italic" );
}
if( pFInData->PFMH.dfWeight >= 700 )
{
StringCchCatW( awcAttrib, CCHOF(awcAttrib), L" Bold" );
}
else if( pFInData->PFMH.dfWeight < 200 )
{
StringCchCatW( awcAttrib, CCHOF(awcAttrib), L" Light" );
}
//
// The attribute string appears in 3 entries of IFIMETRICS, so
// calculate how much storage this will take. NOTE THAT THE LEADING
// CHAR IN awcAttrib is NOT placed in the style name field, so we
// subtract one in the following formula to account for this.
//
if( awcAttrib[ 0 ] )
{
icWChar += 3 * wcslen( awcAttrib ) - 1;
}
//
// Should be printer name
//
icWChar += wcslen( pwstrUniqNm ) + 1;
//
// Terminating nulls
//
icWChar += 4;
//
// Total size of IFIMETRICS structure
//
icbAlloc = DWORD_ALIGN(sizeof( IFIMETRICS ) + sizeof( WCHAR ) * icWChar);
//
// For HeskJet font.
//
if (DO_DJFONTSIMBOLD(pFInData))
{
fsFontSim |= FONT_SIM_DJ_BOLD;
icbAlloc = DWORD_ALIGN(icbAlloc) +
DWORD_ALIGN(sizeof(FONTSIM)) +
DWORD_ALIGN(sizeof(FONTDIFF));
}
else
//
// For CJK font.
// Judge which font simulation to be enabled, then allocate the
// necessary storage.
//
if (DO_FONTSIM(pFInData) || pFInData->dwFlags & FLAG_FONTSIM)
{
cFontDiff = 4;
//
// Decide which attribute should be diabled. We won't simulate
// if the user does not desires it. We won't italicize in case
// it is an italic font, etc.
//
if ( pFInData->PFMH.dfItalic || (pFInData->DI.fCaps & DF_NOITALIC))
{
fsFontSim |= FONT_SIM_NO_ITALIC;
cFontDiff /= 2;
}
if( pFInData->PFMH.dfWeight >= 700 || (pFInData->DI.fCaps & DF_NO_BOLD))
{
fsFontSim |= FONT_SIM_NO_BOLD;
cFontDiff /= 2;
}
cFontDiff--;
if ( cFontDiff > 0)
{
icbAlloc = DWORD_ALIGN(icbAlloc);
icbAlloc += (DWORD_ALIGN(sizeof(FONTSIM)) +
cFontDiff * DWORD_ALIGN(sizeof(FONTDIFF)));
}
}
#if DBG
DbgPrint( "cFontDiff = %d", cFontDiff);
#endif
//
// IFIEXTRA
//
// Fill out IFIEXTRA.cig.
//
icbAlloc += sizeof(IFIEXTRA);
//
// Allocate memory
//
*ppIFI = (IFIMETRICS *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, icbAlloc);
*pdwSize = icbAlloc;
if (NULL == *ppIFI)
{
return FALSE;
}
(*ppIFI)->cjThis = icbAlloc;
(*ppIFI)->cjIfiExtra = 0;
//
// The family name: straight from the FaceName - no choice??
//
// -IFIMETRICS memory image-
// IFIMETRICS
// IFIEXTRA
// FamilyName
// StyleName
// FaceName
// UniqueName
//
pIFIExtra = (PIFIEXTRA)(*ppIFI + 1);
pIFIExtra->dpFontSig = 0;
pIFIExtra->cig = pFInData->PFMH.dfLastChar -
pFInData->PFMH.dfFirstChar + 1;
pIFIExtra->dpDesignVector = 0;
pIFIExtra->dpAxesInfoW = 0;
pwchTmp = (WCHAR*)((PBYTE)(*ppIFI + 1) + sizeof(IFIEXTRA));
(*ppIFI)->dpwszFamilyName = (PTRDIFF)((BYTE *)pwchTmp - (BYTE *)(*ppIFI));
if (dwCodePageOfFacenameConv)
uiCodePage = dwCodePageOfFacenameConv;
else
uiCodePage = UlCharsetToCodePage(pFInData->PFMH.dfCharSet);
DwCopyStringToUnicodeString( uiCodePage,
pFInData->pBase + pFInData->PFMH.dfFace,
pwchTmp,
icWChar);
pwchTmp += wcslen( pwchTmp ) + 1;
icWChar -= wcslen( pwchTmp ) + 1;
//
// Now the face name: we add bold, italic etc to family name
//
(*ppIFI)->dpwszFaceName = (PTRDIFF)((BYTE *)pwchTmp - (BYTE *)(*ppIFI));
DwCopyStringToUnicodeString( uiCodePage,
pFInData->pBase + pFInData->PFMH.dfFace,
pwchTmp,
icWChar);
StringCchCatW( pwchTmp, icWChar, awcAttrib );
//
// Now the unique name - well, sort of, anyway
//
icWChar -= (wcslen( pwchTmp ) + 1);
pwchTmp += wcslen( pwchTmp ) + 1; /* Skip what we just put in */
(*ppIFI)->dpwszUniqueName = (PTRDIFF)((BYTE *)pwchTmp - (BYTE *)(*ppIFI));
StringCchCopyW( pwchTmp, icWChar, pwstrUniqNm ); /* Append printer name for uniqueness */
StringCchCatW( pwchTmp, icWChar, L" " );
StringCchCatW( pwchTmp, icWChar, (PWSTR)((BYTE *)(*ppIFI) + (*ppIFI)->dpwszFaceName) );
/* Onto the attributes only component */
icWChar -= (wcslen( pwchTmp ) + 1);
pwchTmp += wcslen( pwchTmp ) + 1; /* Skip what we just put in */
(*ppIFI)->dpwszStyleName = (PTRDIFF)((BYTE *)pwchTmp - (BYTE *)(*ppIFI));
StringCchCatW( pwchTmp, icWChar, &awcAttrib[ 1 ] );
#if DBG
/*
* Check on a few memory sizes: JUST IN CASE.....
*/
if( (wcslen( awcAttrib ) * sizeof( WCHAR )) >= sizeof( awcAttrib ) )
{
DbgPrint( "BFontInfoToIFIMetrics: STACK CORRUPTED BY awcAttrib" );
HeapFree(hHeap, 0, (LPSTR)(*ppIFI) ); /* No memory leaks */
return FALSE;
}
if( ((BYTE *)(pwchTmp + wcslen( pwchTmp ) + 1)) > ((BYTE *)(*ppIFI) + icbAlloc) )
{
DbgPrint( "BFontInfoToIFIMetrics: IFIMETRICS overflow: Wrote to 0x%lx, allocated to 0x%lx\n",
((BYTE *)(pwchTmp + wcslen( pwchTmp ) + 1)),
((BYTE *)(*ppIFI) + icbAlloc) );
HeapFree(hHeap, 0, (LPSTR)(*ppIFI) ); /* No memory leaks */
return 0;
}
#endif
pwchTmp += wcslen( pwchTmp ) + 1; /* Skip what we just put in */
//
// For HeskJet font.
//
if (fsFontSim & FONT_SIM_DJ_BOLD)
{
pFontSim = (FONTSIM *)pwchTmp;
(*ppIFI)->dpFontSim = (PTRDIFF)((BYTE *)pFontSim - (BYTE *)(*ppIFI) );
pFontSim->dpBold = DWORD_ALIGN(sizeof(FONTSIM));
pfdiffBold = (FONTDIFF *)((BYTE *)pFontSim + pFontSim->dpBold);
pFontSim->dpItalic = 0;
pFontSim->dpBoldItalic = 0;
}
else
if ((DO_FONTSIM( pFInData ) || pFInData->dwFlags & FLAG_FONTSIM) && cFontDiff > 0)
//
// For CJK font.
// Judge which font simulation to be enabled, then allocate the
// necessary storage.
//
{
PTRDIFF dpTmp;
// n.b.: FONTSIM, FONTDIFF have to be dword-aligned
// pFontSim = (FONTSIM *)PtrToUlong(pwchTmp);
pFontSim = (FONTSIM *)pwchTmp;
(*ppIFI)->dpFontSim = (PTRDIFF)((BYTE *)pFontSim - (BYTE *)(*ppIFI) );
dpTmp = DWORD_ALIGN(sizeof(FONTSIM));
if (!(fsFontSim & FONT_SIM_NO_BOLD))
{
pFontSim->dpBold = dpTmp;
pfdiffBold = (FONTDIFF *)((BYTE *)pFontSim + dpTmp);
dpTmp += DWORD_ALIGN(sizeof(FONTDIFF));
if (!(fsFontSim & FONT_SIM_NO_ITALIC))
{
pFontSim->dpBoldItalic = dpTmp;
pfdiffBoldItalic = (FONTDIFF *)((BYTE *)pFontSim + dpTmp);
dpTmp += DWORD_ALIGN(sizeof(FONTDIFF));
}
}
else
if (!(fsFontSim & FONT_SIM_NO_ITALIC))
{
pFontSim->dpItalic = dpTmp;
pfdiffItalic = (FONTDIFF *)((BYTE *)pFontSim + dpTmp);
dpTmp += DWORD_ALIGN(sizeof(FONTDIFF));
}
pwchTmp = (WCHAR *)((BYTE *)pFontSim + dpTmp);
}
// check again...
if ((BYTE *)(pwchTmp) > ((BYTE *)(*ppIFI) + icbAlloc))
{
#if DBG
DbgPrint( "BFontInfoToIFIMetrics: IFIMETRICS overflow: Wrote to 0x%lx, allocated to 0x%lx\n",
((BYTE *)pwchTmp),
((BYTE *)(*ppIFI) + icbAlloc) );
#endif
HeapFree( hHeap, 0, (LPSTR)(*ppIFI) ); /* No memory leaks */
return 0;
}
{
int i;
(*ppIFI)->lEmbedId = 0;
(*ppIFI)->lItalicAngle = 0;
(*ppIFI)->lCharBias = 0;
(*ppIFI)->dpCharSets = 0; // no multiple charsets in rasdd fonts
}
(*ppIFI)->jWinCharSet = (BYTE)pFInData->PFMH.dfCharSet;
//
// If FE Ctt table is used, this overrides what defined in charset
//
if (IS_DBCSCTTTYPE(-(pFInData->DI.sTransTab)))
{
(*ppIFI)->jWinCharSet = CTT_TYPE_TO_CHARSET(-(pFInData->DI.sTransTab));
}
if( pFInData->PFMH.dfPixWidth )
{
(*ppIFI)->jWinPitchAndFamily |= FIXED_PITCH;
(*ppIFI)->flInfo |= (FM_INFO_CONSTANT_WIDTH | FM_INFO_OPTICALLY_FIXED_PITCH);
if(IS_DBCSCHARSET((*ppIFI)->jWinCharSet))
{
// it is too strict to call a DBCS font "fixed pitch" since it has
// both halfwidth glyphs and fullwidth glyphs.
(*ppIFI)->flInfo &= ~FM_INFO_CONSTANT_WIDTH;
(*ppIFI)->flInfo |= (FM_INFO_OPTICALLY_FIXED_PITCH |
FM_INFO_DBCS_FIXED_PITCH);
}
}
else
{
(*ppIFI)->jWinPitchAndFamily |= VARIABLE_PITCH;
if(IS_DBCSCHARSET((*ppIFI)->jWinCharSet))
{
// DBCS glyphs are always fixed pitch even if the SBCS part is
// variable pitch.
(*ppIFI)->flInfo |= FM_INFO_DBCS_FIXED_PITCH;
}
}
(*ppIFI)->jWinPitchAndFamily |= (((BYTE) pFInData->PFMH.dfPitchAndFamily) & 0xf0);
(*ppIFI)->usWinWeight = (USHORT)pFInData->PFMH.dfWeight;
//
// IFIMETRICS::flInfo
//
(*ppIFI)->flInfo |=
FM_INFO_TECH_BITMAP |
FM_INFO_1BPP |
FM_INFO_INTEGER_WIDTH |
FM_INFO_NOT_CONTIGUOUS |
FM_INFO_RIGHT_HANDED;
/*
* A scalable font? This happens when there is EXTTEXTMETRIC data,
* and that data has a min size different to the max size.
*/
if( pFInData->pETM &&
pFInData->pETM->emMinScale != pFInData->pETM->emMaxScale )
{
(*ppIFI)->flInfo |= FM_INFO_ISOTROPIC_SCALING_ONLY;
(*ppIFI)->fwdUnitsPerEm = pFInData->pETM->emMasterUnits;
}
else
{
(*ppIFI)->fwdUnitsPerEm =
(FWORD) (pFInData->PFMH.dfPixHeight - pFInData->PFMH.dfInternalLeading);
}
#ifndef PFM2UFM_SCALING_ANISOTROPIC
#define PFM2UFM_SCALING_ANISOTROPIC 1
#endif
#ifndef PFM2UFM_SCALING_ARB_XFORMS
#define PFM2UFM_SCALING_ARB_XFORMS 2
#endif
if ((*ppIFI)->flInfo & FM_INFO_ISOTROPIC_SCALING_ONLY) {
// Allow forcing non-standard scaling only if the
// font is already scalable.
if ((dwFlags & PFM2UFM_SCALING_ANISOTROPIC)) {
(*ppIFI)->flInfo &= ~FM_INFO_ISOTROPIC_SCALING_ONLY;
(*ppIFI)->flInfo |= FM_INFO_ANISOTROPIC_SCALING_ONLY;
(*ppIFI)->flInfo &= ~FM_INFO_ARB_XFORMS;
}
else if ((dwFlags & PFM2UFM_SCALING_ARB_XFORMS)) {
(*ppIFI)->flInfo &= ~FM_INFO_ISOTROPIC_SCALING_ONLY;
(*ppIFI)->flInfo &= ~FM_INFO_ANISOTROPIC_SCALING_ONLY;
(*ppIFI)->flInfo |= FM_INFO_ARB_XFORMS;
}
}
(*ppIFI)->fsSelection =
((pFInData->PFMH.dfItalic ) ? FM_SEL_ITALIC : 0) |
((pFInData->PFMH.dfUnderline ) ? FM_SEL_UNDERSCORE : 0) |
((pFInData->PFMH.dfStrikeOut ) ? FM_SEL_STRIKEOUT : 0) |
((pFInData->PFMH.dfWeight >= FW_BOLD ) ? FM_SEL_BOLD : 0) ;
(*ppIFI)->fsType = FM_NO_EMBEDDING;
(*ppIFI)->fwdLowestPPEm = 1;
/*
* Calculate fwdWinAscender, fwdWinDescender, fwdAveCharWidth, and
* fwdMaxCharInc assuming a bitmap where 1 font unit equals one
* pixel unit
*/
(*ppIFI)->fwdWinAscender = (FWORD)pFInData->PFMH.dfAscent;
(*ppIFI)->fwdWinDescender =
(FWORD)pFInData->PFMH.dfPixHeight - (*ppIFI)->fwdWinAscender;
(*ppIFI)->fwdMaxCharInc = (FWORD)pFInData->PFMH.dfMaxWidth;
(*ppIFI)->fwdAveCharWidth = (FWORD)pFInData->PFMH.dfAvgWidth;
fwdExternalLeading = (FWORD)pFInData->PFMH.dfExternalLeading;
//
// If the font was scalable, then the answers must be scaled up
// !!! HELP HELP HELP - if a font is scalable in this sense, then
// does it support arbitrary transforms? [kirko]
//
if( (*ppIFI)->flInfo & (FM_INFO_ISOTROPIC_SCALING_ONLY |
FM_INFO_ANISOTROPIC_SCALING_ONLY |
FM_INFO_ARB_XFORMS))
{
/*
* This is a scalable font: because there is Extended Text Metric
* information available, and this says that the min and max
* scale sizes are different: thus it is scalable! This test is
* lifted directly from the Win 3.1 driver.
*/
int iMU, iRel; /* Adjustment factors */
iMU = pFInData->pETM->emMasterUnits;
iRel = pFInData->PFMH.dfPixHeight;
(*ppIFI)->fwdWinAscender = ((*ppIFI)->fwdWinAscender * iMU) / iRel;
(*ppIFI)->fwdWinDescender = ((*ppIFI)->fwdWinDescender * iMU) / iRel;
(*ppIFI)->fwdMaxCharInc = ((*ppIFI)->fwdMaxCharInc * iMU) / iRel;
(*ppIFI)->fwdAveCharWidth = ((*ppIFI)->fwdAveCharWidth * iMU) / iRel;
fwdExternalLeading = (fwdExternalLeading * iMU) / iRel;
}
(*ppIFI)->fwdMacAscender = (*ppIFI)->fwdWinAscender;
(*ppIFI)->fwdMacDescender = - (*ppIFI)->fwdWinDescender;
(*ppIFI)->fwdMacLineGap = fwdExternalLeading;
(*ppIFI)->fwdTypoAscender = (*ppIFI)->fwdMacAscender;
(*ppIFI)->fwdTypoDescender = (*ppIFI)->fwdMacDescender;
(*ppIFI)->fwdTypoLineGap = (*ppIFI)->fwdMacLineGap;
// for Windows 3.1J compatibility
if(IS_DBCSCHARSET((*ppIFI)->jWinCharSet))
{
(*ppIFI)->fwdMacLineGap = 0;
(*ppIFI)->fwdTypoLineGap = 0;
}
if( pFInData->pETM )
{
/*
* Zero is a legitimate default for these. If 0, gdisrv
* chooses some default values.
*/
(*ppIFI)->fwdCapHeight = pFInData->pETM->emCapHeight;
(*ppIFI)->fwdXHeight = pFInData->pETM->emXHeight;
(*ppIFI)->fwdSubscriptYSize = pFInData->pETM->emSubScriptSize;
(*ppIFI)->fwdSubscriptYOffset = pFInData->pETM->emSubScript;
(*ppIFI)->fwdSuperscriptYSize = pFInData->pETM->emSuperScriptSize;
(*ppIFI)->fwdSuperscriptYOffset = pFInData->pETM->emSuperScript;
(*ppIFI)->fwdUnderscoreSize = pFInData->pETM->emUnderlineWidth;
(*ppIFI)->fwdUnderscorePosition = pFInData->pETM->emUnderlineOffset;
(*ppIFI)->fwdStrikeoutSize = pFInData->pETM->emStrikeOutWidth;
(*ppIFI)->fwdStrikeoutPosition = pFInData->pETM->emStrikeOutOffset;
}
else
{
/* No additional information, so do some calculations */
(*ppIFI)->fwdSubscriptYSize = (*ppIFI)->fwdWinAscender/4;
(*ppIFI)->fwdSubscriptYOffset = -((*ppIFI)->fwdWinAscender/4);
(*ppIFI)->fwdSuperscriptYSize = (*ppIFI)->fwdWinAscender/4;
(*ppIFI)->fwdSuperscriptYOffset = (3 * (*ppIFI)->fwdWinAscender)/4;
(*ppIFI)->fwdUnderscoreSize = (*ppIFI)->fwdWinAscender / 12;
if( (*ppIFI)->fwdUnderscoreSize < 1 )
(*ppIFI)->fwdUnderscoreSize = 1;
(*ppIFI)->fwdUnderscorePosition = -pFInData->DI.sUnderLinePos;
(*ppIFI)->fwdStrikeoutSize = (*ppIFI)->fwdUnderscoreSize;
(*ppIFI)->fwdStrikeoutPosition = (FWORD)pFInData->DI.sStrikeThruPos;
if( (*ppIFI)->fwdStrikeoutPosition < 1 )
(*ppIFI)->fwdStrikeoutPosition = ((*ppIFI)->fwdWinAscender + 2) / 3;
}
(*ppIFI)->fwdSubscriptXSize = (*ppIFI)->fwdAveCharWidth/4;
(*ppIFI)->fwdSubscriptXOffset = (3 * (*ppIFI)->fwdAveCharWidth)/4;
(*ppIFI)->fwdSuperscriptXSize = (*ppIFI)->fwdAveCharWidth/4;
(*ppIFI)->fwdSuperscriptXOffset = (3 * (*ppIFI)->fwdAveCharWidth)/4;
(*ppIFI)->chFirstChar = pFInData->PFMH.dfFirstChar;
(*ppIFI)->chLastChar = pFInData->PFMH.dfLastChar;
//
// We now do the conversion of these to Unicode. We presume the
// input is in the ANSI code page, and call the NLS converion
// functions to generate proper Unicode values.
//
iCount = pFInData->PFMH.dfLastChar - pFInData->PFMH.dfFirstChar + 1;
for( iI = 0; iI < iCount; ++iI )
abyte[ iI ] = iI + pFInData->PFMH.dfFirstChar;
DwCopyStringToUnicodeString( uiCodePage,
abyte,
awcAttrib,
iCount);
//
// Now fill in the IFIMETRICS WCHAR fields.
//
(*ppIFI)->wcFirstChar = 0xffff;
(*ppIFI)->wcLastChar = 0;
//
// Look for the first and last
//
for( iI = 0; iI < iCount; ++iI )
{
if( (*ppIFI)->wcFirstChar > awcAttrib[ iI ] )
(*ppIFI)->wcFirstChar = awcAttrib[ iI ];
if( (*ppIFI)->wcLastChar < awcAttrib[ iI ] )
(*ppIFI)->wcLastChar = awcAttrib[ iI ];
}
(*ppIFI)->wcDefaultChar = awcAttrib[ pFInData->PFMH.dfDefaultChar ];
(*ppIFI)->wcBreakChar = awcAttrib[ pFInData->PFMH.dfBreakChar ];
(*ppIFI)->chDefaultChar = pFInData->PFMH.dfDefaultChar + pFInData->PFMH.dfFirstChar;
(*ppIFI)->chBreakChar = pFInData->PFMH.dfBreakChar + pFInData->PFMH.dfFirstChar;
if( pFInData->PFMH.dfItalic )
{
//
// tan (17.5 degrees) = .3153
//
(*ppIFI)->ptlCaret.x = 3153;
(*ppIFI)->ptlCaret.y = 10000;
}
else
{
(*ppIFI)->ptlCaret.x = 0;
(*ppIFI)->ptlCaret.y = 1;
}
(*ppIFI)->ptlBaseline.x = 1;
(*ppIFI)->ptlBaseline.y = 0;
(*ppIFI)->ptlAspect.x = pFInData->PFMH.dfHorizRes;
(*ppIFI)->ptlAspect.y = pFInData->PFMH.dfVertRes;
(*ppIFI)->rclFontBox.left = 0;
(*ppIFI)->rclFontBox.top = (LONG) (*ppIFI)->fwdWinAscender;
(*ppIFI)->rclFontBox.right = (LONG) (*ppIFI)->fwdMaxCharInc;
(*ppIFI)->rclFontBox.bottom = - (LONG) (*ppIFI)->fwdWinDescender;
(*ppIFI)->achVendId[0] = 'U';
(*ppIFI)->achVendId[1] = 'n';
(*ppIFI)->achVendId[2] = 'k';
(*ppIFI)->achVendId[3] = 'n';
(*ppIFI)->cKerningPairs = 0;
(*ppIFI)->ulPanoseCulture = FM_PANOSE_CULTURE_LATIN;
(*ppIFI)->panose.bFamilyType = PAN_ANY;
(*ppIFI)->panose.bSerifStyle = PAN_ANY;
if(pFInData->PFMH.dfWeight >= FW_BOLD)
{
(*ppIFI)->panose.bWeight = PAN_WEIGHT_BOLD;
}
else if (pFInData->PFMH.dfWeight > FW_EXTRALIGHT)
{
(*ppIFI)->panose.bWeight = PAN_WEIGHT_MEDIUM;
}
else
{
(*ppIFI)->panose.bWeight = PAN_WEIGHT_LIGHT;
}
(*ppIFI)->panose.bProportion = PAN_ANY;
(*ppIFI)->panose.bContrast = PAN_ANY;
(*ppIFI)->panose.bStrokeVariation = PAN_ANY;
(*ppIFI)->panose.bArmStyle = PAN_ANY;
(*ppIFI)->panose.bLetterform = PAN_ANY;
(*ppIFI)->panose.bMidline = PAN_ANY;
(*ppIFI)->panose.bXHeight = PAN_ANY;
if (fsFontSim & FONT_SIM_DJ_BOLD)
{
FONTDIFF FontDiff;
SHORT sAddBold;
FontDiff.jReserved1 = 0;
FontDiff.jReserved2 = 0;
FontDiff.jReserved3 = 0;
FontDiff.bWeight = (*ppIFI)->panose.bWeight;
FontDiff.usWinWeight = (*ppIFI)->usWinWeight;
FontDiff.fsSelection = (*ppIFI)->fsSelection;
FontDiff.fwdAveCharWidth = (*ppIFI)->fwdAveCharWidth;
FontDiff.fwdMaxCharInc = (*ppIFI)->fwdMaxCharInc;
FontDiff.ptlCaret = (*ppIFI)->ptlCaret;
if (pfdiffBold)
{
sAddBold = (pFInData->DI.wPrivateData & BASE_BOLD_MASK) >>
BASE_BOLD_SHIFT;
*pfdiffBold = FontDiff;
pfdiffBold->bWeight = PAN_WEIGHT_BOLD;
pfdiffBold->fsSelection |= FM_SEL_BOLD;
pfdiffBold->usWinWeight = FW_BOLD;
pfdiffBold->fwdAveCharWidth += sAddBold;
pfdiffBold->fwdMaxCharInc += sAddBold;
}
}
else
if ( (DO_FONTSIM( pFInData ) || pFInData->dwFlags & FLAG_FONTSIM) &&
cFontDiff > 0 )
{
FONTDIFF FontDiff;
FontDiff.jReserved1 = 0;
FontDiff.jReserved2 = 0;
FontDiff.jReserved3 = 0;
FontDiff.bWeight = (*ppIFI)->panose.bWeight;
FontDiff.usWinWeight = (*ppIFI)->usWinWeight;
FontDiff.fsSelection = (*ppIFI)->fsSelection;
FontDiff.fwdAveCharWidth = (*ppIFI)->fwdAveCharWidth;
FontDiff.fwdMaxCharInc = (*ppIFI)->fwdMaxCharInc;
FontDiff.ptlCaret = (*ppIFI)->ptlCaret;
if (pfdiffBold)
{
*pfdiffBold = FontDiff;
pfdiffBold->bWeight = PAN_WEIGHT_BOLD;
pfdiffBold->fsSelection |= FM_SEL_BOLD;
pfdiffBold->usWinWeight = FW_BOLD;
pfdiffBold->fwdAveCharWidth += 1;
pfdiffBold->fwdMaxCharInc += 1;
}
if (pfdiffItalic)
{
*pfdiffItalic = FontDiff;
pfdiffItalic->fsSelection |= FM_SEL_ITALIC;
pfdiffItalic->ptlCaret.x = 1;
pfdiffItalic->ptlCaret.y = 2;
}
if (pfdiffBoldItalic)
{
*pfdiffBoldItalic = FontDiff;
pfdiffBoldItalic->bWeight = PAN_WEIGHT_BOLD;
pfdiffBoldItalic->fsSelection |= (FM_SEL_BOLD | FM_SEL_ITALIC);
pfdiffBoldItalic->usWinWeight = FW_BOLD;
pfdiffBoldItalic->fwdAveCharWidth += 1;
pfdiffBoldItalic->fwdMaxCharInc += 1;
pfdiffBoldItalic->ptlCaret.x = 1;
pfdiffBoldItalic->ptlCaret.y = 2;
}
}
return TRUE;
}
BOOL
BGetFontSelFromPFM(
HANDLE hHeap,
FONTIN *pFInData, // Access to font info, aligned
BOOL bSelect,
CMDSTRING *pCmdStr)
{
LOCD locd; // From originating data
CD *pCD, **ppCDTrg;
if (bSelect)
{
locd = pFInData->DI.locdSelect;
ppCDTrg = &pFInData->pCDSelectFont;
}
else
{
locd = pFInData->DI.locdUnSelect;
ppCDTrg = &pFInData->pCDUnSelectFont;
}
if( locd != 0xFFFFFFFF) // NOOCD
{
DWORD dwSize;
pCD = (CD *)(pFInData->pBase + locd);
//
// The data pointed at by pCD may not be aligned, so we copy
// it into a local structure. This local structure then allows
// us to determine how big the CD really is (using it's length field),
// so then we can allocate storage and copy as required.
//
//
// Allocate storage area in the heap
//
dwSize = pCD->wLength;
pCmdStr->pCmdString = (PBYTE)HeapAlloc( hHeap,
0,
(dwSize + 3) & ~0x3 );
if (NULL == pCmdStr->pCmdString)
//
// Check if HeapAlloc succeeded.
//
return FALSE;
pCmdStr->dwSize = dwSize;
CopyMemory((PBYTE)pCmdStr->pCmdString, (PBYTE)(pCD + 1), dwSize);
*ppCDTrg = pCD;
return TRUE;
}
pCmdStr->dwSize = 0;
return FALSE;
}
BOOL
BAlignPFM(
FONTIN *pFInData) // Has ALL we need!
/*++
Routine Description:
Convert the non-aligned windows format data into a properly
aligned structure for our use. Only some of the data is converted
here, since we are mostly interested in extracting the addresses
contained in these structures.
Arguments:
pFInData - pointer to FONTIN
Return Value:
TRUE if successfull, otherwise fail to convert.
--*/
{
BYTE *pb; /* Miscellaneous operations */
res_PFMHEADER *pPFM; /* The resource data format */
res_PFMEXTENSION *pR_PFME; /* Resource data PFMEXT format */
/*
* Align the PFMHEADER structure.
*/
pPFM = (res_PFMHEADER *)pFInData->pBase;
pFInData->PFMH.dfType = pPFM->dfType;
pFInData->PFMH.dfPoints = pPFM->dfPoints;
pFInData->PFMH.dfVertRes = pPFM->dfVertRes;
pFInData->PFMH.dfHorizRes = pPFM->dfHorizRes;
pFInData->PFMH.dfAscent = pPFM->dfAscent;
pFInData->PFMH.dfInternalLeading = pPFM->dfInternalLeading;
pFInData->PFMH.dfExternalLeading = pPFM->dfExternalLeading;
pFInData->PFMH.dfItalic = pPFM->dfItalic;
pFInData->PFMH.dfUnderline = pPFM->dfUnderline;
pFInData->PFMH.dfStrikeOut = pPFM->dfStrikeOut;
pFInData->PFMH.dfWeight = DwAlign2( pPFM->b_dfWeight );
pFInData->PFMH.dfCharSet = pPFM->dfCharSet;
pFInData->PFMH.dfPixWidth = pPFM->dfPixWidth;
pFInData->PFMH.dfPixHeight = pPFM->dfPixHeight;
pFInData->PFMH.dfPitchAndFamily = pPFM->dfPitchAndFamily;
pFInData->PFMH.dfAvgWidth = DwAlign2( pPFM->b_dfAvgWidth );
pFInData->PFMH.dfMaxWidth = DwAlign2( pPFM->b_dfMaxWidth );
pFInData->PFMH.dfFirstChar = pPFM->dfFirstChar;
pFInData->PFMH.dfLastChar = pPFM->dfLastChar;
pFInData->PFMH.dfDefaultChar = pPFM->dfDefaultChar;
pFInData->PFMH.dfBreakChar = pPFM->dfBreakChar;
pFInData->PFMH.dfWidthBytes = DwAlign2( pPFM->b_dfWidthBytes );
pFInData->PFMH.dfDevice = DwAlign4( pPFM->b_dfDevice );
pFInData->PFMH.dfFace = DwAlign4( pPFM->b_dfFace );
pFInData->PFMH.dfBitsPointer = DwAlign4( pPFM->b_dfBitsPointer );
pFInData->PFMH.dfBitsOffset = DwAlign4( pPFM->b_dfBitsOffset );
/*
* The PFMEXTENSION follows the PFMHEADER structure plus any width
* table info. The width table will be present if the PFMHEADER has
* a zero width dfPixWidth. If present, adjust the extension address.
*/
pb = pFInData->pBase + sizeof( res_PFMHEADER ); /* Size in resource data */
if( pFInData->PFMH.dfPixWidth == 0 )
{
pb += (pFInData->PFMH.dfLastChar - pFInData->PFMH.dfFirstChar + 2) *
sizeof( short );
}
pR_PFME = (res_PFMEXTENSION *)pb;
//
// Now convert the extended PFM data.
//
pFInData->PFMExt.dfSizeFields = pR_PFME->dfSizeFields;
pFInData->PFMExt.dfExtMetricsOffset = DwAlign4( pR_PFME->b_dfExtMetricsOffset );
pFInData->PFMExt.dfExtentTable = DwAlign4( pR_PFME->b_dfExtentTable );
pFInData->PFMExt.dfOriginTable = DwAlign4( pR_PFME->b_dfOriginTable );
pFInData->PFMExt.dfPairKernTable = DwAlign4( pR_PFME->b_dfPairKernTable );
pFInData->PFMExt.dfTrackKernTable = DwAlign4( pR_PFME->b_dfTrackKernTable );
pFInData->PFMExt.dfDriverInfo = DwAlign4( pR_PFME->b_dfDriverInfo );
pFInData->PFMExt.dfReserved = DwAlign4( pR_PFME->b_dfReserved );
CopyMemory( &pFInData->DI,
pFInData->pBase + pFInData->PFMExt.dfDriverInfo,
sizeof( DRIVERINFO ) );
//
// Also need to fill in the address of the EXTTEXTMETRIC. This
// is obtained from the extended PFM data that we just converted!
//
if( pFInData->PFMExt.dfExtMetricsOffset )
{
//
// This structure is only an array of shorts, so there is
// no alignment problem. However, the data itself is not
// necessarily aligned in the resource!
//
int cbSize;
BYTE *pbIn; /* Source of data to shift */
pbIn = pFInData->pBase + pFInData->PFMExt.dfExtMetricsOffset;
cbSize = DwAlign2( pbIn );
if( cbSize == sizeof( EXTTEXTMETRIC ) )
{
/* Simply copy it! */
CopyMemory( pFInData->pETM, pbIn, cbSize );
}
else
{
pFInData->pETM = NULL; /* Not our size, so best not use it */
}
}
else
{
pFInData->pETM = NULL; /* Is non-zero when passed in */
}
return TRUE;
}
BOOL
BGetWidthVectorFromPFM(
HANDLE hHeap,
FONTIN *pFInData, // Details of the current font
PSHORT *ppWidth,
PDWORD pdwSize)
{
//
// For debugging code, verify that we have a width table! Then,
// allocate memory and copy into it.
//
int icbSize; // Number of bytes required
if( pFInData->PFMH.dfPixWidth )
{
ERR(( "BGetWidthVectorFromPFM called for FIXED PITCH FONT\n" ));
return FALSE;
}
//
// There are LastChar - FirstChar width entries, plus the default
// char. And the widths are shorts.
//
icbSize = (pFInData->PFMH.dfLastChar - pFInData->PFMH.dfFirstChar + 2) *
sizeof( short );
*ppWidth = (PSHORT) HeapAlloc( hHeap, 0, icbSize );
*pdwSize = icbSize;
//
// If this is a bitmap font, then use the width table, but use
// the extent table (in PFMEXTENSION area) as these are ready to
// to scale.
//
if( *ppWidth )
{
BYTE *pb;
if( pFInData->pETM &&
pFInData->pETM->emMinScale != pFInData->pETM->emMaxScale &&
pFInData->PFMExt.dfExtentTable )
{
//
// Scalable, so use the extent table
//
pb = pFInData->pBase + pFInData->PFMExt.dfExtentTable;
}
else
{
//
// Not scalable
//
pb = pFInData->pBase + sizeof( res_PFMHEADER );
}
CopyMemory( *ppWidth, pb, icbSize );
}
else
{
ERR(( "GetWidthVec(): HeapAlloc( %ld ) fails\n", icbSize ));
return FALSE;
}
return TRUE;
}
BOOL
BGetKerningPairFromPFM(
HANDLE hHeap,
FONTIN *pFInData,
w3KERNPAIR **ppSrcKernPair)
{
if (pFInData->PFMExt.dfPairKernTable)
{
*ppSrcKernPair = (w3KERNPAIR*)(pFInData->pBase + pFInData->PFMExt.dfPairKernTable);
return TRUE;
}
return FALSE;
}
LONG
LCtt2Cc(
IN SHORT sTransTable,
IN SHORT sCharSet)
{
LONG lRet;
if (sTransTable > 0)
{
lRet = (LONG)sTransTable;
}
else
{
switch (sTransTable)
{
case CTT_CP437:
case CTT_CP850:
case CTT_CP863:
lRet = (LONG)sTransTable;
break;
case CTT_BIG5:
lRet = (LONG)CC_BIG5;
break;
case CTT_ISC:
lRet = (LONG)CC_ISC;
break;
case CTT_JIS78:
case CTT_JIS83:
lRet = (LONG)CC_JIS;
break;
case CTT_JIS78_ANK:
case CTT_JIS83_ANK:
lRet = (LONG)CC_JIS_ANK;
break;
case CTT_NS86:
lRet = (LONG)CC_NS86;
break;
case CTT_TCA:
lRet = (LONG)CC_TCA;
break;
default:
switch (sCharSet)
{
case SHIFTJIS_CHARSET:
lRet = CC_SJIS;
break;
case HANGEUL_CHARSET:
lRet = CC_WANSUNG;
break;
case GB2312_CHARSET:
lRet = CC_GB2312;
break;
case CHINESEBIG5_CHARSET:
lRet = CC_BIG5;
break;
default:
lRet = 0;
break;
}
break;
}
}
return lRet;
}
WORD
WGetGlyphHandle(
PUNI_GLYPHSETDATA pGlyph,
WORD wUnicode)
{
PGLYPHRUN pGlyphRun;
DWORD dwI;
WORD wGlyphHandle;
BOOL bFound;
pGlyphRun = (PGLYPHRUN)((PBYTE)pGlyph + pGlyph->loRunOffset);
wGlyphHandle = 0;
bFound = FALSE;
for (dwI = 0; dwI < pGlyph->dwRunCount; dwI ++)
{
if (pGlyphRun->wcLow <= wUnicode &&
wUnicode < pGlyphRun->wcLow + pGlyphRun->wGlyphCount)
{
//
// Glyph handle starting from ONE!
//
wGlyphHandle += wUnicode - pGlyphRun->wcLow + 1;
bFound = TRUE;
break;
}
wGlyphHandle += pGlyphRun->wGlyphCount;
pGlyphRun++;
}
if (!bFound)
{
//
// Couldn't find.
//
wGlyphHandle = 0;
}
return wGlyphHandle;
}
BOOL
BCreateWidthTable(
IN HANDLE hHeap,
IN PWORD pwGlyphHandleVector,
IN WORD wFirst,
IN WORD wLast,
IN PSHORT psWidthVectorSrc,
OUT PWIDTHTABLE *ppWidthTable,
OUT PDWORD pdwWidthTableSize)
{
struct {
WORD wGlyphHandle;
WORD wCharCode;
} GlyphHandleVectorTrg[256];
PWIDTHRUN pWidthRun;
DWORD loWidthTableOffset;
PWORD pWidth;
WORD wI, wJ;
WORD wHandle, wMiniHandle, wMiniHandleId, wRunCount;
//
// Sort in the order of Glyph Handle.
// Simple sort
// Basically it's not necessary to think about a performance.
//
// pwGlyphHandleVector 0 -> glyph handle of character code wFirst
// 1 -> glyph handle of character code wFirst + 1
// 2 -> glyph handle of character code wFirst + 2
// ...
//
// GlyphHandleVectorTrg 0 -> minimum glyph handle
// 1 -> second minimum glyph handle
// 2 -> third minimum glyph handle
//
for (wJ = 0; wJ <= wLast - wFirst; wJ++)
{
wMiniHandle = 0xFFFF;
wMiniHandleId = wFirst;
for (wI = wFirst ; wI <= wLast; wI++)
{
if (wMiniHandle > pwGlyphHandleVector[wI])
{
wMiniHandle = pwGlyphHandleVector[wI];
wMiniHandleId = wI;
}
}
pwGlyphHandleVector[wMiniHandleId] = 0xFFFF;
GlyphHandleVectorTrg[wJ].wGlyphHandle = wMiniHandle;
GlyphHandleVectorTrg[wJ].wCharCode = wMiniHandleId;
}
//
// Count Width run
//
wHandle = GlyphHandleVectorTrg[0].wGlyphHandle;
wRunCount = 1;
for (wI = 1; wI < wLast - wFirst + 1 ; wI++)
{
if (++wHandle != GlyphHandleVectorTrg[wI].wGlyphHandle)
{
wHandle = GlyphHandleVectorTrg[wI].wGlyphHandle;
wRunCount ++;
}
}
//
// Allocate WIDTHTABLE buffer
//
*pdwWidthTableSize = sizeof(WIDTHTABLE) +
(wRunCount - 1) * sizeof(WIDTHRUN) +
sizeof(SHORT) * wLast + 1 - wFirst;
*ppWidthTable = HeapAlloc(hHeap,
0,
*pdwWidthTableSize);
if (!*ppWidthTable)
{
*pdwWidthTableSize = 0;
return FALSE;
}
//
// Fill in a WIDTHTABLE
//
(*ppWidthTable)->dwSize = sizeof(WIDTHTABLE) +
sizeof(WIDTHRUN) * (wRunCount - 1) +
sizeof(SHORT) * (wLast + 1 - wFirst);
(*ppWidthTable)->dwRunNum = wRunCount;
loWidthTableOffset = sizeof(WIDTHTABLE) +
(wRunCount - 1) * sizeof(WIDTHRUN);
pWidth = (PWORD)((PBYTE)*ppWidthTable + loWidthTableOffset);
pWidthRun = (*ppWidthTable)->WidthRun;
wHandle =
pWidthRun[0].wStartGlyph = GlyphHandleVectorTrg[0].wGlyphHandle;
pWidthRun[0].loCharWidthOffset = loWidthTableOffset;
pWidthRun[0].wGlyphCount = 1;
wJ = 1;
wI = 0;
while (wI < wRunCount)
{
while (GlyphHandleVectorTrg[wJ].wGlyphHandle == ++wHandle)
{
pWidthRun[wI].wGlyphCount ++;
wJ ++;
};
wI++;
wHandle =
pWidthRun[wI].wStartGlyph = GlyphHandleVectorTrg[wJ].wGlyphHandle;
pWidthRun[wI].loCharWidthOffset = loWidthTableOffset;
pWidthRun[wI].wGlyphCount = 1;
loWidthTableOffset += sizeof(SHORT) *
pWidthRun[wI].wGlyphCount;
wJ ++;
}
for (wI = 0; wI < wLast + 1 - wFirst; wI ++)
{
pWidth[wI] = psWidthVectorSrc[GlyphHandleVectorTrg[wI].wCharCode-wFirst];
}
return TRUE;
}
BOOL
BCreateKernData(
HANDLE hHeap,
w3KERNPAIR *pKernPair,
DWORD dwCodePage,
PKERNDATA *ppKernData,
PDWORD pdwKernDataSize)
{
FD_KERNINGPAIR *pDstKernPair;
DWORD dwNumOfKernPair;
DWORD dwI, dwJ, dwId;
WORD wUnicode[2];
WCHAR wcMiniSecond, wcMiniFirst;
BYTE ubMultiByte[2];
BOOL bFound;
//
// Count kerning pairs
//
dwNumOfKernPair = 0;
while( pKernPair[dwNumOfKernPair].kpPair.each[0] != 0 &&
pKernPair[dwNumOfKernPair].kpPair.each[1] != 0 )
{
dwNumOfKernPair ++;
}
if (!dwNumOfKernPair)
{
*pdwKernDataSize = 0;
*ppKernData = NULL;
return TRUE;
}
//
// Allocate memory
//
*pdwKernDataSize = sizeof(FD_KERNINGPAIR) * dwNumOfKernPair;
pDstKernPair = HeapAlloc(hHeap,
HEAP_ZERO_MEMORY,
*pdwKernDataSize);
if (!pDstKernPair)
{
HeapDestroy(hHeap);
return FALSE;
}
//
// Convert kerning pair table from character code base to unicode base.
//
for (dwI = 0; dwI < dwNumOfKernPair; dwI ++)
{
ubMultiByte[0] = (BYTE)pKernPair->kpPair.each[0];
ubMultiByte[1] = (BYTE)pKernPair->kpPair.each[1];
MultiByteToWideChar(dwCodePage,
0,
(LPCSTR)ubMultiByte,
2,
(LPWSTR)wUnicode,
2);
pDstKernPair[dwI].wcFirst = wUnicode[0];
pDstKernPair[dwI].wcSecond = wUnicode[1];
pDstKernPair[dwI].fwdKern = pKernPair->kpKernAmount;
pKernPair++;
}
//
// Sort kerning pair table.
// An extra FD_KERNPAIR is allocated for the NULL sentinel
// (built into KERNDATA size)- it is zero'd by the HeapAlloc
//
*pdwKernDataSize += sizeof(KERNDATA);
(*ppKernData) = HeapAlloc(hHeap,
HEAP_ZERO_MEMORY,
*pdwKernDataSize);
if (*ppKernData == NULL)
{
HeapDestroy(hHeap);
return FALSE;
}
//
// Fill the final format of kerning pair.
//
(*ppKernData)->dwSize = *pdwKernDataSize;
(*ppKernData)->dwKernPairNum = dwNumOfKernPair;
for (dwI = 0; dwI < dwNumOfKernPair; dwI ++)
{
wcMiniSecond = 0xFFFF;
wcMiniFirst = 0xFFFF;
dwId = 0xFFFF;
bFound = FALSE;
for (dwJ = 0; dwJ < dwNumOfKernPair; dwJ ++)
{
if (pDstKernPair[dwJ].wcSecond < wcMiniSecond)
{
wcMiniSecond = pDstKernPair[dwJ].wcSecond;
wcMiniFirst = pDstKernPair[dwJ].wcFirst;
dwId = dwJ;
bFound = TRUE;
}
else
if (pDstKernPair[dwJ].wcSecond == wcMiniSecond)
{
if (pDstKernPair[dwJ].wcFirst < wcMiniFirst)
{
wcMiniFirst = pDstKernPair[dwJ].wcFirst;
dwId = dwJ;
bFound = TRUE;
}
}
}
if (bFound)
{
(*ppKernData)->KernPair[dwI].wcFirst = wcMiniFirst;
(*ppKernData)->KernPair[dwI].wcSecond = wcMiniSecond;
(*ppKernData)->KernPair[dwI].fwdKern =
pDstKernPair[dwId].fwdKern;
pDstKernPair[dwId].wcSecond = 0xFFFF;
pDstKernPair[dwId].wcFirst = 0xFFFF;
}
}
return TRUE;
}
BOOL
BConvertPFM2UFM(
HANDLE hHeap,
PBYTE pPFMData,
PUNI_GLYPHSETDATA pGlyph,
DWORD dwCodePage,
PFONTMISC pMiscData,
PFONTIN pFInData,
INT iGTTID,
PFONTOUT pFOutData,
DWORD dwFlags)
{
DWORD dwOffset;
DWORD dwI;
SHORT sWidthVectorSrc[256];
WORD awMtoUniDst[256];
WORD awGlyphHandle[256];
BYTE aubMultiByte[256];
//
// Zero out the header structure. This means we can ignore any
// irrelevant fields, which will then have the value 0, which is
// the value for not used.
//
pFInData->pBase = pPFMData;
if ( !BAlignPFM( pFInData))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// dwCodePage has to be same as pGlyph->loCodePageInfo->dwCodePage.
//
if (pGlyph && pGlyph->loCodePageOffset)
{
dwCodePage = ((PUNI_CODEPAGEINFO)((PBYTE)pGlyph +
pGlyph->loCodePageOffset))->dwCodePage;
}
else
{
pGlyph = PGetDefaultGlyphset(hHeap,
(WORD)pFInData->PFMH.dfFirstChar,
(WORD)pFInData->PFMH.dfLastChar,
dwCodePage);
}
if (NULL == pGlyph)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Fill in IFIMETRICS
//
if ( !BFontInfoToIFIMetric(hHeap,
pFInData,
pMiscData->pwstrUniqName,
pFInData->dwCodePageOfFacenameConv,
&pFOutData->pIFI,
&pFOutData->dwIFISize,
dwFlags))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (BGetKerningPairFromPFM(hHeap, pFInData, &pFInData->pKernPair))
{
if (!BCreateKernData(hHeap,
pFInData->pKernPair,
dwCodePage,
&pFOutData->pKernData,
&pFOutData->dwKernDataSize))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pFOutData->pIFI->cKerningPairs = pFOutData->pKernData->dwKernPairNum;
}
else
{
pFOutData->dwKernDataSize = 0;
pFOutData->pKernData = NULL;
}
BGetFontSelFromPFM(hHeap, pFInData, TRUE, &pFOutData->SelectFont);
BGetFontSelFromPFM(hHeap, pFInData, FALSE, &pFOutData->UnSelectFont);
if( pFInData->PFMH.dfPixWidth == 0 &&
BGetWidthVectorFromPFM(hHeap,
pFInData,
&(pFInData->psWidthTable),
&(pFInData->dwWidthTableSize)))
{
for (dwI = 0; dwI < 256; dwI++)
{
aubMultiByte[dwI] = (BYTE)dwI;
}
MultiByteToWideChar(dwCodePage,
0,
(LPCSTR)aubMultiByte,
256,
(LPWSTR)awMtoUniDst,
256 );
//
// Glyph handle base
//
for (dwI = (DWORD)pFInData->PFMH.dfFirstChar;
dwI <= (DWORD)pFInData->PFMH.dfLastChar;
dwI ++)
{
awGlyphHandle[dwI] = WGetGlyphHandle(pGlyph, awMtoUniDst[dwI]);
}
if (!BCreateWidthTable(hHeap,
awGlyphHandle,
(WORD)pFInData->PFMH.dfFirstChar,
(WORD)pFInData->PFMH.dfLastChar,
pFInData->psWidthTable,
&pFOutData->pWidthTable,
&pFOutData->dwWidthTableSize))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
else
{
pFOutData->dwWidthTableSize = 0;
pFOutData->pWidthTable = NULL;
}
//
// Fill in UNIFM
//
// Fix the ETM pointer, instead oi leaving it uninitialized.
pFOutData -> pETM = pFInData -> pETM;
pFOutData->UniHdr.dwSize = sizeof(UNIFM_HDR) +
DWORD_ALIGN(sizeof(UNIDRVINFO) +
pFOutData->SelectFont.dwSize +
pFOutData->UnSelectFont.dwSize) +
pFOutData->dwIFISize +
!!pFOutData -> pETM * sizeof(EXTTEXTMETRIC) +
pFOutData->dwWidthTableSize +
pFOutData->dwKernDataSize;
pFOutData->UniHdr.dwVersion = UNIFM_VERSION_1_0;
pFOutData->UniHdr.ulDefaultCodepage = dwCodePage;
pFOutData->UniHdr.lGlyphSetDataRCID = iGTTID;
pFOutData->UniHdr.loUnidrvInfo = sizeof(UNIFM_HDR);
pFOutData->UniHdr.loIFIMetrics = pFOutData->UniHdr.loUnidrvInfo +
DWORD_ALIGN(sizeof(UNIDRVINFO) +
pFOutData->SelectFont.dwSize +
pFOutData->UnSelectFont.dwSize);
dwOffset = pFOutData->UniHdr.loIFIMetrics + pFOutData->dwIFISize;
if (pFOutData->pETM)
{
pFOutData->UniHdr.loExtTextMetric = dwOffset;
dwOffset += sizeof(EXTTEXTMETRIC);
}
else
{
pFOutData->UniHdr.loExtTextMetric = 0;
}
if (pFOutData->dwWidthTableSize && pFOutData->pWidthTable)
{
pFOutData->UniHdr.loWidthTable = dwOffset;
dwOffset += pFOutData->dwWidthTableSize;
}
else
{
pFOutData->UniHdr.loWidthTable = 0;
}
if (pFOutData->dwKernDataSize && pFOutData->pKernData)
{
pFOutData->UniHdr.loKernPair = dwOffset;
}
else
{
pFOutData->UniHdr.loKernPair = 0;
}
memset(pFOutData->UniHdr.dwReserved, 0, sizeof pFOutData->UniHdr.dwReserved);
//
// Fill in DRIVERINFO
//
pFOutData->UnidrvInfo.dwSize = DWORD_ALIGN(sizeof(UNIDRVINFO) +
pFOutData->SelectFont.dwSize +
pFOutData->UnSelectFont.dwSize);
pFOutData->UnidrvInfo.flGenFlags = 0;
pFOutData->UnidrvInfo.wType = pFInData->DI.wFontType;
pFOutData->UnidrvInfo.fCaps = pFInData->DI.fCaps;
pFOutData->UnidrvInfo.wXRes = pFInData->PFMH.dfHorizRes;
pFOutData->UnidrvInfo.wYRes = pFInData->PFMH.dfVertRes;
pFOutData->UnidrvInfo.sYAdjust = pFInData->DI.sYAdjust;
pFOutData->UnidrvInfo.sYMoved = pFInData->DI.sYMoved;
pFOutData->UnidrvInfo.sShift = pFInData->DI.sShift;
pFOutData->UnidrvInfo.wPrivateData = pFInData->DI.wPrivateData;
if (pFOutData->pIFI->flInfo & (FM_INFO_ISOTROPIC_SCALING_ONLY |
FM_INFO_ANISOTROPIC_SCALING_ONLY |
FM_INFO_ARB_XFORMS) )
{
pFOutData->UnidrvInfo.flGenFlags |= UFM_SCALABLE;
}
dwOffset = sizeof(UNIDRVINFO);
if (pFOutData->SelectFont.dwSize != 0)
{
pFOutData->UnidrvInfo.SelectFont.loOffset = dwOffset;
pFOutData->UnidrvInfo.SelectFont.dwCount = pFOutData->SelectFont.dwSize;
dwOffset += pFOutData->SelectFont.dwSize;
}
else
{
pFOutData->UnidrvInfo.SelectFont.loOffset = (DWORD)0;
pFOutData->UnidrvInfo.SelectFont.dwCount = (DWORD)0;
}
if (pFOutData->UnSelectFont.dwSize != 0)
{
pFOutData->UnidrvInfo.UnSelectFont.loOffset = dwOffset;
pFOutData->UnidrvInfo.UnSelectFont.dwCount = pFOutData->UnSelectFont.dwSize;
dwOffset += pFOutData->UnSelectFont.dwSize;
}
else
{
pFOutData->UnidrvInfo.UnSelectFont.loOffset = (DWORD)0;
pFOutData->UnidrvInfo.UnSelectFont.dwCount = (DWORD)0;
}
memset(pFOutData->UnidrvInfo.wReserved, 0, sizeof pFOutData->UnidrvInfo.wReserved);
return TRUE;
}
PUNI_GLYPHSETDATA
PGetDefaultGlyphset(
IN HANDLE hHeap,
IN WORD wFirstChar,
IN WORD wLastChar,
IN DWORD dwCodePage)
{
PUNI_GLYPHSETDATA pGlyphSetData;
PGLYPHRUN pGlyphRun, pGlyphRunTmp;
DWORD dwcbBits, *pdwBits, dwNumOfRuns;
WORD wI, wNumOfHandle;
WCHAR awchUnicode[256], wchMax, wchMin;
BYTE aubAnsi[256];
BOOL bInRun;
DWORD dwGTTLen;
#ifdef BUILD_FULL_GTT
PUNI_CODEPAGEINFO pCPInfo;
PMAPTABLE pMap;
PTRANSDATA pTrans;
int i, j, k, m ;
WORD wUnicode ;
#endif
wNumOfHandle = wLastChar - wFirstChar + 1;
for( wI = wFirstChar; wI <= wLastChar; ++wI )
{
aubAnsi[wI - wFirstChar] = (BYTE)wI;
}
if( ! MultiByteToWideChar(dwCodePage,
0,
aubAnsi,
wNumOfHandle,
awchUnicode,
wNumOfHandle))
{
return NULL;
}
//
// Get min and max Unicode value
// Find the largest Unicode value, then allocate storage to allow us
// to create a bit array of valid unicode points. Then we can
// examine this to determine the number of runs.
//
for( wchMax = 0, wchMin = 0xffff, wI = 0; wI < wNumOfHandle; ++wI )
{
if( awchUnicode[ wI ] > wchMax )
wchMax = awchUnicode[ wI ];
if( awchUnicode[ wI ] < wchMin )
wchMin = awchUnicode[ wI ];
}
//
// Create Unicode bits table from CTT.
// Note that the expression 1 + wchMax IS correct. This comes about
// from using these values as indices into the bit array, and that
// this is essentially 1 based.
//
dwcbBits = (1 + wchMax + DWBITS - 1) / DWBITS * sizeof( DWORD );
if( !(pdwBits = (DWORD *)HeapAlloc( hHeap, 0, dwcbBits )) )
{
return FALSE; /* Nothing going */
}
ZeroMemory( pdwBits, dwcbBits );
//
// Set bits in this array corresponding to Unicode code points
//
for( wI = 0; wI < wNumOfHandle; ++wI )
{
pdwBits[ awchUnicode[ wI ] / DWBITS ]
|= (1 << (awchUnicode[ wI ] & DW_MASK));
}
//
// Count the number of run.
//
//
// Now we can examine the number of runs required. For starters,
// we stop a run whenever a hole is discovered in the array of 1
// bits we just created. Later we MIGHT consider being a little
// less pedantic.
//
bInRun = FALSE;
dwNumOfRuns = 0;
for( wI = 0; wI <= wchMax; ++wI )
{
if( pdwBits[ wI / DWBITS ] & (1 << (wI & DW_MASK)) )
{
/* Not in a run: is this the end of one? */
if( !bInRun )
{
/* It's time to start one */
bInRun = TRUE;
++dwNumOfRuns;
}
}
else
{
if( bInRun )
{
/* Not any more! */
bInRun = FALSE;
}
}
}
//
// 7. Allocate memory for GTT and begin to fill in its header.
//
dwGTTLen = sizeof(UNI_GLYPHSETDATA) + dwNumOfRuns * sizeof(GLYPHRUN) ;
#ifdef BUILD_FULL_GTT
dwGTTLen += sizeof(UNI_CODEPAGEINFO) + sizeof(MAPTABLE)
+ sizeof(TRANSDATA) * (wNumOfHandle - 1) ;
#endif
if( !(pGlyphSetData = (PUNI_GLYPHSETDATA)HeapAlloc(hHeap,
HEAP_ZERO_MEMORY,
dwGTTLen )) )
{
return FALSE;
}
#ifdef BUILD_FULL_GTT
pGlyphSetData->dwSize = dwGTTLen ;
pGlyphSetData->dwVersion = UNI_GLYPHSETDATA_VERSION_1_0 ;
pGlyphSetData->lPredefinedID = CC_NOPRECNV ;
pGlyphSetData->dwGlyphCount = wNumOfHandle ;
#endif
pGlyphSetData->dwRunCount = dwNumOfRuns;
pGlyphSetData->loRunOffset = sizeof(UNI_GLYPHSETDATA);
pGlyphRun = pGlyphRunTmp = (PGLYPHRUN)(pGlyphSetData + 1);
//
// 8. Create GLYPHRUN
//
bInRun = FALSE;
for (wI = 0; wI <= wchMax; wI ++)
{
if (pdwBits[ wI/ DWBITS ] & (1 << (wI & DW_MASK)) )
{
if (!bInRun)
{
bInRun = TRUE;
pGlyphRun->wcLow = wI;
pGlyphRun->wGlyphCount = 1;
}
else
{
pGlyphRun->wGlyphCount++;
}
}
else
{
if (bInRun)
{
bInRun = FALSE;
pGlyphRun++;
}
}
}
//
// 9. Create CODEPAGEINFO and set related GTT header fields.
//
#ifdef BUILD_FULL_GTT
pGlyphSetData->dwCodePageCount = 1 ;
pGlyphSetData->loCodePageOffset = pGlyphSetData->loRunOffset
+ dwNumOfRuns * sizeof(GLYPHRUN) ;
pCPInfo = (PUNI_CODEPAGEINFO)
((UINT_PTR) pGlyphSetData + pGlyphSetData->loCodePageOffset) ;
pCPInfo->dwCodePage = dwCodePage ;
pCPInfo->SelectSymbolSet.dwCount = pCPInfo->SelectSymbolSet.loOffset = 0 ;
pCPInfo->UnSelectSymbolSet.dwCount = pCPInfo->UnSelectSymbolSet.loOffset = 0 ;
//
// 10. Create MAPTABLE and set related GTT header fields.
//
pGlyphSetData->loMapTableOffset = pGlyphSetData->loCodePageOffset +
sizeof(UNI_CODEPAGEINFO) ;
pMap = (PMAPTABLE) ((UINT_PTR) pGlyphSetData + pGlyphSetData->loMapTableOffset) ;
pMap->dwSize = sizeof(MAPTABLE) + sizeof(TRANSDATA) * (wNumOfHandle - 1) ;
pMap->dwGlyphNum = wNumOfHandle ;
pTrans = (PTRANSDATA) &(pMap->Trans[0]) ;
pGlyphRun = pGlyphRunTmp ;
for (i = m = 0 ; i <= (int) pGlyphSetData->dwRunCount ; i++, pGlyphRun++) {
for (j = 0 ; j <= pGlyphRun->wGlyphCount ; j ++) {
wUnicode = pGlyphRun->wcLow + j ;
for (k = 0 ; k <= 255 ; k ++)
if (wUnicode == awchUnicode[k])
break ;
ASSERT(k < 256) ;
pTrans->uCode.ubCode = aubAnsi[k] ;
pTrans->ubCodePageID = 0 ;
pTrans->ubType = MTYPE_DIRECT ;
pTrans++;
} ;
m += pGlyphRun->wGlyphCount ;
} ;
ASSERT(m != wNumOfHandle) ;
#endif
return pGlyphSetData;
}