mirror of https://github.com/lianthony/NT4.0
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.
3472 lines
117 KiB
3472 lines
117 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: fontmap.cxx *
|
|
* *
|
|
* Routines for mapping fonts. *
|
|
* *
|
|
* Created: 17-Jun-1992 11:12:16 *
|
|
* Author: Kirk Olynyk [kirko] *
|
|
* *
|
|
* Copyright (c) 1992-1995 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
|
|
// external procedures from draweng.cxx
|
|
|
|
VOID vArctan(EFLOAT, EFLOAT,EFLOAT&, LONG&);
|
|
|
|
// external procedure from FONTSUB.CXX
|
|
|
|
extern "C" ULONG ulCharsetToCodePage(UINT uiCharSet);
|
|
extern "C" FONTSUB * pfsubAlternateFacename(PWCHAR);
|
|
extern BOOL gbDBCSCodePage;
|
|
|
|
/*** globals defined in this module ***/
|
|
|
|
#if DBG
|
|
#define DEBUG_SMALLSUBSTITUTION 0x80
|
|
FLONG gflFontDebug = 0;
|
|
|
|
PFE *ppfeBreak = 0;
|
|
LONG lDevFontThresh = FM_DEVICE_FONTS_ARE_BETTER_BELOW_THIS_SIZE;
|
|
#endif
|
|
|
|
PWSZ gpwszDefFixedSysFaceName = (PWSZ) L"FIXEDSYS";
|
|
|
|
#define WIN31_SMALL_WISH_HEIGHT 2
|
|
#define WIN31_SMALL_FONT_HEIGHT 3
|
|
|
|
PFE *gppfeMapperDefault = PPFENULL; // set to something meaningfule
|
|
// at boot by bInitSystemFont()
|
|
// in stockfnt.cxx
|
|
|
|
// Storage for static globals in MAPPER
|
|
|
|
PDWORD MAPPER::SignatureTable; // base of the signature table
|
|
PWCHAR MAPPER::FaceNameTable; // base of the face name table
|
|
BYTE MAPPER::DefaultCharset; // default charset is equivilent to this
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BYTE jMapCharset()
|
|
*
|
|
* This routine is stollen from Win95 code (converted from asm).
|
|
* It checks if a font supports a requested charset.
|
|
*
|
|
* History:
|
|
* 17-Jan-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BYTE jMapCharset(BYTE lfCharSet, IFIMETRICS *pifi)
|
|
{
|
|
// if only one charset supported in a font, this is the best match to
|
|
// the request that the font can offer.
|
|
|
|
// the check for FM_INFO_TECH_TYPE1 is a temporary hack until
|
|
// we add a new field to the IFI metrics for the Type1 font ID's
|
|
// [gerritv] 8-23-95
|
|
|
|
if (pifi->dpCharSets == 0)
|
|
{
|
|
return( pifi->jWinCharSet );
|
|
}
|
|
|
|
// this is what is meant by default_charset:
|
|
|
|
if (lfCharSet == DEFAULT_CHARSET)
|
|
{
|
|
lfCharSet = MAPPER::DefaultCharset;
|
|
}
|
|
|
|
// if several charsets are supported, let us check out
|
|
// if the requested one is one of them:
|
|
|
|
BYTE *ajCharSets = (BYTE *)pifi + pifi->dpCharSets;
|
|
BYTE *ajCharSetsEnd = ajCharSets + MAXCHARSETS;
|
|
|
|
for (BYTE *pjCharSets = ajCharSets; pjCharSets < ajCharSetsEnd; pjCharSets++)
|
|
{
|
|
if (*pjCharSets == lfCharSet)
|
|
{
|
|
return( lfCharSet );
|
|
}
|
|
if (*pjCharSets == DEFAULT_CHARSET) // terminator
|
|
{
|
|
return( ajCharSets[0] ); // the "best" supported char set
|
|
}
|
|
}
|
|
|
|
// never should have gotten here
|
|
|
|
RIP("FONT mapper: suspicious charset array\n");
|
|
return( ajCharSets[0] ); // the "best" supported char set
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* bInitMapper()
|
|
*
|
|
* This callback routine reads the default facename entries from the registry.
|
|
* The entries have a the following form:
|
|
*
|
|
* FontMapper
|
|
* FaceName1 = REG_DWORD FontSignature1
|
|
* FaceName2 = REG_DWORD FontSignature2
|
|
* .........
|
|
* Default = REG_DWORD Charset equivilent to default charset
|
|
*
|
|
* The FontSignature entry has the following format:
|
|
*
|
|
*
|
|
* |-----------------Used when fixed pitch is requested
|
|
* ||--------------- Used when FF_ROMAN is requested
|
|
* |||-------------- Used when vertical face is requested
|
|
* |||-------------- Used as first choice for BM font
|
|
* ||||------------- Used as second choice for BM font
|
|
* ||||
|
|
* |||| |------- Bits 0-7 Charset
|
|
* |||| |
|
|
* YYYYYYYYXXXXYYYYXXXXXXXX
|
|
*
|
|
* The bits specified by Y's are unused. Thus determine what face name is
|
|
* to be used by default, the mapper will create a signature based on pitch,
|
|
* family, charset, etc fields in the LOGFONT and then try to match it against
|
|
* the signature/facename pairs in the registry. Putting these values in
|
|
* the registry makes it possible add extra entries for other charsets such
|
|
* as Shift-JIS and Big-5.
|
|
*
|
|
*
|
|
* History:
|
|
* Thu 2-Jun-1994 16:42:11 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C"
|
|
NTSTATUS
|
|
DefaultFontQueryRoutine
|
|
(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
PREGREADER RegRead = (PREGREADER) Context;
|
|
|
|
|
|
if( !_wcsicmp( ValueName, L"DEFAULT" ) )
|
|
{
|
|
// The value "Default" is a special case.
|
|
// It doesn't refer to the facename and instead indicates
|
|
// which charset the default charset is equivilent to.
|
|
|
|
DWORD Data = *((DWORD*)ValueData);
|
|
RegRead->DefaultCharset = (BYTE) Data;
|
|
}
|
|
else if( RegRead->NextValue == NULL )
|
|
{
|
|
// If NextValue is NULL then this is the first pass
|
|
// of the enumeration and we are just figuring out
|
|
// the number of entries and size of buffer we
|
|
// will need.
|
|
|
|
RegRead->TableSize += ( wcslen(ValueName) + 1 ) * sizeof(WCHAR);
|
|
RegRead->NumEntries += 1;
|
|
}
|
|
else
|
|
{
|
|
// On this pass we are actually building up a table of
|
|
// signtures and face names to match them.
|
|
|
|
if( ValueType == REG_DWORD )
|
|
{
|
|
// move the font signature portion to the high word,
|
|
// the low word will store the offset to the facename
|
|
|
|
DWORD Data = (*((DWORD*)ValueData));
|
|
|
|
Data |= ( RegRead->NextFaceName - RegRead->FaceNameBase ) << 16;
|
|
|
|
*(RegRead->NextValue)++ = Data;
|
|
|
|
// We ignore the last character of the string
|
|
// if it is a number. This allows us to have
|
|
// multiple entries for the same face name like
|
|
// Roman0, Roman1, etc.
|
|
|
|
UINT ValueLen = wcslen(ValueName);
|
|
|
|
wcscpy( RegRead->NextFaceName, ValueName );
|
|
|
|
if( ValueName[ValueLen-1] >= (WCHAR) '0' &&
|
|
ValueName[ValueLen-1] <= (WCHAR) '9' )
|
|
{
|
|
ValueLen -= 1;
|
|
(RegRead->NextFaceName)[ValueLen] = (WCHAR) 0;
|
|
}
|
|
|
|
RegRead->NextFaceName += ValueLen+1;
|
|
|
|
// Finally update the number of entries
|
|
|
|
RegRead->NumEntries += 1;
|
|
}
|
|
else
|
|
{
|
|
WARNING("DefaultFontQueryRoutine:invalid registry entry\n");
|
|
return(!STATUS_SUCCESS);
|
|
}
|
|
}
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
/******************************Member*Function*****************************\
|
|
* vInitMapper()
|
|
*
|
|
* This funtion reads in the FontSignature/Default facenmame pairs from
|
|
* the registry. The format of these pairs is described in the comment
|
|
* for the DefaultFontQueryRoutine function. vInitMapper() is called once
|
|
* when winsrv is initialized.
|
|
*
|
|
* If there is an error in initialization the mapper can still work but just
|
|
* won't fill in default facenames properly and will perform considerably
|
|
* slower for requests in which no facename is specified or which an invalid
|
|
* facename is specified.
|
|
*
|
|
* History:
|
|
* Thu 2-Jun-1994 16:42:11 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vInitMapper()
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
DWORD Status;
|
|
REGREADER RegRead;
|
|
|
|
QueryTable[0].QueryRoutine = DefaultFontQueryRoutine;
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[0].Name = (PWSTR)NULL;
|
|
QueryTable[0].EntryContext = NULL;
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
QueryTable[0].DefaultData = NULL;
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
QueryTable[1].QueryRoutine = NULL;
|
|
QueryTable[1].Flags = 0;
|
|
QueryTable[1].Name = NULL;
|
|
|
|
RegRead.NumEntries = 0;
|
|
RegRead.TableSize = 0;
|
|
RegRead.NextValue = NULL;
|
|
|
|
MAPPER::SignatureTable = NULL;
|
|
MAPPER::FaceNameTable = NULL;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
|
|
L"FontMapper",
|
|
QueryTable,
|
|
&RegRead,
|
|
NULL );
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
MAPPER::SignatureTable = (PDWORD)
|
|
PALLOCMEM(RegRead.NumEntries * sizeof(DWORD) + RegRead.TableSize,'pamG');
|
|
|
|
if( MAPPER::SignatureTable == NULL )
|
|
{
|
|
WARNING("vInitMapper:Unable to allocate enough memory\n");
|
|
return;
|
|
}
|
|
|
|
// Set all the proper pointers in the REGREAD structure
|
|
// for the next pass of the enumeration to use.
|
|
|
|
RegRead.NextValue = MAPPER::SignatureTable;
|
|
RegRead.FaceNameBase = (PWCHAR) &(MAPPER::SignatureTable[RegRead.NumEntries]);
|
|
RegRead.NumEntries = 0;
|
|
RegRead.NextFaceName = RegRead.FaceNameBase;
|
|
|
|
// do the second pass of the enumeration
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
|
|
L"FontMapper",
|
|
QueryTable,
|
|
&RegRead,
|
|
NULL );
|
|
// we are done
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
MAPPER::FaceNameTable = RegRead.FaceNameBase;
|
|
MAPPER::DefaultCharset = RegRead.DefaultCharset;
|
|
|
|
return;
|
|
}
|
|
|
|
// else fall through to error warning and reset MAPPER::FaceNameTable
|
|
|
|
VFREEMEM(MAPPER::SignatureTable);
|
|
MAPPER::SignatureTable = NULL;
|
|
}
|
|
WARNING("vInitMapper:Error enumerating default face names\n");
|
|
}
|
|
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PWSZ FindFaceName
|
|
*
|
|
* This routine takes a signature (described above)
|
|
* and tries to find a defualt facename that matches it.
|
|
* If it doesn't find a match if will return a pointer
|
|
* to an empty string.
|
|
*
|
|
* History:
|
|
* Thu 2-Jun-1994 16:42:11 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PWSZ FindFaceName( DWORD Signature )
|
|
{
|
|
PDWORD SigPtr;
|
|
|
|
for( SigPtr = MAPPER::SignatureTable;
|
|
SigPtr < (PDWORD) MAPPER::FaceNameTable;
|
|
SigPtr += 1)
|
|
{
|
|
if( (*SigPtr & 0xFFFF ) == Signature )
|
|
{
|
|
return( MAPPER::FaceNameTable + (*SigPtr >> 16 & 0xFFFF ) );
|
|
}
|
|
}
|
|
|
|
// Return a pointer to an empty string. Nothing will match
|
|
// this causing us to fall through to a case where do a
|
|
// mapping which doesnt take face name into account.
|
|
|
|
return( (PWSZ) L"" );
|
|
}
|
|
|
|
|
|
|
|
/******************************Member*Function*****************************\
|
|
* MAPPER::MAPPER() *
|
|
* *
|
|
* History: *
|
|
* Tue 29-Dec-1992 09:22:31 by Kirk Olynyk [kirko] *
|
|
* Added back in the case for small font substitution. *
|
|
* *
|
|
* Fri 18-Dec-1992 22:43:09 -by- Charles Whitmer [chuckwh] *
|
|
* Slimmed it down by removing lots of structure copies. *
|
|
* *
|
|
* Tue 10-Dec-1991 12:45:41 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
MAPPER::MAPPER
|
|
(
|
|
XDCOBJ *pdcoSrc, // current DC
|
|
FLONG *pflSim_,
|
|
POINTL *pptlSim_,
|
|
FLONG *pflAboutMatch_,
|
|
const EXTLOGFONTW *pelfwWishSrc, // wish list in World Coordinates
|
|
PWSZ pwszFaceName_,
|
|
ULONG ulMaxPenaltySrc, // pruning criteria
|
|
BOOL bIndexFont_,
|
|
FLONG flOptions = 0
|
|
)
|
|
{
|
|
fl = 0;
|
|
ifio.vSet((IFIMETRICS*) NULL);
|
|
pdco = pdcoSrc;
|
|
pelfwWish = pelfwWishSrc;
|
|
pwszFaceName = pwszFaceName_;
|
|
ulMaxPenalty = ulMaxPenaltySrc;
|
|
bIndexFont = bIndexFont_;
|
|
|
|
ASSERTGDI(pdco && pelfwWish,"Bad call to MAPPER\n");
|
|
|
|
// to begin with use the lfCharSet value from the logfont, this may
|
|
// be latter replaced by the value from [font substitutes]
|
|
|
|
jMapCharSet = pelfwWish->elfLogFont.lfCharSet;
|
|
|
|
{
|
|
pflAboutMatch = pflAboutMatch_;
|
|
*pflAboutMatch = 0;
|
|
|
|
ppfeBest = (PFE*) NULL;
|
|
ulBestTime = ULONG_MAX;
|
|
pflSimBest = pflSim_;
|
|
pptlSimBest = pptlSim_;
|
|
|
|
*pflSimBest = 0;
|
|
pptlSimBest->x = 1;
|
|
pptlSimBest->y = 1;
|
|
}
|
|
|
|
// Is it a display DC or it's moral equivilent?
|
|
|
|
fl |= pdco->bPrinter() ? 0 : FM_BIT_DISPLAY_DC;
|
|
|
|
// Set the GM_COMPATIBLE bit.
|
|
//
|
|
// If we are playing a metafile , world to page transform may be set
|
|
// even if the graphics mode is COMPATIBLE, in which case the mapping
|
|
// will occur the same way as it would in the advanced mode case
|
|
// [bodind].
|
|
|
|
if
|
|
(
|
|
(pdco->pdc->iGraphicsMode() == GM_COMPATIBLE) &&
|
|
(pdco->pdc->bWorldToPageIdentity() || !pdco->pdc->bUseMetaPtoD())
|
|
)
|
|
{
|
|
fl |= FM_BIT_GM_COMPATIBLE;
|
|
}
|
|
else
|
|
{
|
|
// If you are in advanced mode, then ignore the windows
|
|
// hack for stock fonts
|
|
|
|
flOptions &= ~FM_BIT_PIXEL_COORD;
|
|
}
|
|
|
|
if (pelfwWish->elfLogFont.lfQuality == PROOF_QUALITY)
|
|
{
|
|
fl |= FM_BIT_PROOF_QUALITY;
|
|
}
|
|
|
|
// The windows short circuit mapper doesn't get called
|
|
// when an a NULL facename is requested. In this case
|
|
// windows goes to the long mapper where a true type font
|
|
// will win over a raster font for some reason if the weight
|
|
// requested is FW_BOLD or FW_NORMAL. We on the other
|
|
// hand will give out a raster font in this case which
|
|
// causes CA Super Project to break. We mark this case
|
|
// here and fail bFindBitmapFont font when it occurs. [gerritv]
|
|
|
|
if( ( pelfwWish->elfLogFont.lfWeight == FW_NORMAL ) ||
|
|
( pelfwWish->elfLogFont.lfWeight == FW_BOLD ) )
|
|
{
|
|
fl |= FM_BIT_WEIGHT_NOT_FAST_BM;
|
|
}
|
|
|
|
// If the requested facename is Ms Shell Dlg then we wont
|
|
// worry about charset. This is a hack to make the shell
|
|
// work with other versions of Ms Sans Serif
|
|
// such as Greek [gerritv]
|
|
|
|
if( pwszFaceName[0] == U_LATIN_CAPITAL_LETTER_M &&
|
|
pwszFaceName[1] == U_LATIN_CAPITAL_LETTER_S &&
|
|
pwszFaceName[2] == U_SPACE &&
|
|
pwszFaceName[3] == U_LATIN_CAPITAL_LETTER_S &&
|
|
pwszFaceName[4] == U_LATIN_CAPITAL_LETTER_H &&
|
|
pwszFaceName[5] == U_LATIN_CAPITAL_LETTER_E &&
|
|
pwszFaceName[6] == U_LATIN_CAPITAL_LETTER_L &&
|
|
pwszFaceName[7] == U_LATIN_CAPITAL_LETTER_L &&
|
|
pwszFaceName[8] == U_SPACE &&
|
|
pwszFaceName[9] == U_LATIN_CAPITAL_LETTER_D &&
|
|
pwszFaceName[10] == U_LATIN_CAPITAL_LETTER_L &&
|
|
pwszFaceName[11] == U_LATIN_CAPITAL_LETTER_G &&
|
|
pwszFaceName[12] == U_NULL
|
|
)
|
|
{
|
|
fl |= FM_BIT_MS_SHELL_DLG;
|
|
}
|
|
else if
|
|
(
|
|
// If the requested facename is 'system' then Windows 3.1
|
|
// compatibilty requires that we treat this case specially
|
|
|
|
pwszFaceName[0] == U_LATIN_CAPITAL_LETTER_S &&
|
|
pwszFaceName[1] == U_LATIN_CAPITAL_LETTER_Y &&
|
|
pwszFaceName[2] == U_LATIN_CAPITAL_LETTER_S &&
|
|
pwszFaceName[3] == U_LATIN_CAPITAL_LETTER_T &&
|
|
pwszFaceName[4] == U_LATIN_CAPITAL_LETTER_E &&
|
|
pwszFaceName[5] == U_LATIN_CAPITAL_LETTER_M &&
|
|
pwszFaceName[6] == U_NULL
|
|
)
|
|
{
|
|
// record the fact that 'SYSTEM' has been requested
|
|
|
|
fl |= FM_BIT_SYSTEM_REQUEST;
|
|
|
|
// If the request was for a fixed pitch font, then the
|
|
// application really wants 'FIXEDSYS' instead
|
|
|
|
if ((pelfwWish->elfLogFont.lfPitchAndFamily & 0xF) == FIXED_PITCH)
|
|
{
|
|
pwszFaceName = gpwszDefFixedSysFaceName;
|
|
}
|
|
}
|
|
else if
|
|
(
|
|
pwszFaceName[0] == U_LATIN_CAPITAL_LETTER_T &&
|
|
pwszFaceName[1] == U_LATIN_CAPITAL_LETTER_M &&
|
|
pwszFaceName[2] == U_LATIN_CAPITAL_LETTER_S &&
|
|
pwszFaceName[3] == U_SPACE &&
|
|
pwszFaceName[4] == U_LATIN_CAPITAL_LETTER_R &&
|
|
pwszFaceName[5] == U_LATIN_CAPITAL_LETTER_M &&
|
|
pwszFaceName[6] == U_LATIN_CAPITAL_LETTER_N &&
|
|
pwszFaceName[7] == U_NULL
|
|
)
|
|
{
|
|
fl |= FM_BIT_TMS_RMN_REQUEST;
|
|
}
|
|
else if
|
|
(
|
|
// If the user requests symbol then he can goof up
|
|
// the character set. This was put in to allow
|
|
// "Spyglass Plot" to work See Bug #18228
|
|
|
|
pwszFaceName[0] == U_LATIN_CAPITAL_LETTER_S &&
|
|
pwszFaceName[1] == U_LATIN_CAPITAL_LETTER_Y &&
|
|
pwszFaceName[2] == U_LATIN_CAPITAL_LETTER_M &&
|
|
pwszFaceName[3] == U_LATIN_CAPITAL_LETTER_B &&
|
|
pwszFaceName[4] == U_LATIN_CAPITAL_LETTER_O &&
|
|
pwszFaceName[5] == U_LATIN_CAPITAL_LETTER_L
|
|
)
|
|
{
|
|
fl |= FM_BIT_CHARSET_ACCEPT;
|
|
}
|
|
#ifdef FE_SB
|
|
// If user requests vertical font. We have to map this logical font to vertical
|
|
// Physical font
|
|
else if
|
|
(
|
|
pwszFaceName[0] == U_COMMERCIAL_AT
|
|
)
|
|
{
|
|
fl |= FM_BIT_VERT_FACE_REQUEST;
|
|
}
|
|
#endif
|
|
|
|
// Copy over the requested sizes. We will transform them to device
|
|
// coordinates later if needed.
|
|
|
|
lDevWishHeight = pelfwWish->elfLogFont.lfHeight;
|
|
|
|
lDevWishWidth = ABS( pelfwWish->elfLogFont.lfWidth );
|
|
|
|
{
|
|
// Lock the PDEV to get some important information
|
|
|
|
PDEVOBJ pdo((HDEV)pdco->pdc->ppdev());
|
|
|
|
ulLogPixelsX = pdo.GdiInfo()->ulLogPixelsX;
|
|
ulLogPixelsY = pdo.GdiInfo()->ulLogPixelsY;
|
|
|
|
fl |= (pdo.GdiInfo()->flTextCaps & TC_RA_ABLE) ? FM_BIT_DEVICE_RA_ABLE : 0;
|
|
fl |= (pdo.GdiInfo()->flTextCaps & TC_CR_90) ? FM_BIT_DEVICE_CR_90_ALL : 0;
|
|
fl |= (pdo.cFonts()) ? FM_BIT_DEVICE_HAS_FONTS : 0;
|
|
fl |= (pdo.GdiInfo()->ulTechnology == DT_PLOTTER) ? FM_BIT_DEVICE_PLOTTER : 0;
|
|
fl |= (pdo.GdiInfo()->ulTechnology == DT_CHARSTREAM) ? FM_BIT_DEVICE_ONLY : 0;
|
|
|
|
ASSERTGDI(
|
|
!((pdo.GdiInfo()->ulTechnology == DT_PLOTTER) &&
|
|
(pdo.GdiInfo()->flTextCaps & TC_RA_ABLE)),
|
|
"winsrv!I didn't anticipate a plotter "
|
|
"that can handle bitmap fonts\n"
|
|
);
|
|
|
|
if (lDevWishHeight == 0)
|
|
{
|
|
// "If lfHeight is zero, a reasonable default size is
|
|
// substituted." [SDK Vol 2]. Fortunately, the
|
|
// device driver is kind enough to suggest a nice
|
|
// height (in pixels). We shall put this suggestion
|
|
// into lDefaultDeviceHeight
|
|
//
|
|
// NOTE:
|
|
//
|
|
// I have assumed that the suggested font height, as
|
|
// given in lDefaultDeviceHeight is in pixel units
|
|
|
|
lDevWishHeight = pdo.pdevinfo()->lfDefaultFont.lfHeight;
|
|
|
|
// Inform bCalculateWishCell that the height needs no transform.
|
|
|
|
fl |= FM_BIT_HEIGHT;
|
|
}
|
|
// At this point the PDEVOBJ passes out of scope and unlocks the PDEV
|
|
}
|
|
if (lDevWishHeight < 0)
|
|
{
|
|
fl |= FM_BIT_USE_EMHEIGHT;
|
|
lDevWishHeight *= -1;
|
|
}
|
|
|
|
// Cache the wish weight and assign default weight if
|
|
// no weight specified. (This way we don't have to
|
|
// compute this each time in msCheckFont. And we
|
|
// can't modify pelfwWish directly because it is
|
|
// declared "const").
|
|
|
|
lWishWeight = (LONG) pelfwWish->elfLogFont.lfWeight;
|
|
|
|
if( lWishWeight == FW_DONTCARE )
|
|
{
|
|
// if FW_DONTCARE then we compute penalities
|
|
// slightly differently so we keep track of this
|
|
|
|
fl |= FM_BIT_FW_DONTCARE ;
|
|
|
|
lWishWeight = FW_NORMAL;
|
|
}
|
|
|
|
// If the caller did not provide a face name, we provide a default.
|
|
|
|
if (pwszFaceName[0] == (WCHAR) 0)
|
|
{
|
|
bGetFaceName();
|
|
}
|
|
|
|
fl |= (flOptions & FM_ALLOWED_OPTIONS) | FM_BIT_STILL_ALIVE;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* BOOL bGetFaceName() *
|
|
* *
|
|
* Gets a face name when there is none *
|
|
* *
|
|
* Comments *
|
|
* *
|
|
* you got here because no facename was provided by *
|
|
* the user. At this point we shall select the font *
|
|
* based upon its height and pitch and family. First *
|
|
* we examine the height in device space. If the *
|
|
* height has been calculated already then the *
|
|
* FM_BIT_HEIGHT bit will have been set and no *
|
|
* calculation is needed. Otherwise we must *
|
|
* calculate the requested height in pixel unit. We *
|
|
* do this by calling off to *
|
|
* MAPPER::bCaluculateWishCell(). If this returns *
|
|
* with FALSE then the transformation was not *
|
|
* appropriate to a bitmap font and we can choose *
|
|
* only from TrueType defaults. If *
|
|
* MAPPER::bCalculateWishCell returns true then *
|
|
* this->lDevWishHeight has been calculated. At that *
|
|
* point we must see if it is in the range where the *
|
|
* 'small' fonts should be used, otherwise we must *
|
|
* default to the TrueType fonts. *
|
|
* *
|
|
* Returns: *
|
|
* The only situation for this function to return FALSE is if the *
|
|
* FM_BIT_DISABLE_TT_NAMES bit is set in the MAPPER state. When this *
|
|
* bit is set, the function may fail to find a suitable new facename *
|
|
* (because the catch-all of the TT core facenames is turned off). *
|
|
* *
|
|
* History: *
|
|
* *
|
|
* Thu 2-Jun-1994 16:42:11 by Gerrit van Wingerden [gerritv] *
|
|
* Rewrote it to get default facenames from the registry *
|
|
* Thu 11-Mar-1993 14:09:49 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL MAPPER::bGetFaceName()
|
|
{
|
|
BYTE Charset;
|
|
|
|
// if the default charset is specified then use the
|
|
// registry entry to determine what it really means
|
|
|
|
Charset = (jMapCharSet == DEFAULT_CHARSET) ?
|
|
MAPPER::DefaultCharset : jMapCharSet;
|
|
|
|
fl |= FM_BIT_CALLED_BGETFACENAME;
|
|
|
|
// compute the signature of the desired font
|
|
|
|
DWORD Signature = (DWORD) Charset;
|
|
|
|
if(( pelfwWish->elfLogFont.lfPitchAndFamily & (LOGFONT_PITCH_SET) ) == FIXED_PITCH )
|
|
{
|
|
Signature |= DFS_FIXED_PITCH;
|
|
}
|
|
#ifdef FE_SB
|
|
// This is probably my bug and should go into the U.S. build. It's too risky to
|
|
// do it now though so wait until after SUR ships.
|
|
;
|
|
#else
|
|
else
|
|
#endif
|
|
if(( pelfwWish->elfLogFont.lfPitchAndFamily & (FF_SET) ) == FF_ROMAN )
|
|
{
|
|
// the font family is only important for variable pitch fonts
|
|
|
|
Signature |= DFS_FF_ROMAN;
|
|
}
|
|
else
|
|
if(( pelfwWish->elfLogFont.lfPitchAndFamily & (LOGFONT_PITCH_SET) ) == DEFAULT_PITCH &&
|
|
( pelfwWish->elfLogFont.lfPitchAndFamily & (FF_SET) ) == FF_MODERN )
|
|
{
|
|
// Windows95 may sometimes chooses Courier instead of Courier New
|
|
|
|
Signature |= DFS_FIXED_PITCH;
|
|
}
|
|
|
|
#ifdef FE_SB
|
|
if( fl & FM_BIT_VERT_FACE_REQUEST )
|
|
{
|
|
Signature |= DFS_VERTICAL;
|
|
}
|
|
#endif
|
|
|
|
// In the case of the ANSI character set, we need to
|
|
// consider the possibility of using one of the small
|
|
// bitmap fonts. If this search is unsuccessful, we
|
|
// will fall into the default case, which chooses an
|
|
// appropriate TrueType font from the core set.
|
|
//
|
|
// The following set of conditions check to see if
|
|
// the requested height is so small so as to make
|
|
// TrueType fonts look awful. The only way to know
|
|
// is to calculate the wish cell by calling to
|
|
// bCalculateWishCell().
|
|
//
|
|
// bCalculateWishCell() will return FALSE if the font
|
|
// request is not suitable for a bitmap font. It
|
|
// turns out that this condition may be too
|
|
// stringent. Win 3.1 compatibility forces us to
|
|
// choose "Courier New" as the default small fixed
|
|
// pitch font. Thus, it is possible that
|
|
// bCalculateWishCell() would reject "Courier New" on
|
|
// the false premise that the transform is
|
|
// incompatible with all small fonts because they
|
|
// should be bitmap fonts. In any case, I will go
|
|
// with the follwing conditions until I am proven
|
|
// wrong. It is my belief that in such a case,
|
|
// "Courier New" will be picked up in the else
|
|
// clause.
|
|
|
|
if
|
|
(
|
|
( Charset == ANSI_CHARSET ) &&
|
|
(fl & FM_BIT_DEVICE_RA_ABLE ) &&
|
|
((fl & FM_BIT_CELL) ? TRUE : bCalculateWishCell() ) &&
|
|
((fl & FM_BIT_ORIENTATION) ? TRUE : bCalcOrientation() ) &&
|
|
(
|
|
iOrientationDevice == 0 * ORIENTATION_90_DEG ||
|
|
iOrientationDevice == 1 * ORIENTATION_90_DEG ||
|
|
iOrientationDevice == 2 * ORIENTATION_90_DEG ||
|
|
iOrientationDevice == 3 * ORIENTATION_90_DEG
|
|
)
|
|
)
|
|
{
|
|
// Note: If we break out of this switch, we will fall into
|
|
// the TT case below. We are writing it this way so that
|
|
// we can bail out of the "small font" case and into the TT
|
|
// case if we have to.
|
|
|
|
PWSZ pwszBitmap;
|
|
|
|
pwszBitmap = FindFaceName( Signature | DFS_BITMAP_A );
|
|
|
|
// Try the first choice
|
|
|
|
if ( bFindBitmapFont(pwszBitmap) )
|
|
{
|
|
pwszFaceName = pwszBitmap;
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("MAPPER::bGetFaceName() --> \"%ws\"\n", pwszFaceName);
|
|
}
|
|
#endif
|
|
return( TRUE );
|
|
}
|
|
|
|
// The first choice doesn't cut it, try the second choice
|
|
|
|
pwszBitmap = FindFaceName( Signature | DFS_BITMAP_B );
|
|
|
|
if ( bFindBitmapFont(pwszBitmap) )
|
|
{
|
|
pwszFaceName = pwszBitmap;
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("MAPPER::bGetFaceName() --> \"%ws\"\n", pwszFaceName);
|
|
}
|
|
#endif
|
|
return( TRUE );
|
|
}
|
|
|
|
// If we get to here, we couldn't find a suitable raster
|
|
// small font. If the FM_BIT_DISABLE_TT_NAMES flag is
|
|
// set, return error. Otherwise, fall into the TT facename
|
|
// substitution code below in the default case.
|
|
|
|
if (fl & FM_BIT_DISABLE_TT_NAMES)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("MAPPER::bGetFaceName() failed\n");
|
|
}
|
|
#endif
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
// find the face name
|
|
|
|
PWSZ pwszTemp = FindFaceName( Signature );
|
|
if (*pwszTemp || !(fl & FM_BIT_FACENAME_MATCHED))
|
|
{
|
|
// If a new name was found then it should be used. On the
|
|
// other hand, if a new name was not found then we must check
|
|
// to see if the face name as specified in the LOGFONT was
|
|
// ever found in the font tables. If the original face name
|
|
// was found then we should use it again, but this time
|
|
// allow character set mismatches. If the original name was
|
|
// not found in the font table then return a string of zero
|
|
// length causing the font mapper to fall into the emergency
|
|
// procedure.
|
|
|
|
pwszFaceName = pwszTemp;
|
|
}
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("MAPPER::bGetFaceName() --> \"%ws\"\n", pwszFaceName);
|
|
}
|
|
#endif
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL MAPPER::bFindBitmapFont *
|
|
* *
|
|
* The purpose of this function is to determine whether a bitmap font *
|
|
* with the given facename and EXACTLY the wish height exists. The *
|
|
* purpose is to support Windows 3.1 compatible "small font" behavior. *
|
|
* The Win 3.1 short circuit mapper (written by DavidW) forces mapping to *
|
|
* the either of the standard small fonts ("Small fonts" and "MS Serif") *
|
|
* only if the exact height requested exists. *
|
|
* *
|
|
* Returns: *
|
|
* TRUE if font found, otherwise FALSE. *
|
|
* *
|
|
* History: *
|
|
* 21-Apr-1993 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL MAPPER::bFindBitmapFont(PWSZ pwszFindFace)
|
|
{
|
|
PFE **pppfe;
|
|
HASHBUCKET *pbkt;
|
|
FONTHASHTYPE fht;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
// we need to fail at certain weights to insure Win 3.1 compatibility
|
|
|
|
if( fl & FM_BIT_WEIGHT_NOT_FAST_BM )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// We are only going to check the family table.
|
|
// This is a very specialized search, so if its
|
|
// not there it shouldn't be anywhere!
|
|
|
|
PUBLIC_PFTOBJ pfto;
|
|
FHOBJ fho(&pfto.pPFT->pfhFamily);
|
|
if (!fho.bValid())
|
|
{
|
|
return( bRet );
|
|
}
|
|
fht = fho.fht();
|
|
|
|
pbkt = fho.pbktSearch(pwszFindFace,(UINT*)NULL);
|
|
|
|
if (!pbkt)
|
|
{
|
|
FONTSUB* pfsub = pfsubAlternateFacename(pwszFindFace);
|
|
|
|
// only check "old style substitutions"
|
|
|
|
if (pfsub && (pfsub->fcsAltFace.fjFlags & FJ_NOTSPECIFIED))
|
|
{
|
|
pbkt = fho.pbktSearch((PWSZ)pfsub->fcsAltFace.awch,(UINT*)NULL);
|
|
}
|
|
}
|
|
|
|
if (!pbkt)
|
|
{
|
|
return( bRet );
|
|
}
|
|
|
|
// Scan the PFE list for an exact height match.
|
|
|
|
for
|
|
(
|
|
pppfe = &(pbkt->ppfeEnumHead);
|
|
*pppfe != PPFENULL;
|
|
)
|
|
{
|
|
PFEOBJ pfeo(*pppfe);
|
|
IFIOBJ ifio(pfeo.pifi());
|
|
|
|
if (ifio.bBitmap())
|
|
{
|
|
LONG lH;
|
|
|
|
lH = (fl & FM_BIT_USE_EMHEIGHT) ?
|
|
(LONG) ifio.fwdUnitsPerEm() : ifio.lfHeight();
|
|
if
|
|
(
|
|
lDevWishHeight == lH ||
|
|
( lDevWishHeight == WIN31_SMALL_WISH_HEIGHT
|
|
&& lH == WIN31_SMALL_FONT_HEIGHT
|
|
)
|
|
)
|
|
{
|
|
if (lDevWishWidth == 0 || lDevWishWidth == ifio.lfWidth())
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
pppfe = pfeo.pppfeEnumNext(fht);
|
|
}
|
|
|
|
return( bRet );
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* BOOL MAPPER::bCalcOrientation() *
|
|
* *
|
|
* History: *
|
|
* Tue 23-Mar-1993 22:24:19 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL MAPPER::bCalcOrientation()
|
|
{
|
|
INT s11,s12,s21,s22;
|
|
|
|
if (fl & FM_BIT_GM_COMPATIBLE)
|
|
{
|
|
// Taken from bGetNtoD_Win31()
|
|
// !!! should use common macro
|
|
|
|
iOrientationDevice = pelfwWish->elfLogFont.lfEscapement;
|
|
if (iOrientationDevice != 0)
|
|
{
|
|
if ( (pdco->pdc->bWorldToPageIdentity()) &&
|
|
(!(pdco->pdc->bPageToDeviceScaleIdentity())) &&
|
|
(pdco->pdc->efM11().lSignum() !=
|
|
pdco->pdc->efM22().lSignum()) )
|
|
{
|
|
iOrientationDevice = -iOrientationDevice;
|
|
}
|
|
}
|
|
fl |= FM_BIT_ORIENTATION;
|
|
return( TRUE );
|
|
}
|
|
else if (pdco->pdc->bWorldToDeviceIdentity() || (fl & FM_BIT_PIXEL_COORD))
|
|
{
|
|
iOrientationDevice = pelfwWish->elfLogFont.lfOrientation;
|
|
fl |= FM_BIT_ORIENTATION;
|
|
return( TRUE );
|
|
}
|
|
|
|
EXFORMOBJ xo(*pdco, WORLD_TO_DEVICE);
|
|
|
|
s11 = (INT) xo.efM11().lSignum();
|
|
s12 = (INT) xo.efM12().lSignum();
|
|
s21 = (INT) xo.efM21().lSignum();
|
|
s22 = (INT) xo.efM22().lSignum();
|
|
|
|
if (pdco->pdc->bYisUp())
|
|
{
|
|
s21 = -s21;
|
|
s22 = -s22;
|
|
}
|
|
|
|
if (pelfwWish->elfLogFont.lfOrientation % 900)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if
|
|
(
|
|
(s11 - s22) // Signs on diagonal must match.
|
|
| (s12 + s21) // Signs off diagonal must be opposite.
|
|
| ((s11^s12^1)&1) // Exactly one diagonal must be zero.
|
|
)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
iOrientationDevice =
|
|
pelfwWish->elfLogFont.lfOrientation
|
|
+ (s12 & 900)
|
|
+ (s11 & 1800)
|
|
+ (s21 & 2700);
|
|
|
|
if (iOrientationDevice >= 3600)
|
|
iOrientationDevice -= 3600;
|
|
|
|
fl |= FM_BIT_ORIENTATION;
|
|
return( TRUE );
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* MAPPER::bCalculateWishCell *
|
|
* *
|
|
* Calculates either the 'ascent' vector or 'width' vector of the font *
|
|
* in device space units. Then the equivalent 'height' and/or width *
|
|
* is filled in the the MAPPER::elfWishDevice fields. The height and width *
|
|
* are defined to be positive. *
|
|
* *
|
|
* Also computes the wished for orientation in device coordinates. *
|
|
* This is needed whenever the cell is needed! *
|
|
* *
|
|
* We use three flags which have the following meaning when set, and should *
|
|
* be used for no other purpose. *
|
|
* *
|
|
* FM_BIT_CELL Informs the world that bCalculateWishCell has *
|
|
* been called in the past, and successfully *
|
|
* transformed the height, width, and orientation *
|
|
* to device space. (OUTPUT) *
|
|
* *
|
|
* FM_BIT_BAD_WISH_CELL A flag internal to this function to tell it *
|
|
* that it has been called already and the *
|
|
* calculation failed. (INTERNAL) *
|
|
* *
|
|
* FM_BIT_HEIGHT Informs this function that the height is *
|
|
* already in device space. (INPUT) *
|
|
* *
|
|
* History: *
|
|
* Fri 18-Dec-1992 02:51:39 -by- Charles Whitmer [chuckwh] *
|
|
* Rewrote. Utilizing the assumption that it only gets called for raster *
|
|
* fonts, I was able to delete hundreds of lines of complex code! *
|
|
* *
|
|
* Mon 30-Dec-1991 14:35:22 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
LONG lNormAngle(LONG);
|
|
|
|
BOOL MAPPER::bCalculateWishCell()
|
|
{
|
|
INT s11,s12,s21,s22;
|
|
|
|
LONG lAngle = lNormAngle(pelfwWish->elfLogFont.lfOrientation);
|
|
|
|
// If we've failed here before, it's no better now!
|
|
|
|
if (fl & FM_BIT_BAD_WISH_CELL)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// Make sure we haven't been called before!
|
|
|
|
ASSERTGDI
|
|
(
|
|
(fl & FM_BIT_CELL) == 0,
|
|
"gdi!MAPPER::bCalculateWishCell: Useless call!\n"
|
|
);
|
|
|
|
// Handle the trivial case.
|
|
|
|
if (pdco->pdc->bWorldToDeviceIdentity() || (fl & FM_BIT_PIXEL_COORD))
|
|
{
|
|
iOrientationDevice = lAngle;
|
|
fl |= (FM_BIT_CELL | FM_BIT_HEIGHT | FM_BIT_WIDTH);
|
|
return( TRUE );
|
|
}
|
|
|
|
// Locate our transform and examine the matrix.
|
|
|
|
EXFORMOBJ xo(*pdco, WORLD_TO_DEVICE);
|
|
|
|
s11 = (INT) xo.efM11().lSignum();
|
|
s12 = (INT) xo.efM12().lSignum();
|
|
s21 = (INT) xo.efM21().lSignum();
|
|
s22 = (INT) xo.efM22().lSignum();
|
|
|
|
// Change to an equivalent transform where the y axis goes down.
|
|
// We remove a sign change from the matrix components that hit y.
|
|
|
|
if (pdco->pdc->bYisUp())
|
|
{
|
|
s21 = -s21;
|
|
s22 = -s22;
|
|
}
|
|
|
|
// If we are in GM_ADVANCED mode, make sure the orientation and transform
|
|
// are consistent with a bitmap font. In GM_COMPATIBLE mode, just ignore
|
|
// it all. Note that iOrientationDevice remains undefined in GM_COMPATIBLE
|
|
// mode.
|
|
|
|
if (!(fl & FM_BIT_GM_COMPATIBLE) && !(fl & FM_BIT_ORIENTATION))
|
|
{
|
|
// Reject random orientations. Even under simple
|
|
// scaling transforms, they don't transform well.
|
|
// (Assuming we're mapping to a raster font.)
|
|
|
|
if (lAngle % 900)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint(
|
|
"\tMAPPER::bCalculateWishCell detected a bad orientation\n");
|
|
}
|
|
#endif
|
|
fl |= FM_BIT_BAD_WISH_CELL;
|
|
return( FALSE );
|
|
}
|
|
|
|
// Examine the transform to see if it's a simple multiple of 90
|
|
// degrees rotation and perhaps some scaling.
|
|
|
|
// Check for parity flipping transforms which are not allowed.
|
|
// (That would require reflecting a bitmap, something we don't
|
|
// consider likely.) Also look for complex transforms.
|
|
|
|
// If any of the terms we OR together are non-zero,
|
|
// it's a bad transform.
|
|
|
|
if (
|
|
(s11 - s22) // Signs on diagonal must match.
|
|
| (s12 + s21) // Signs off diagonal must be opposite.
|
|
| ((s11^s12^1)&1) // Exactly one diagonal must be zero.
|
|
)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("\tMAPPER::bCalculateWishCell "
|
|
"detected a bad trasform -- returning FALSE");
|
|
DbgPrint("{%d,%d,%d,%d}\n",s11,s12,s21,s22);
|
|
}
|
|
#endif
|
|
fl |= FM_BIT_BAD_WISH_CELL;
|
|
return( FALSE );
|
|
}
|
|
|
|
// Since we've normalized to a space where (0 -1) represents
|
|
// a vector with a 90 degree orientation (like MM_TEXT) note
|
|
// that the matrix that rotates us by positive 90 degrees is:
|
|
//
|
|
// [ 0 -1 ]
|
|
// (0 -1) [ ] = (-1 0)
|
|
// [ 1 0 ]
|
|
//
|
|
// I.e. the one with M < 0. Knowing this, the rest is easy!
|
|
// 12
|
|
|
|
iOrientationDevice =
|
|
lAngle
|
|
+ (s12 & 900)
|
|
+ (s11 & 1800)
|
|
+ (s21 & 2700);
|
|
|
|
// Note that only the single 0xFFFFFFFF term contributes above.
|
|
|
|
if (iOrientationDevice >= 3600)
|
|
iOrientationDevice -= 3600;
|
|
|
|
fl |= FM_BIT_ORIENTATION;
|
|
}
|
|
|
|
// Transform the height to device coordinates.
|
|
|
|
if (!(fl & FM_BIT_HEIGHT))
|
|
{
|
|
// lDevWishHeight = lCvt(s22 ? xo.efM22() : xo.efM21(),lDevWishHeight);
|
|
|
|
if (s22)
|
|
lDevWishHeight = lCvt(xo.efM22(),lDevWishHeight);
|
|
else
|
|
lDevWishHeight = lCvt(xo.efM21(),lDevWishHeight);
|
|
|
|
if (lDevWishHeight < 0)
|
|
lDevWishHeight = -lDevWishHeight;
|
|
lDevWishHeight = LONG_FLOOR_OF_FIX(lDevWishHeight + FIX_HALF);
|
|
}
|
|
|
|
// Transform the width to device coordinates.
|
|
|
|
if (pelfwWish->elfLogFont.lfWidth && !(fl & FM_BIT_WIDTH))
|
|
{
|
|
// lDevWishWidth = lCvt(s11 ? xo.efM11() : xo.efM12(),lDevWishWidth);
|
|
|
|
if (s11)
|
|
lDevWishWidth = lCvt(xo.efM11(),lDevWishWidth);
|
|
else
|
|
lDevWishWidth = lCvt(xo.efM12(),lDevWishWidth);
|
|
|
|
if (lDevWishWidth < 0)
|
|
lDevWishWidth = -lDevWishWidth;
|
|
lDevWishWidth = LONG_FLOOR_OF_FIX(lDevWishWidth + FIX_HALF);
|
|
}
|
|
fl |= (FM_BIT_CELL | FM_BIT_HEIGHT | FM_BIT_WIDTH);
|
|
return( TRUE );
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* MAPPER::bNearMatch *
|
|
* *
|
|
* History: *
|
|
* Tue 28-Dec-1993 09:39:24 by Kirk Olynyk [kirko] *
|
|
* Changed the way msCheckFamily works for the case when the physical *
|
|
* font has FF_DONTCARE for the family *
|
|
* Fri 18-Dec-1992 23:19:09 -by- Charles Whitmer [chuckwh] *
|
|
* Simplified a lot of stuff and then pulled all the routines in line. *
|
|
* We were spending an extra 12 instructions per part checked by having *
|
|
* them out of line, which adds up to about half the time in this routine! *
|
|
* Tue 10-Dec-1991 11:33:28 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
int MAPPER::bNearMatch(PFEOBJ &pfeo, BYTE *pjCharSet)
|
|
{
|
|
int iRet = FALSE; // return value
|
|
ULONG ul; // Temp variable.
|
|
BYTE jAsk, jHav;
|
|
PFE *ppfeNew = pfeo.ppfeGet();
|
|
HPFE hpfeNew = (HPFE) ((pfeo.ppfeGet())->hGet());
|
|
|
|
// Clear the per-font status bits
|
|
|
|
fl &= ~(FM_BIT_NO_MAX_HEIGHT | FM_BIT_SYSTEM_FONT);
|
|
|
|
if (pfeo.ppfeGet() == gppfeMapperDefault)
|
|
{
|
|
fl |= FM_BIT_SYSTEM_FONT;
|
|
}
|
|
|
|
ifio.vSet(pfeo.pifi());
|
|
if (pfeo.bDead())
|
|
{
|
|
// The font is in a "ready to die" state. That is, the engine is
|
|
// ready to delete the font, but has had to delay it until all
|
|
// outstanding references (via RFONTs) has disappeared. Meanwhile,
|
|
// we must not allow enumeration or mapping to this font.
|
|
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint(
|
|
"msCheckFont is returning FM_REJECT because pfeo.bDead() is true\n");
|
|
}
|
|
#endif
|
|
|
|
ulPenaltyTotal = FM_REJECT;
|
|
return( iRet );
|
|
}
|
|
|
|
if (pfeo.bEmbedded())
|
|
{
|
|
// The font is embedded then it can only be seen if the call is
|
|
// Win 3.1 compatible (i.e. called by ppfeGetAMatch), the
|
|
// embedded bit is set in the caller's logical font, and the clients
|
|
// PID or TID matches that embeded in the *.fot file.
|
|
|
|
if (!(pelfwWish->elfLogFont.lfClipPrecision & CLIP_EMBEDDED) ||
|
|
( (ULONG)(pfeo.bPIDEmbedded() ? W32GetCurrentProcess() :
|
|
(PW32PROCESS) W32GetCurrentThread() ) != pfeo.ulEmbedID()))
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("msCheckFont is returning FM_REJECT\n");
|
|
DbgPrint("because the font is embedded\n\n");
|
|
}
|
|
#endif
|
|
|
|
ulPenaltyTotal = FM_REJECT;
|
|
return( iRet );
|
|
}
|
|
}
|
|
|
|
ulPenaltyTotal = 0;
|
|
|
|
// Assume be default that the font that is chosen will no have
|
|
// any bold or italic simulations
|
|
|
|
flSimulations = 0;
|
|
|
|
// Assume by default that if we happen to choose a bitmap font, there
|
|
// will be no streching in either the height-direction or width-direction
|
|
|
|
ptlSimulations.x = 1;
|
|
ptlSimulations.y = 1;
|
|
|
|
// At this point, the code used to have the following nice structure. For
|
|
// performance reasons, I pulled the code of each of these routines inline.
|
|
// Even so, the functionality of each of the following sections should
|
|
// remain clean and distinct. [chuckwh]
|
|
//
|
|
// if
|
|
// (
|
|
// (msCheckPitchAndFamily()) == MSTAT_NEAR &&
|
|
// (msCheckHeight() ) == MSTAT_NEAR &&
|
|
// (msCheckAspect() ) == MSTAT_NEAR &&
|
|
// (msCheckItalic() ) == MSTAT_NEAR &&
|
|
// (msCheckWeight() ) == MSTAT_NEAR &&
|
|
// (msCheckOutPrecision() ) == MSTAT_NEAR &&
|
|
// (msCheckWidth() ) == MSTAT_NEAR &&
|
|
// (msCheckOrientation(pfeo.iOrientation())) == MSTAT_NEAR
|
|
// )
|
|
// {
|
|
// return( MSTAT_NEAR );
|
|
// }
|
|
// return( MSTAT_FAR );
|
|
|
|
// if glyph index font is required, but this font does not support it, reject it
|
|
|
|
MSBREAKPOINT("msCheckForGlyphIndexFont");
|
|
if (bIndexFont && !ppfeNew->pgiset)
|
|
{
|
|
CHECKPRINT("CheckForGlyphIndexFont", FM_REJECT );
|
|
ulPenaltyTotal = FM_REJECT;
|
|
return( iRet );
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckPitch");
|
|
{
|
|
jHav = (BYTE) (ifio.lfPitchAndFamily() & LOGFONT_PITCH_SET);
|
|
jAsk =
|
|
(BYTE) (pelfwWish->elfLogFont.lfPitchAndFamily & LOGFONT_PITCH_SET);
|
|
ul = 0;
|
|
if (jAsk != DEFAULT_PITCH)
|
|
{
|
|
if (jAsk == FIXED_PITCH)
|
|
{
|
|
if (jHav & VARIABLE_PITCH)
|
|
{
|
|
ul = FM_WEIGHT_PITCHFIXED;
|
|
}
|
|
}
|
|
else if (!(jHav & VARIABLE_PITCH))
|
|
{
|
|
ul = FM_WEIGHT_PITCHVARIABLE;
|
|
}
|
|
}
|
|
else if (jHav & FIXED_PITCH)
|
|
{
|
|
ul = FM_WEIGHT_DEFAULTPITCHFIXED;
|
|
}
|
|
if (ul)
|
|
{
|
|
CHECKPRINT("Pitch",ul);
|
|
ulPenaltyTotal += ul;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckFamily");
|
|
{
|
|
jHav = ifio.lfPitchAndFamily() & FF_SET;
|
|
jAsk = pelfwWish->elfLogFont.lfPitchAndFamily & FF_SET;
|
|
if (jAsk == FF_DONTCARE)
|
|
{
|
|
if (jMapCharSet == SYMBOL_CHARSET)
|
|
{
|
|
// If the application asked for the symbol character set
|
|
// and did not specify a family preference
|
|
// then we should arrange it so that the choice of fonts
|
|
// is family neutral so I set the asked for family
|
|
// to be equal to the family of the current candidate
|
|
// font.
|
|
|
|
jAsk = ifio.lfPitchAndFamily() & FF_SET;
|
|
}
|
|
else
|
|
{
|
|
// If the application did not specify a family preference
|
|
// then we shall pick one for it. Normally we choose
|
|
// Swiss except for the case where the application
|
|
// asked for "Tms Rmn" where we ask for a Roman (serifed)
|
|
// font.
|
|
|
|
if (jHav != FF_DONTCARE)
|
|
{
|
|
// I have decide to excecute this family proxy
|
|
// request only in the case where the font doesn't
|
|
// have a family of FF_DONTCARE. The reason for this
|
|
// is interesting. Consider the case where a font,
|
|
// for what ever reason, chooses to have FF_DONTCARE
|
|
// for the family. Of course this is a bug but what
|
|
// can we do. Anyway, an application enumerates the
|
|
// fonts and gets back a logical font with
|
|
// FF_DONTCARE for the family. Then suppose the
|
|
// application takes that font and uses it to create
|
|
// a font of its own (this is what the ChooseFont
|
|
// common dialog box does all the time). Then we
|
|
// have the situation, where the logical font and the
|
|
// intended font both have FF_DONTCARE for their
|
|
// chosen family. If the statement below where
|
|
// excecuted, the family request would be changed to
|
|
// something that does not match the physical font.
|
|
// Trouble will occur if there is another font around
|
|
// with the same face name or family name. You may
|
|
// not get the font you wanted because we have
|
|
// erroneously added a family mismatch penalty. (See
|
|
// Bug #4912)
|
|
//
|
|
// Tue 28-Dec-1993 09:38:29 by Kirk Olynyk [kirko]
|
|
|
|
jAsk = (fl & FM_BIT_TMS_RMN_REQUEST) ? FF_ROMAN : FF_SWISS;
|
|
}
|
|
}
|
|
}
|
|
if (jAsk != jHav)
|
|
{
|
|
ul = 0;
|
|
if (jHav)
|
|
{
|
|
if
|
|
(
|
|
// Win 3.1 dogma -- Are jAsk and jHav on opposite sides of
|
|
// the FF_MODERN barrier? if so, a familiy match
|
|
// isn't likely
|
|
|
|
((jAsk <= FF_MODERN) && (jHav > FF_MODERN)) ||
|
|
((jAsk > FF_MODERN) && (jHav <= FF_MODERN))
|
|
)
|
|
{
|
|
ul += FM_WEIGHT_FAMILYUNLIKELY;
|
|
}
|
|
ul += FM_WEIGHT_FAMILY;
|
|
}
|
|
else
|
|
{
|
|
ul = FM_WEIGHT_FAMILYUNKNOWN;
|
|
}
|
|
if (ul)
|
|
{
|
|
CHECKPRINT("Family",ul);
|
|
ulPenaltyTotal += ul;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckCharSet");
|
|
|
|
{
|
|
if( (jMapCharSet != DEFAULT_CHARSET) &&
|
|
(!( fl & FM_BIT_MS_SHELL_DLG ) ))
|
|
{
|
|
*pjCharSet = jMapCharset(jMapCharSet, pfeo.pifi());
|
|
|
|
if (jMapCharSet != *pjCharSet)
|
|
{
|
|
if( fl & FM_BIT_CHARSET_ACCEPT )
|
|
{
|
|
CHECKPRINT("CharSet",FM_WEIGHT_CHARSET);
|
|
ulPenaltyTotal += FM_WEIGHT_CHARSET;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CHECKPRINT("CharSet", FM_REJECT );
|
|
ulPenaltyTotal = FM_REJECT;
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we still want to call jMapCharset, just don't set any penalty
|
|
|
|
*pjCharSet = jMapCharset(jMapCharSet, pfeo.pifi());
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef FE_SB
|
|
MSBREAKPOINT("msCheckVertAttr");
|
|
{
|
|
// If requested font is vertlcal face font, We have to map it to vertical
|
|
// face font
|
|
if ( fl & FM_BIT_VERT_FACE_REQUEST )
|
|
{
|
|
if ( *ifio.pwszFaceName() != U_COMMERCIAL_AT )
|
|
{
|
|
CHECKPRINT("VertAttr",FM_REJECT);
|
|
ulPenaltyTotal = FM_REJECT;
|
|
return(iRet);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
MSBREAKPOINT("msCheckHeight");
|
|
if (!ifio.bContinuousScaling())
|
|
{
|
|
if (!(fl & FM_BIT_CELL) && !bCalculateWishCell())
|
|
{
|
|
// The transform is incompatible with a raster font.
|
|
|
|
ulPenaltyTotal = FM_REJECT;
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
if (fl & FM_BIT_BAD_WISH_CELL)
|
|
{
|
|
DbgPrint("\t\tFM_BIT_BAD_WISH_CELL\n");
|
|
}
|
|
}
|
|
#endif
|
|
CHECKPRINT("Height", FM_REJECT);
|
|
return( iRet );
|
|
}
|
|
|
|
// Raster fonts shall be used only in the case when
|
|
// the transformation from World to Device
|
|
// coordinates is a simple scale, and the orientation
|
|
// angle is along either the x or y-axis.
|
|
//
|
|
// The physical height to compare against is either
|
|
// the cell height or em-height depending upon the
|
|
// sign of the LOGFONT::lfHeight field passed in by
|
|
// the application
|
|
//
|
|
// differences of over a pixel are the only ones that
|
|
// count so, we count pixels instead of angstroms
|
|
//
|
|
// Don't reject for the height penalty if the
|
|
// requested char set and physical font's char set
|
|
// are both symbol, or if the requested font is the
|
|
// system font since the system font is special.
|
|
|
|
LONG
|
|
lDevHeight =
|
|
(fl & FM_BIT_USE_EMHEIGHT) ? ifio.fwdUnitsPerEm() : ifio.lfHeight();
|
|
|
|
if (
|
|
lDevHeight < lDevWishHeight &&
|
|
ifio.bIntegralScaling() &&
|
|
!(fl & FM_BIT_PROOF_QUALITY) &&
|
|
WIN31_BITMAP_HEIGHT_SCALING_CRITERIA(lDevWishHeight,lDevHeight)
|
|
)
|
|
{
|
|
LONG lTemp = WIN31_BITMAP_HEIGHT_SCALING(lDevWishHeight,lDevHeight);
|
|
|
|
ptlSimulations.y = min(WIN31_BITMAP_HEIGHT_SCALING_MAX,lTemp);
|
|
}
|
|
else
|
|
{
|
|
ptlSimulations.y = 1;
|
|
}
|
|
|
|
ul = 0;
|
|
if (ptlSimulations.y > 1)
|
|
{
|
|
// Check to see if the height scaling is too gross according to
|
|
// the Win31 criteria
|
|
|
|
if (!(fl & FM_BIT_NO_MAX_HEIGHT))
|
|
{
|
|
if (WIN31_BITMAP_HEIGHT_SCALING_BAD(ptlSimulations.y,lDevHeight))
|
|
{
|
|
#if DBG
|
|
// needed by CHECKPRINT macro
|
|
ulPenaltyTotal = FM_REJECT;
|
|
#endif
|
|
CHECKPRINT("Height (scaling too big)",FM_REJECT);
|
|
return( iRet );
|
|
}
|
|
}
|
|
|
|
lDevHeight *= ptlSimulations.y;
|
|
ul += (ULONG) ptlSimulations.y * FM_WEIGHT_INT_SIZE_SYNTH;
|
|
|
|
// This next statement is found in the Win 3.1 code. Ours is not to
|
|
// question why.
|
|
|
|
ul |= (ULONG) (ptlSimulations.y-1)*WIN31_BITMAP_WIDTH_SCALING_MAX;
|
|
}
|
|
|
|
if (lDevWishHeight >= lDevHeight)
|
|
{
|
|
ul += FM_WEIGHT_HEIGHT * ((ULONG) (lDevWishHeight - lDevHeight));
|
|
}
|
|
else
|
|
{
|
|
// Under Win 3.1 the only non-scalable device fonts
|
|
// we run into are those from the printer UniDriver.
|
|
// Unfortunately, this driver has a very different
|
|
// idea of how font mapping is done. It allows the
|
|
// realized font to be one pel larger than the
|
|
// request with no penalty, but otherwise the penalty
|
|
// is fairly prohibitive. I am not simulating that
|
|
// exactly here (since it would be impossible), but I
|
|
// do allow the off by one miss, and then impose a 20
|
|
// pel penalty. I believe this will reduce by
|
|
// another order of magnitude the number of font
|
|
// mapping differences that remain. [chuckwh]
|
|
// 6/12/93.
|
|
|
|
if
|
|
(
|
|
(fl & (FM_BIT_DEVICE_FONT+FM_BIT_GM_COMPATIBLE))
|
|
== (FM_BIT_DEVICE_FONT+FM_BIT_GM_COMPATIBLE)
|
|
)
|
|
{
|
|
if (lDevHeight - lDevWishHeight > 1)
|
|
{
|
|
ul += FM_WEIGHT_HEIGHT *
|
|
(
|
|
(ULONG)
|
|
(
|
|
lDevHeight
|
|
- lDevWishHeight
|
|
+ 5 * FM_PHYS_FONT_TOO_LARGE_FACTOR
|
|
)
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ul += FM_WEIGHT_HEIGHT *
|
|
(
|
|
(ULONG)
|
|
(
|
|
lDevHeight
|
|
- lDevWishHeight
|
|
+ FM_PHYS_FONT_TOO_LARGE_FACTOR
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (ul)
|
|
{
|
|
CHECKPRINT("Height",ul);
|
|
ulPenaltyTotal += ul;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
if
|
|
(
|
|
ul >= FM_WEIGHT_FACENAME &&
|
|
!(fl & (FM_BIT_NO_MAX_HEIGHT | FM_BIT_SYSTEM_FONT))
|
|
)
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckAspect");
|
|
// 1. Check if aspect ratio filtering is turned on.
|
|
// 2. Do not check aspect ratio if not raster.
|
|
// 3. Win 3.1 says that the system font cannot be rejected
|
|
// on the basis of the aspect ratio test
|
|
// 4. Win 3.1 style aspect ratio test. In Win 3.1, the X and Y
|
|
// resolutions are checked, not the actual aspect ratio.
|
|
// 5. [GilmanW] 10-Jun-1992
|
|
// For 100% Windows 3.1 compatibility we should not check the true
|
|
// aspect ratio.
|
|
//
|
|
// But as KirkO says, lets leave it for now, as long as we comment
|
|
// it. So, unless you are KirkO or GilmanW, please don't remove
|
|
// this comment.
|
|
|
|
if
|
|
(
|
|
(pdco->pdc->flFontMapper() & ASPECT_FILTERING)
|
|
&& (ifio.lfOutPrecision() == OUT_RASTER_PRECIS)
|
|
&& !(fl & FM_BIT_SYSTEM_FONT)
|
|
&& (
|
|
(ulLogPixelsX != (ULONG) ifio.pptlAspect()->x)
|
|
|| (ulLogPixelsY != (ULONG) ifio.pptlAspect()->y)
|
|
)
|
|
&& (
|
|
(ulLogPixelsX * (ULONG) ifio.pptlAspect()->y)
|
|
!= (ulLogPixelsY * (ULONG) ifio.pptlAspect()->x)
|
|
)
|
|
)
|
|
{
|
|
CHECKPRINT("Aspect", FM_REJECT);
|
|
ulPenaltyTotal = FM_REJECT;
|
|
return( iRet );
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckItalic");
|
|
if (pelfwWish->elfLogFont.lfItalic)
|
|
{
|
|
// if you get here then the application wants an italicized font
|
|
// if the non simulated font is italicized already then
|
|
// then the penalty is zero.
|
|
|
|
if (!ifio.bNonSimItalic())
|
|
{
|
|
if (ifio.bSimItalic())
|
|
{
|
|
flSimulations |= FO_SIM_ITALIC;
|
|
ul = FM_WEIGHT_ITALICSIM;
|
|
}
|
|
else
|
|
{
|
|
ul = FM_WEIGHT_ITALIC;
|
|
}
|
|
CHECKPRINT("Italic",ul);
|
|
ulPenaltyTotal += ul;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The application doesn't want italicization,
|
|
// the normal font is its best shot
|
|
|
|
if (ifio.bNonSimItalic())
|
|
{
|
|
CHECKPRINT("Italic",FM_WEIGHT_ITALIC);
|
|
ulPenaltyTotal += FM_WEIGHT_ITALIC;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckWeight");
|
|
{
|
|
LONG lPen;
|
|
|
|
lPen = ifio.lfNonSimWeight() - lWishWeight;
|
|
|
|
if (fl & FM_BIT_FW_DONTCARE)
|
|
{
|
|
lPen = NT_FAST_DONTCARE_WEIGHT_PENALTY(ABS( lPen ));
|
|
|
|
CHECKPRINT("Weight", (DWORD) lPen );
|
|
ulPenaltyTotal += (DWORD) lPen;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
else if (lPen != 0)
|
|
{
|
|
if (lPen < 0)
|
|
{
|
|
// non simulated font isn't bold enough -> try a simulation
|
|
|
|
lPen = -lPen;
|
|
|
|
if( (WIN31_BITMAP_EMBOLDEN_CRITERIA(lPen)) &&
|
|
(ifio.pvSimBold() != NULL) )
|
|
{
|
|
flSimulations |= FO_SIM_BOLD;
|
|
lPen -= FM_WEIGHT_SIMULATED_WEIGHT;
|
|
}
|
|
}
|
|
|
|
lPen = NT_FAST_WEIGHT_PENALTY(lPen);
|
|
|
|
CHECKPRINT("Weight",(DWORD) lPen );
|
|
ulPenaltyTotal += (DWORD) lPen;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckOutPrecision");
|
|
|
|
if (!(fl & FM_BIT_DEVICE_FONT))
|
|
{
|
|
// If the device is a plotter then it can't do bitmap fonts
|
|
//
|
|
// If you get to here we are considering the suitability of
|
|
// a non-device font for the current device. The only case
|
|
// where this could be a problem is if the font is a raster
|
|
// font and the device cannot handle raster fonts.
|
|
//
|
|
// I have assume that a plotter can never handle a raster font.
|
|
// Other than that the a raster font is rejected if the device
|
|
// does not set the TC_RA_ABLE bit and the font does not tell
|
|
// you to ignore the TC_RA_ABLE bit.
|
|
|
|
if (ifio.lfOutPrecision() == OUT_RASTER_PRECIS)
|
|
{
|
|
if
|
|
(
|
|
(fl & FM_BIT_DEVICE_PLOTTER) ||
|
|
!(fl & FM_BIT_DEVICE_RA_ABLE || ifio.bIGNORE_TC_RA_ABLE())
|
|
)
|
|
{
|
|
ulPenaltyTotal = FM_REJECT;
|
|
CHECKPRINT("OutPrecision", FM_REJECT);
|
|
return( iRet );
|
|
}
|
|
}
|
|
|
|
// We also want to reject non-True Type fonts if the
|
|
// msCheckOutPrecision has
|
|
// been set to OUT_TT_ONLY_PRECIS. [gerritv]
|
|
|
|
if (
|
|
(pelfwWish->elfLogFont.lfOutPrecision == OUT_TT_ONLY_PRECIS) &&
|
|
(ifio.lfOutPrecision() != OUT_OUTLINE_PRECIS)
|
|
)
|
|
{
|
|
ulPenaltyTotal = FM_REJECT;
|
|
CHECKPRINT("OutPrecision: font isn't True Type", FM_REJECT);
|
|
return( iRet );
|
|
}
|
|
|
|
}
|
|
|
|
// If OUT_TT_PRECIS is used,
|
|
// the mapper gives the slight preference to screen outline font over the
|
|
// device font, everything else being equal. The example of
|
|
// this sitation is arial font, which exists as screen tt font
|
|
// as well as pcl printer device font. If the lfCharSet = 0,
|
|
// weight etc all match, using OUT_SCREEN_OUTLINE_PRECIS would allow applications
|
|
// to choose arial screen (tt) font over arial device.
|
|
// This is important because arial tt will typically have a larger
|
|
// character set and the apps will want to take advantage of it.
|
|
// The difference between this flag and OUT_TT_ONLY_PRECIS is
|
|
// that the latter one forces outline font on screen but does not
|
|
// give preference to outline font over device font on device.
|
|
// Another example might be Helvetica Type 1 font, and screen version
|
|
// may have more glyphs than the small Helvetica built
|
|
// into pscript printers. This of course assumes atm driver installed.
|
|
// Also, setting this flag would pick tt symbol over bitmap symbol.
|
|
|
|
if (
|
|
(pelfwWish->elfLogFont.lfOutPrecision == OUT_SCREEN_OUTLINE_PRECIS) &&
|
|
((fl & FM_BIT_DEVICE_FONT) || (ifio.lfOutPrecision() != OUT_OUTLINE_PRECIS))
|
|
)
|
|
{
|
|
CHECKPRINT("lfOutPrecision",(DWORD) FM_WEIGHT_FAVOR_TT);
|
|
ulPenaltyTotal += FM_WEIGHT_FAVOR_TT;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckWidth");
|
|
if (!ifio.bArbXforms() && !ifio.bAnisotropicScalingOnly())
|
|
{
|
|
// If the physical font is scalable. I make the bold assumption
|
|
// that any width can be achieved through linear transformation.
|
|
// This untrue but I will try to get away with this.
|
|
//
|
|
// [kirko] I believe that the correct thing to do is to compare
|
|
// the ratio of the height to with of the request and compare it
|
|
// with the ratio of the height to width of the font in design
|
|
// space. Then assign a penalty based upon the difference.
|
|
|
|
LONG lDevWidth = ifio.lfWidth();
|
|
ptlSimulations.x = 1;
|
|
|
|
if (pelfwWish->elfLogFont.lfWidth != 0)
|
|
{
|
|
if (!(fl & FM_BIT_CELL) && !bCalculateWishCell())
|
|
{
|
|
// The transform is incompatible with a raster font.
|
|
|
|
ulPenaltyTotal = FM_REJECT;
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
if (fl & FM_BIT_BAD_WISH_CELL)
|
|
{
|
|
DbgPrint("\t\tFM_BIT_BAD_WISH_CELL\n");
|
|
}
|
|
}
|
|
#endif
|
|
CHECKPRINT("Width", FM_REJECT);
|
|
return( iRet );
|
|
}
|
|
|
|
if
|
|
(
|
|
ifio.bIntegralScaling() &&
|
|
!(fl & FM_BIT_PROOF_QUALITY) &&
|
|
WIN31_BITMAP_WIDTH_SCALING_CRITERIA(lDevWishWidth, lDevWidth)
|
|
)
|
|
{
|
|
// set ptlSimulations.x
|
|
|
|
LONG lTemp = WIN31_BITMAP_WIDTH_SCALING(lDevWishWidth,lDevWidth);
|
|
|
|
ptlSimulations.x = min(WIN31_BITMAP_WIDTH_SCALING_MAX, lTemp);
|
|
}
|
|
else if (ifio.bIsotropicScalingOnly())
|
|
{
|
|
// For simple scaling fonts, the scaling is determined by the
|
|
// ratio of the font space height to the device space height
|
|
// request.
|
|
|
|
ASSERTGDI(ifio.lfHeight(),"msCheckWidth finds lfHeight == 0\n");
|
|
{
|
|
lDevWidth *= lDevWishHeight;
|
|
lDevWidth /= ifio.lfHeight();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// nothing needs to be done
|
|
}
|
|
|
|
ul = 0;
|
|
if (ptlSimulations.x > 1)
|
|
{
|
|
lDevWidth *= ptlSimulations.x;
|
|
ul += (ULONG) ptlSimulations.x
|
|
* FM_WEIGHT_INT_SIZE_SYNTH;
|
|
|
|
// Win 3.1 compatibility dictates the next statement
|
|
|
|
ul |= (ULONG) (ptlSimulations.x - 1);
|
|
|
|
}
|
|
ul += FM_WEIGHT_FWIDTH
|
|
* (ULONG) ABS(lDevWishWidth - lDevWidth);
|
|
|
|
if (ul)
|
|
{
|
|
CHECKPRINT("Width",ul);
|
|
ulPenaltyTotal += ul;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If you get to here then the application has specified a width
|
|
// of zero.
|
|
//
|
|
// If the application asks for proof quality then no simulations
|
|
// are allowed. No width penalty is assessed in the case where
|
|
// the applicaition does not specify a width.
|
|
|
|
if (ifio.bIntegralScaling() && !(fl & FM_BIT_PROOF_QUALITY))
|
|
{
|
|
// since no width has been specified we must do aspect
|
|
// ratio matching Win 3.1 style [gerritv]
|
|
|
|
ul = 0;
|
|
ULONG ulDevAspect, ulFontAspect, ulFontAspectSave;
|
|
|
|
// Since FontAspects and DevAspects will usually be one we will
|
|
// introduce some fast cases to avoid extraneous multiplies and
|
|
// divides
|
|
|
|
BOOL bSpeedup = FALSE;
|
|
|
|
if (ifio.pptlAspect()->x == ifio.pptlAspect()->y)
|
|
{
|
|
if (ulLogPixelsX == ulLogPixelsY)
|
|
{
|
|
// this is the common case under which
|
|
// we can avoid many multiplies and divides.
|
|
|
|
bSpeedup = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (!bSpeedup)
|
|
{
|
|
// this is taken straight from the Win 3.1 code
|
|
|
|
ulDevAspect = ( ulLogPixelsY * 100 ) / ulLogPixelsX;
|
|
ulFontAspectSave = ( ( ifio.pptlAspect()->x * 100 ) /
|
|
ifio.pptlAspect()->y );
|
|
ulFontAspect = ulFontAspectSave / ptlSimulations.y;
|
|
}
|
|
|
|
if ((!bSpeedup) || (ptlSimulations.y != 1))
|
|
{
|
|
if ( (bSpeedup) ||
|
|
WIN31_BITMAP_ASPECT_BASED_SCALING(ulDevAspect,ulFontAspect) )
|
|
{
|
|
// divide with rounding
|
|
|
|
if (bSpeedup)
|
|
{
|
|
ptlSimulations.x = ptlSimulations.y;
|
|
}
|
|
else
|
|
{
|
|
ptlSimulations.x = ulDevAspect / ulFontAspect;
|
|
}
|
|
|
|
// enforce maximum scalling factor
|
|
|
|
ptlSimulations.x =
|
|
min( WIN31_BITMAP_WIDTH_SCALING_MAX, ptlSimulations.x );
|
|
|
|
ul +=
|
|
WIN31_BITMAP_WIDTH_SCALING_PENALTY((ULONG)ptlSimulations.x);
|
|
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(ptlSimulations.x == 1, "ptlSimulations.x != 1\n");
|
|
}
|
|
|
|
if
|
|
(
|
|
(!bSpeedup) || (ptlSimulations.x != ptlSimulations.y)
|
|
)
|
|
{
|
|
ulFontAspect = ulFontAspectSave *
|
|
ptlSimulations.x / ptlSimulations.y;
|
|
|
|
ULONG ulTemp = (ULONG) ABS((LONG)(ulDevAspect - ulFontAspect));
|
|
|
|
ul += WIN31_BITMAP_ASPECT_MISMATCH_PENALTY( ulTemp );
|
|
}
|
|
|
|
if (ul)
|
|
{
|
|
CHECKPRINT("Width",ul);
|
|
ulPenaltyTotal += ul;
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// do nothing: no scaling means no penalty
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckScaling");
|
|
if
|
|
(
|
|
(ptlSimulations.x > 1 || ptlSimulations.y > 1)
|
|
)
|
|
{
|
|
// Following Win 3.1 we penalize if there is a scaling at all. And there
|
|
// is an additional penalty if the scaling of the height and width
|
|
// directions are not the same.
|
|
|
|
#if DBG
|
|
ULONG ulTemp = ulPenaltyTotal;
|
|
#endif
|
|
|
|
// Penalize for scaling at all
|
|
|
|
ulPenaltyTotal += FM_WEIGHT_SIZESYNTH;
|
|
|
|
// Penalize even more if the scaling is anisotropic.
|
|
// Win 3.1 uses the hard coded factor of 100 and so do we!
|
|
|
|
if (ptlSimulations.x > ptlSimulations.y)
|
|
{
|
|
ulPenaltyTotal += (ULONG)
|
|
FM_WEIGHT_FUNEVENSIZESYNTH * MULDIV(100, ptlSimulations.x, ptlSimulations.y);
|
|
}
|
|
else if ( ptlSimulations.x < ptlSimulations.y )
|
|
{
|
|
ulPenaltyTotal += (ULONG)
|
|
FM_WEIGHT_FUNEVENSIZESYNTH * MULDIV(100, ptlSimulations.y, ptlSimulations.x);
|
|
}
|
|
|
|
CHECKPRINT("msCheckScaling",ulPenaltyTotal-ulTemp);
|
|
if (bNoMatch(ppfeNew))
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckOrientation");
|
|
if (!ifio.bArbXforms())
|
|
{
|
|
// Either this matches or it doesn't. The penalty is either
|
|
// maximally prohibitive or it is zero.
|
|
//
|
|
// Discussion:
|
|
//
|
|
// All vector fonts are assumed to be OK
|
|
//
|
|
// Raster Font are OK (1) The requested baseline
|
|
// direction agrees with the direction of the raster
|
|
// font (2) The transformation from world to device
|
|
// coordinates is the combination of a scale and a
|
|
// rotation by a multiple of 90 degrees. This means
|
|
// that we will reject if a reflection exists or if
|
|
// there is shear.
|
|
//
|
|
// I shall make the assumption that raster fonts can be
|
|
// used only in the case where the notional to device
|
|
// transformation is a simple scale followed by a rotation
|
|
// that is a multiple of 90 degrees. This means that the
|
|
// baseline in device space is along either the x-axis or
|
|
// y-axis. Moreover, the acender direction must be
|
|
// perpendicular to the baseline. There are a lot of
|
|
// cases where this could happen. For example, suppose
|
|
// that the original orientation was alpha, and their was
|
|
// a world to device transformation that was 90 degrees
|
|
// minus alpha. The resulting orientation would be along
|
|
// one of the axes. However, I will not check for such a
|
|
// coincidence. I will allow only cases where the
|
|
// original orientation in world coordinates is a multiple
|
|
// of 90 degrees, and the world to device transformation
|
|
// is a simple combination of scales and rotations by 90
|
|
// degrees.
|
|
//
|
|
// The orientation should have been computed when we
|
|
// checked heights above.
|
|
//
|
|
// Under Win 3.1 we cannot reject a font because of orientation
|
|
// mismatch if it the device is the screen
|
|
|
|
if (!((fl & FM_BIT_GM_COMPATIBLE) && (fl & FM_BIT_DISPLAY_DC)))
|
|
{
|
|
ul = 1;
|
|
|
|
if ((fl & FM_BIT_ORIENTATION) || bCalcOrientation())
|
|
{
|
|
ul = (ULONG) iOrientationDevice - pfeo.iOrientation();
|
|
|
|
if (ul && (fl & FM_BIT_DEVICE_CR_90_ALL) && (fl & FM_BIT_DEVICE_FONT))
|
|
{
|
|
if (ul > (ULONG) iOrientationDevice)
|
|
{
|
|
ul = (ULONG) (- (LONG) ul);
|
|
}
|
|
ul = ul % ORIENTATION_90_DEG;
|
|
}
|
|
#ifdef FE_SB
|
|
if (ul && ifio.b90DegreeRotations())
|
|
{
|
|
if (ul > (ULONG) iOrientationDevice)
|
|
{
|
|
ul = (ULONG) (- (LONG) ul);
|
|
}
|
|
ul = ul % ORIENTATION_90_DEG;
|
|
}
|
|
#endif
|
|
}
|
|
if ( ul )
|
|
{
|
|
ulPenaltyTotal = FM_REJECT;
|
|
CHECKPRINT("Orientation",FM_REJECT);
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
|
|
MSBREAKPOINT("msCheckAlias");
|
|
{
|
|
// Checks to see if the font is really an alias for a device font.
|
|
//
|
|
// Discussion:
|
|
//
|
|
// In the Win/WFW3.1 architecture, the device drivers get
|
|
// a chance to do font mapping. Some device drivers, like
|
|
// the PostScript driver and the HP PCL drivers, allow
|
|
// some of the device fonts to be aliased to other names.
|
|
// For example, while the PostScript printer might
|
|
// physically have a "Helvetica" font, the driver allows
|
|
// "Helv", "Arial", and "Swiss" to be mapped to it (with
|
|
// only a small penalty). More precisely, "Helv" et. al
|
|
// are in the "Helvetica" equivalence class.
|
|
//
|
|
// We do not want such a font to be returned without error.
|
|
// Otherwise, if we return this as an exact match, we will not
|
|
// be able to map to REAL fonts that may exist in the engine.
|
|
// For example, since "Arial" is in the equivalence class for
|
|
// "Helvetica", without a penalty we may return "Helvetica" as
|
|
// an exact match. This shorts out the mapper before it can
|
|
// get to the TrueType "Arial" that REALLY exists as an engine
|
|
// font. Therefore, we will impose a slight penalty for
|
|
// aliased fonts.
|
|
//
|
|
//
|
|
// If the FM_BIT_EQUIV_NAME bit is set, the font list we are
|
|
// looking at is really an aliased font name for a device font.
|
|
|
|
if (fl & FM_BIT_EQUIV_NAME)
|
|
{
|
|
ulPenaltyTotal += FM_WEIGHT_DEVICE_ALIAS;
|
|
if ( bNoMatch(ppfeNew) )
|
|
{
|
|
return( iRet );
|
|
}
|
|
}
|
|
}
|
|
|
|
// We are all done!
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* IFIOBJ::lfOrientation *
|
|
* *
|
|
* Returns the Orientation (angle of the baseline in tenths of degrees *
|
|
* measured counter clockwise from the x-axis) in device space. *
|
|
* *
|
|
* History: *
|
|
* Thu 17-Dec-1992 16:22:56 -by- Charles Whitmer [chuckwh] *
|
|
* Changed the easy case to wierd bit manipulation. *
|
|
* *
|
|
* Tue 24-Sep-1991 10:54:24 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
LONG IFIOBJ::lfOrientation()
|
|
{
|
|
INT sx = SIGNUM(pifi->ptlBaseline.x);
|
|
INT sy = SIGNUM(pifi->ptlBaseline.y);
|
|
|
|
if ((sx^sy)&1) // I.e. if exactly one of them is zero...
|
|
{
|
|
// Return the following angles:
|
|
//
|
|
// sx = 00000001 : 0
|
|
// sy = 00000001 : 900
|
|
// sx = FFFFFFFF : 1800
|
|
// sy = FFFFFFFF : 2700
|
|
|
|
return( (sx & 1800) | (sy & 2700) | ((-sy) & 900) );
|
|
}
|
|
|
|
// Do the hard case.
|
|
|
|
LONG lDummy;
|
|
|
|
EFLOATEXT efltX(pifi->ptlBaseline.x);
|
|
EFLOATEXT efltY(pifi->ptlBaseline.y);
|
|
|
|
EFLOAT efltTheta;
|
|
vArctan(efltX, efltY, efltTheta, lDummy);
|
|
|
|
*(EFLOATEXT*) &efltTheta *= (LONG) 10;
|
|
|
|
return( efltTheta.bEfToL(lDummy) ? lDummy : 0 );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* MAPPER::bFoundExactMatch() *
|
|
* *
|
|
* This routine searches for a match to an extended logical font. *
|
|
* It is assumed that the face name has infinite weight. Therefore *
|
|
* the face name is searched for in the hash table that is provided by *
|
|
* the caller. If the name is found, then the best match is searched for *
|
|
* among the elements of the linked list of PFE's containing the same *
|
|
* face name. *
|
|
* *
|
|
* If the name is found, then the MAPFONT_FOUND_NAME flag is set in *
|
|
* pflAboutMatch. If the name was found by using facename substitution *
|
|
* (ie., alternate facename), then the MAPFONT_ALTNAME_USED flag is also *
|
|
* set. *
|
|
* *
|
|
* The return value of the function report whether the match was exact. *
|
|
* This information is actually redundant. It could be retrived by *
|
|
* looking at mapper.ulPenaltyTotal *
|
|
* *
|
|
* Important Operating Principles *
|
|
* *
|
|
* 1. The value pointed to pppfeRet is modified only if i) an the name *
|
|
* is matched, and ii) the match is better than any found previously *
|
|
* *
|
|
* History: *
|
|
* Fri 18-Dec-1992 04:57:29 -by- Charles Whitmer [chuckwh] *
|
|
* Rewrote it for performance. One major change is that I only take the *
|
|
* winning PFE and move it to the front of the list, rather than *
|
|
* continually shuffling the list. This cuts down overhead and should *
|
|
* have about the same effect. *
|
|
* *
|
|
* Wed 22-Apr-1992 10:47:50 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
MAPPER::bFoundExactMatch(
|
|
FONTHASH **ppfh
|
|
)
|
|
{
|
|
PFE **pppfe,**pppfeBest;
|
|
PWSZ pwszTarg;
|
|
|
|
HASHBUCKET *apbkt[2];
|
|
BYTE ajCharSet[2];
|
|
|
|
FONTHASHTYPE fht;
|
|
int i,iBest;
|
|
BOOL bRet = FALSE;
|
|
BYTE jCharSet = DEFAULT_CHARSET;
|
|
|
|
// This is returned as the *pflAboutMatch in the MAPPER class if and only
|
|
// if we find a better match. So we store it temporarily in this local
|
|
// rather than set it directly.
|
|
|
|
*pflAboutMatch &= ~MAPFONT_FOUND_NAME;
|
|
|
|
FHOBJ fho(ppfh);
|
|
if (!fho.bValid())
|
|
{
|
|
return( bRet );
|
|
}
|
|
fht = fho.fht();
|
|
|
|
// Note well: mapper.pwszFaceName must ALWAYS be CAPITALIZED!
|
|
|
|
pwszTarg = this->pwszFaceName;
|
|
|
|
// Attempt to locate the name.
|
|
|
|
#define I_ORIGINAL 0
|
|
#define I_ALTERNATE 1
|
|
|
|
apbkt[I_ORIGINAL ] = 0;
|
|
apbkt[I_ALTERNATE] = 0;
|
|
ajCharSet[I_ORIGINAL] = ajCharSet[I_ALTERNATE] = this->jMapCharSet;
|
|
|
|
FONTSUB* pfsub = pfsubAlternateFacename(pwszTarg);
|
|
|
|
if (pfsub)
|
|
{
|
|
// charsets specified or not in the substitution entry ?
|
|
|
|
if (pfsub->fcsAltFace.fjFlags & FJ_NOTSPECIFIED)
|
|
{
|
|
// old style substitution, now charsets are specified
|
|
// First search for the facename on the left hand side,
|
|
// if not found search for the one on the right hand side.
|
|
// In both cases use the original charset in the logfont.
|
|
|
|
apbkt[I_ORIGINAL] = fho.pbktSearch(pwszTarg,(UINT*)NULL);
|
|
apbkt[I_ALTERNATE] = fho.pbktSearch((PWSZ)pfsub->fcsAltFace.awch,(UINT*)NULL);
|
|
}
|
|
else
|
|
{
|
|
// charsets are specified in the font substitution entry.
|
|
|
|
if (this->jMapCharSet == pfsub->fcsFace.jCharSet)
|
|
{
|
|
// If the charset requested in the logfont matches the one on
|
|
// the left hand side of the substitution, we shall actually go
|
|
// for the alternate facename and charset, without even looking
|
|
// if the font with facename and charset specified on the left
|
|
// hand side is installed on the system.
|
|
// This is win95 behavior which actually makes some sense.
|
|
|
|
apbkt[I_ALTERNATE] = fho.pbktSearch((PWSZ)pfsub->fcsAltFace.awch,(UINT*)NULL);
|
|
ajCharSet[I_ALTERNATE] = pfsub->fcsAltFace.jCharSet;
|
|
}
|
|
else
|
|
{
|
|
// logfont charset request does not match what is in the substitution entry,
|
|
// even though the face name matches. We treat this the same as pfsub == 0 case
|
|
|
|
apbkt[I_ORIGINAL] = fho.pbktSearch(pwszTarg,(UINT*)NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
apbkt[I_ORIGINAL] = fho.pbktSearch(pwszTarg,(UINT*)NULL);
|
|
}
|
|
|
|
if (!apbkt[I_ORIGINAL] && !apbkt[I_ALTERNATE])
|
|
{
|
|
return( bRet );
|
|
}
|
|
|
|
// If we get to here, we were able to find a hash bucket
|
|
// of the correct name.
|
|
|
|
*pflAboutMatch |= MAPFONT_FOUND_NAME;
|
|
fl |= FM_BIT_FACENAME_MATCHED;
|
|
|
|
// Scan the PFE list for the best match.
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (!apbkt[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
vResetCharSet(ajCharSet[i]);
|
|
|
|
if (apbkt[i]->fl & HB_EQUIV_FAMILY)
|
|
{
|
|
fl |= FM_BIT_EQUIV_NAME;
|
|
}
|
|
else
|
|
{
|
|
fl &= ~FM_BIT_EQUIV_NAME;
|
|
}
|
|
|
|
for
|
|
(
|
|
pppfeBest = (PFE **) NULL, pppfe = &(apbkt[i]->ppfeEnumHead)
|
|
;
|
|
*pppfe != PPFENULL
|
|
;
|
|
// see iteration statement at end of loop
|
|
)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER && *pppfe == ppfeBreak)
|
|
{
|
|
DbgPrint(" **** breaking on ppfe = %-#8lx\n\n",*pppfe);
|
|
DbgBreakPoint();
|
|
}
|
|
#endif
|
|
|
|
PFEOBJ pfeo(*pppfe);
|
|
|
|
if (this->bNearMatch(pfeo,&jCharSet))
|
|
{
|
|
DUMP_CHOSEN_FONT(pfeo);
|
|
iBest = i;
|
|
|
|
// remember the good one
|
|
|
|
pppfeBest = pppfe;
|
|
|
|
// remember the simulation information for the best font
|
|
// choice to this time
|
|
|
|
vSetBest(*pppfe, fl & FM_BIT_DEVICE_FONT, jCharSet);
|
|
|
|
if (this->ulPenaltyTotal == 0)
|
|
{
|
|
// If the match was exact, return immediately unless
|
|
// there this is a true type font and there are
|
|
// rasterfonts of the same face name. In this case
|
|
// we must give the rasterfonts a chance since in the
|
|
// event of a tie, the raster font must win to be Win
|
|
// 3.1 compatibility.
|
|
|
|
if( !( apbkt[i]->cRaster ) ||
|
|
( pfeo.flFontType() & RASTER_FONTTYPE ))
|
|
{
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
|
|
// we need to give the raster fonts a chance we do this
|
|
// by setting ulPenaltyTotal to 1.
|
|
// This way only an exact match will beat us out.
|
|
|
|
this->ulPenaltyTotal = 1;
|
|
}
|
|
|
|
// prune the search
|
|
|
|
this->ulMaxPenalty = this->ulPenaltyTotal;
|
|
}
|
|
else
|
|
{
|
|
DUMP_REJECTED_FONT(pfeo);
|
|
}
|
|
|
|
// iteration statement
|
|
|
|
pppfe = pfeo.pppfeEnumNext(fht);
|
|
}
|
|
if (bRet == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
// Return a good one if we found it.
|
|
|
|
if (pppfeBest != (PFE **) NULL)
|
|
{
|
|
// We found a better match, so better change the about flags.
|
|
|
|
if (iBest == I_ALTERNATE || fht == FHT_FACE)
|
|
{
|
|
*pflAboutMatch |= MAPFONT_ALTFACE_USED;
|
|
}
|
|
|
|
// record code page, needed for correct code page to
|
|
// unicode translation In case of single charset
|
|
// font, we always cheat and represent the font
|
|
// glyphset using ansi to unicode conversion using
|
|
// the current ansi code page, even though the
|
|
// underlining font may contain a symbol or an oem
|
|
// code page. But we do not care, we just need to
|
|
// make the round trip a->u->a works for these fonts.
|
|
// Also we want the client side cacheing of char
|
|
// widths for GTE and GCW to work for these fonts.
|
|
// there are two exceptions to this rule: 1) the default ansi code page is
|
|
// not SBCS since this doesn't guarantee roundtrip conversion and
|
|
// 2) the charset of the font is DBCS
|
|
|
|
ULONG ulCodePage;
|
|
|
|
if
|
|
(
|
|
(*pppfeBest)->pifi->dpCharSets ||
|
|
(
|
|
((*pppfeBest)->flPFE & PFE_DEVICEFONT) &&
|
|
|
|
// the following line singles out pcl device fonts, our ps
|
|
// driver fonts report the glyphset computed based on the current
|
|
// acp, just like bitmap fonts do. When we get the ps 5.0 driver,
|
|
// we should remove this line. At this time, the only reason to have
|
|
// a distinction will be bm and vector fonts. These often have incorrect
|
|
// charset in the pfm file and we shall for that reason continue to lie
|
|
// about them.
|
|
|
|
((*pppfeBest)->pifi->flInfo & FM_INFO_TECH_BITMAP)
|
|
)
|
|
)
|
|
{
|
|
ulCodePage = ulCharsetToCodePage((UINT) jCharSet);
|
|
}
|
|
else
|
|
{
|
|
switch(jCharSet)
|
|
{
|
|
case SHIFTJIS_CHARSET:
|
|
case HANGEUL_CHARSET:
|
|
case GB2312_CHARSET:
|
|
case CHINESEBIG5_CHARSET:
|
|
case JOHAB_CHARSET:
|
|
ulCodePage = ulCharsetToCodePage((UINT) jCharSet);
|
|
break;
|
|
|
|
default:
|
|
// just use 1252 if the default CP is not SBCS
|
|
|
|
ulCodePage = (gbDBCSCodePage) ? 1252 : CP_ACP;
|
|
}
|
|
}
|
|
*pflAboutMatch |= (ulCodePage << 8);
|
|
}
|
|
fl &= ~FM_BIT_EQUIV_NAME;
|
|
return( bRet );
|
|
}
|
|
|
|
/****************************************************************************
|
|
* MAPPER::bFoundForcedMatch( PUNIVERSAL_FONT_ID pufi )
|
|
*
|
|
* This routine forces mapping to a PFE identified by a UFI. It will compute
|
|
* simulations to be performed on the font as well.
|
|
|
|
* History:
|
|
* 5/11/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
|
|
BOOL MAPPER::bFoundForcedMatch(UNIVERSAL_FONT_ID *pufi)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("MAPPER::bFoundForcedMatch: " );
|
|
DbgPrint("CheckSum = %x Index = %d\n", pufi->CheckSum, pufi->Index );
|
|
}
|
|
#endif
|
|
PFE *ppfe;
|
|
|
|
if( UFI_DEVICE_FONT( pufi ) || UFI_TYPE1_FONT( pufi ) )
|
|
{
|
|
DEVICE_PFTOBJ pftoDevice;
|
|
FONTHASH **ppfh = (FONTHASH**) NULL;
|
|
PFF *pPFF;
|
|
|
|
if (pPFF = pftoDevice.pPFFGet(pdco->hdev()))
|
|
{
|
|
PFFOBJ pffo(pPFF);
|
|
|
|
if (pffo.bValid())
|
|
{
|
|
ppfh = &pffo.pPFF->pfhFamily;
|
|
}
|
|
}
|
|
|
|
if (ppfh == (FONTHASH**) NULL)
|
|
{
|
|
WARNING1("MAPPER::bFoundForcedMatch() -- invalid FONTHASH\n");
|
|
return( FALSE );
|
|
}
|
|
|
|
// Prepare to enumerate through all the device fonts
|
|
|
|
ENUMFHOBJ fho(ppfh);
|
|
for (ppfe = fho.ppfeFirst(); ppfe; ppfe = fho.ppfeNext())
|
|
{
|
|
PFEOBJ pfeo(ppfe);
|
|
|
|
if( UFI_SAME_FACE(pfeo.pUFI(),pufi) )
|
|
{
|
|
if( pfeo.bDead() )
|
|
{
|
|
WARNING("MAPPER::bFoundForcedMatch mapped to dead PFE\n");
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if( ppfe == NULL )
|
|
{
|
|
WARNING1("MAPPER::bFoundForcedMatch unable to find force device match");
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PUBLIC_PFTOBJ pfto;
|
|
FHOBJ fho(&pfto.pPFT->pfhUFI);
|
|
HASHBUCKET *pbkt;
|
|
|
|
pbkt = fho.pbktSearch( NULL, (UINT*)NULL, pufi );
|
|
|
|
if( pbkt == NULL )
|
|
{
|
|
WARNING1("MAPPER::bFoundForcedMatch: pbkt is NULL\n");
|
|
return( FALSE );
|
|
}
|
|
|
|
for( ppfe = pbkt->ppfeEnumHead ; ppfe ; )
|
|
{
|
|
PFEOBJ pfeo ( ppfe );
|
|
|
|
// if the UFI's match and (in the case of a remote font) the process
|
|
// that created the remote font is the same as the current one then
|
|
// we've got a match
|
|
|
|
if(UFI_SAME_FACE(pfeo.pUFI(),pufi) && pfeo.SameProccess())
|
|
{
|
|
if( pfeo.bDead() )
|
|
{
|
|
WARNING1("MAPPER::bFoundForcedMatch mapped to dead PFE\n");
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
ppfe = *pfeo.pppfeEnumNext(FHT_UFI);
|
|
}
|
|
if( ppfe == NULL )
|
|
{
|
|
WARNING1("MAPPER::bFoundForcedMatch unable to find force engine match\n");
|
|
return( FALSE );
|
|
}
|
|
}
|
|
ASSERTGDI( ppfe != NULL, "bFoundForceMatch: ppfe is NULL" );
|
|
|
|
// If we are here we found the right PFE,
|
|
// now we need to compute ptlSim and flSim.
|
|
|
|
ptlSimulations.x = 1;
|
|
ptlSimulations.y = 1;
|
|
flSimulations = 0;
|
|
|
|
PFEOBJ pfeo(ppfe);
|
|
|
|
ifio.vSet( pfeo.pifi() );
|
|
|
|
// first compute any possible height simulations
|
|
|
|
if (!ifio.bContinuousScaling())
|
|
{
|
|
LONG
|
|
lDevHeight =
|
|
(fl & FM_BIT_USE_EMHEIGHT) ? ifio.fwdUnitsPerEm() : ifio.lfHeight();
|
|
if (
|
|
lDevHeight < lDevWishHeight &&
|
|
ifio.bIntegralScaling() &&
|
|
!(fl & FM_BIT_PROOF_QUALITY) &&
|
|
WIN31_BITMAP_HEIGHT_SCALING_CRITERIA(lDevWishHeight,lDevHeight)
|
|
)
|
|
{
|
|
LONG lTemp = WIN31_BITMAP_HEIGHT_SCALING(lDevWishHeight,lDevHeight);
|
|
|
|
ptlSimulations.y = min(WIN31_BITMAP_HEIGHT_SCALING_MAX,lTemp);
|
|
}
|
|
else
|
|
{
|
|
ptlSimulations.y = 1;
|
|
}
|
|
}
|
|
|
|
// next check for italic simulations
|
|
|
|
if (pelfwWish->elfLogFont.lfItalic)
|
|
{
|
|
// if you get here then the application wants an italicized font
|
|
|
|
if (!ifio.bNonSimItalic() && ifio.bSimItalic())
|
|
{
|
|
flSimulations |= FO_SIM_ITALIC;
|
|
}
|
|
}
|
|
|
|
// bold simulations
|
|
|
|
LONG lPen;
|
|
|
|
lPen = ifio.lfNonSimWeight() - lWishWeight;
|
|
|
|
if( !(fl & FM_BIT_FW_DONTCARE) && (lPen < 0 ) )
|
|
{
|
|
|
|
// non simulated font isn't bold enough -> try a simulation
|
|
|
|
lPen = -lPen;
|
|
|
|
if( (WIN31_BITMAP_EMBOLDEN_CRITERIA(lPen)) &&
|
|
(ifio.pvSimBold() != NULL) )
|
|
{
|
|
flSimulations |= FO_SIM_BOLD;
|
|
}
|
|
}
|
|
|
|
// width simulations
|
|
|
|
if (!ifio.bArbXforms() && !ifio.bAnisotropicScalingOnly())
|
|
{
|
|
LONG lDevWidth = ifio.lfWidth();
|
|
ptlSimulations.x = 1;
|
|
|
|
if (pelfwWish->elfLogFont.lfWidth != 0)
|
|
{
|
|
if( !(fl & FM_BIT_CELL) )
|
|
{
|
|
bCalculateWishCell();
|
|
}
|
|
|
|
if
|
|
(
|
|
ifio.bIntegralScaling() &&
|
|
!(fl & FM_BIT_PROOF_QUALITY) &&
|
|
WIN31_BITMAP_WIDTH_SCALING_CRITERIA(lDevWishWidth, lDevWidth)
|
|
)
|
|
{
|
|
// set ptlSimulations.x
|
|
|
|
LONG lTemp = WIN31_BITMAP_WIDTH_SCALING(lDevWishWidth,lDevWidth);
|
|
|
|
ptlSimulations.x = min(WIN31_BITMAP_WIDTH_SCALING_MAX, lTemp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ifio.bIntegralScaling() && !(fl & FM_BIT_PROOF_QUALITY))
|
|
{
|
|
// since no width has been specified we must do aspect
|
|
// ratio matching Win 3.1 style [gerritv]
|
|
|
|
ULONG ulDevAspect, ulFontAspect, ulFontAspectSave;
|
|
|
|
// Since FontAspects and DevAspects will usually be one we will
|
|
// introduce some fast cases to avoid extraneous multiplies and
|
|
// divides
|
|
|
|
BOOL bSpeedup = FALSE;
|
|
|
|
if (ifio.pptlAspect()->x == ifio.pptlAspect()->y)
|
|
{
|
|
if (ulLogPixelsX == ulLogPixelsY)
|
|
{
|
|
// this is the common case under which
|
|
// we can avoid many multiplies and divides.
|
|
|
|
bSpeedup = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bSpeedup)
|
|
{
|
|
// this is taken straight from the Win 3.1 code
|
|
|
|
ulDevAspect = ( ulLogPixelsY * 100 ) / ulLogPixelsX;
|
|
|
|
ulFontAspectSave = ( ( ifio.pptlAspect()->x * 100 ) /
|
|
ifio.pptlAspect()->y );
|
|
|
|
ulFontAspect = ulFontAspectSave / ptlSimulations.y;
|
|
}
|
|
|
|
if ((!bSpeedup) || (ptlSimulations.y != 1))
|
|
{
|
|
if
|
|
(
|
|
(bSpeedup) ||
|
|
WIN31_BITMAP_ASPECT_BASED_SCALING(ulDevAspect,ulFontAspect)
|
|
)
|
|
{
|
|
// divide with rounding
|
|
|
|
if (bSpeedup)
|
|
{
|
|
ptlSimulations.x = ptlSimulations.y;
|
|
}
|
|
else
|
|
{
|
|
ptlSimulations.x = ulDevAspect / ulFontAspect;
|
|
}
|
|
|
|
// enforce maximum scalling factor
|
|
|
|
ptlSimulations.x =
|
|
min( WIN31_BITMAP_WIDTH_SCALING_MAX, ptlSimulations.x );
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(ptlSimulations.x == 1, "ptlSimulations.x != 1\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// need to do this here because vSetBest will update ptlSim and pflSim
|
|
|
|
vSetBest( ppfe, TRUE, DEFAULT_CHARSET );
|
|
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("MAPPER::bFoundForcedMatch: ppfeBest = %-#x\n", ppfeBest );
|
|
}
|
|
#endif
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ppfeGetAMatch *
|
|
* *
|
|
* Returns the best fit to a wish defined by the application. *
|
|
* *
|
|
* History: *
|
|
* Wed 11-Dec-1991 09:32:11 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
PFE *ppfeGetAMatch (
|
|
XDCOBJ& dco, // The DC defines all the relevant
|
|
// transformations and physical
|
|
// sizes to be used to determine
|
|
// the suitablity of a font
|
|
|
|
EXTLOGFONTW *pelfwWishSrc, // defines the font that is wished
|
|
// for by the application
|
|
|
|
PWSZ pwszFaceName, // The sought name.
|
|
|
|
ULONG ulMaxPenalty, // a cutoff for the sum of all the
|
|
// individual penalties of each of the
|
|
// fields of the EXTLOGFONT structure.
|
|
// If the sum of all the penalties
|
|
// associated with a physical font
|
|
// is greater than this cutoff, then
|
|
// the phyisical font is rejected
|
|
// as a potential match.
|
|
|
|
FLONG fl, // This is a set of flags defining
|
|
// how mapping is to proceed and/or
|
|
// various parameters are to be
|
|
// interpreted. The flags that are
|
|
// supported are:
|
|
//
|
|
// FM_BIT_PIXEL_COORD
|
|
//
|
|
// If this flag is not present, then the
|
|
// dimensionful quantities in the
|
|
// logical font are in world coordinates.
|
|
// If this flag is present then the
|
|
// dimensionful (length like) quantities
|
|
// in the logical font are in pixel
|
|
// coordinates (one unit = one pixel).
|
|
// This bit is set only for stock
|
|
// fonts, which are defined by the device
|
|
// driver and are to be transformation
|
|
// independent.
|
|
|
|
FLONG *pflSim, // a place to put the simulation
|
|
// flags.
|
|
|
|
POINTL *pptlSim, // this recieves the height- and width-
|
|
// scaling factor for bitmap fonts
|
|
|
|
FLONG *pflAboutMatch, // This returns information about how
|
|
// the match was achieved. Flags
|
|
// supported are:
|
|
//
|
|
// MAPFONT_FOUND_NAME
|
|
//
|
|
// This flag indicates that a facename
|
|
// was found by the mapper.
|
|
//
|
|
// MAPFONT_ALTFACE_USED
|
|
//
|
|
// This flag indicates that the facename
|
|
// found was an alternate or substitute
|
|
// facename.
|
|
BOOL bIndexFont_ // font MUST support ETO_GLYPH_INDEX
|
|
)
|
|
{
|
|
ASSERTGDI(!(fl & ~FM_BIT_PIXEL_COORD),"GDISRV!ppfeGetAMatch -- invalid fl\n");
|
|
|
|
PPFEGETAMATCH_DEBUG_MACRO_1;
|
|
|
|
MAPPER
|
|
mapper(
|
|
&dco
|
|
, pflSim
|
|
, pptlSim
|
|
, pflAboutMatch
|
|
, pelfwWishSrc
|
|
, pwszFaceName
|
|
, ulMaxPenalty
|
|
, bIndexFont_
|
|
, fl
|
|
);
|
|
|
|
// Currently there is no way for the MAPPER constructor
|
|
// to fail. In the future it may be able to fail and we
|
|
// will need to check here.
|
|
|
|
ASSERTGDI(mapper.bValid(),"GDISRV!ppfeGetAMatch -- invalid mapper\n");
|
|
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_DUMP_FHOBJ)
|
|
{
|
|
if (mapper.bDeviceFontsExist())
|
|
{
|
|
DEVICE_PFTOBJ pftoDevice;
|
|
PFFOBJ pffo(pftoDevice.pPFFGet(dco.pdc->hdev()));
|
|
if (pffo.bValid())
|
|
{
|
|
FHOBJ fhoFamily(&pffo.pPFF->pfhFamily);
|
|
FHOBJ fhoFace(&pffo.pPFF->pfhFace);
|
|
|
|
DbgPrint("\n\n\tDumping Device Family Names\n");
|
|
fhoFamily.vPrint((VPRINT) DbgPrint);
|
|
|
|
DbgPrint("\n\n\tDumping Device Face Names\n");
|
|
fhoFace.vPrint((VPRINT) DbgPrint);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("\n\tTHERE ARE NO DEVICE FONTS!\n\n");
|
|
}
|
|
PUBLIC_PFTOBJ pfto;
|
|
FHOBJ fhoFamily(&pfto.pPFT->pfhFamily);
|
|
FHOBJ fhoFace(&pfto.pPFT->pfhFace);
|
|
|
|
DbgPrint("\n\n\tDumping Engine Family Names\n");
|
|
fhoFamily.vPrint((VPRINT) DbgPrint);
|
|
DbgPrint("\n\n\tDumping Engine Face Names\n");
|
|
fhoFace.vPrint((VPRINT) DbgPrint);
|
|
}
|
|
#endif
|
|
|
|
UNIVERSAL_FONT_ID ufi;
|
|
if( dco.pdc->bForcedMapping( &ufi ) )
|
|
{
|
|
// If we got here we are playing back an EMF spoolfile
|
|
// which was generated on a remote machine. We must do
|
|
// forced mapping based on UFI's
|
|
|
|
if( mapper.bFoundForcedMatch( &ufi ) )
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
else
|
|
{
|
|
WARNING1("ppfeGetAMatch: bFoundForceMatch "
|
|
"failed to find a match");
|
|
}
|
|
}
|
|
|
|
// check the device fonts first (if they exist)
|
|
|
|
DEVICE_PFTOBJ pftoDevice;
|
|
if (mapper.bDeviceFontsExist())
|
|
{
|
|
PFF *pPFF;
|
|
|
|
// put mapper in "check device fonts" state
|
|
|
|
mapper.vDeviceFonts();
|
|
|
|
if (pPFF = pftoDevice.pPFFGet(dco.hdev()))
|
|
{
|
|
PFFOBJ pffo(pPFF);
|
|
if (pffo.bValid())
|
|
{
|
|
if
|
|
(
|
|
mapper.bFoundExactMatch(&pffo.pPFF->pfhFamily) ||
|
|
mapper.bFoundExactMatch(&pffo.pPFF->pfhFace)
|
|
)
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
if( mapper.bDeviceOnly() )
|
|
{
|
|
FONTHASH **ppfh = &pffo.pPFF->pfhFamily;
|
|
ENUMFHOBJ fho(ppfh);
|
|
|
|
*pflSim = 0;
|
|
*pflAboutMatch = 0;
|
|
pptlSim->x = pptlSim->y = 1;
|
|
|
|
PPFEGETAMATCH_DEBUG_RETURN(fho.ppfeFirst());
|
|
}
|
|
}
|
|
}
|
|
|
|
// If an exact match was not found check the Engine fonts
|
|
|
|
PUBLIC_PFTOBJ pftoPublic;
|
|
mapper.vNotDeviceFonts(); // put mapper in "check engine fonts" state
|
|
if
|
|
(
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFamily) ||
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFace)
|
|
)
|
|
{
|
|
PFEOBJ pfeo(mapper.ppfeRet());
|
|
IFIOBJ ifio(pfeo.pifi());
|
|
|
|
// The assumption is that at small sizes, TT will
|
|
// look bad so we may want to consider trying one
|
|
// of the small bitmap fonts. However, we do not
|
|
// want to do this if the text is rotated (lfOrientation)
|
|
// of if the caller has specified a width (which implies
|
|
// horizontal stretching/compression).
|
|
//
|
|
// We also don't do it for fixed pitch (no fixed pitch
|
|
// small bitmap font) or non-ANSI character set.
|
|
//
|
|
// Bitmap fonts can only be substituted for the screen DC
|
|
|
|
if ( ifio.bTrueType() &&
|
|
(mapper.fl & FM_BIT_DISPLAY_DC) &&
|
|
(pelfwWishSrc->elfLogFont.lfOrientation == 0) &&
|
|
(pelfwWishSrc->elfLogFont.lfWidth == 0) &&
|
|
(mapper.jMapCharSet == ANSI_CHARSET) &&
|
|
((pelfwWishSrc->elfLogFont.lfPitchAndFamily & LOGFONT_PITCH_SET) == VARIABLE_PITCH) &&
|
|
mapper.bSmallFontWeight() &&
|
|
mapper.bTooSmallForTrueType()
|
|
)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("Requested height is too small"
|
|
" for this TrueType font\n");
|
|
}
|
|
#endif
|
|
if (!(mapper.bCalled_bGetFaceName()))
|
|
{
|
|
// If we can find an appropriate small bitmap font,
|
|
// redo the mapping with the small font facename.
|
|
|
|
mapper.vSmallFontHack();
|
|
if (mapper.bGetFaceName())
|
|
{
|
|
// put mapper in "check engine fonts" state
|
|
|
|
mapper.vReset();
|
|
mapper.vNotDeviceFonts();
|
|
if
|
|
(
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFamily) ||
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFace) ||
|
|
mapper.ppfeRet()
|
|
)
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
}
|
|
|
|
// No suitable small font, so stick with original.
|
|
|
|
PPFEGETAMATCH_DEBUG_RETURN(pfeo.ppfeGet());
|
|
}
|
|
else
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
|
|
// If you get here, and ppfeRet != 0 then then lfFaceName
|
|
// has been matched by either the device or gdi. In either
|
|
// case, we terminate the search and return the best match
|
|
// found. This is somewhat incompatible with Windows 3.1
|
|
// which considers FaceName less important that pitch
|
|
// and family. Windows 3.1 would continue the search over
|
|
// all available fonts in order to get a better match.
|
|
|
|
if (mapper.ppfeRet())
|
|
{
|
|
PFEOBJ pfeo(mapper.ppfeRet());
|
|
IFIOBJ ifio(pfeo.pifi());
|
|
|
|
// The assumption is that at small sizes, TT will
|
|
// look bad so we may want to consider trying one
|
|
// of the small bitmap fonts. However, we do not
|
|
// want to do this if the text is rotated (lfOrientation)
|
|
// of if the caller has specified a width (which implies
|
|
// horizontal stretching/compression).
|
|
//
|
|
// We also don't do it for fixed pitch (no fixed pitch
|
|
// small bitmap font) or non-ANSI character set.
|
|
|
|
if
|
|
(
|
|
ifio.bTrueType()
|
|
&& (pelfwWishSrc->elfLogFont.lfOrientation == 0)
|
|
&& (pelfwWishSrc->elfLogFont.lfWidth == 0)
|
|
&& (mapper.jMapCharSet == ANSI_CHARSET)
|
|
&& ((pelfwWishSrc->elfLogFont.lfPitchAndFamily & LOGFONT_PITCH_SET) == VARIABLE_PITCH)
|
|
&& mapper.bSmallFontWeight()
|
|
&& mapper.bTooSmallForTrueType()
|
|
)
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("Requested height is too small"
|
|
" for this TrueType font\n");
|
|
}
|
|
#endif
|
|
if (!(mapper.bCalled_bGetFaceName()))
|
|
{
|
|
// If we can find an appropriate small bitmap font,
|
|
// redo the mapping with the small font facename.
|
|
|
|
mapper.vSmallFontHack();
|
|
if (mapper.bGetFaceName())
|
|
{
|
|
// put mapper in "check engine fonts" state
|
|
|
|
mapper.vReset();
|
|
mapper.vNotDeviceFonts();
|
|
if
|
|
(
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFamily) ||
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFace) ||
|
|
mapper.ppfeRet()
|
|
)
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
}
|
|
|
|
// No suitable small font, so stick with original.
|
|
|
|
PPFEGETAMATCH_DEBUG_RETURN(pfeo.ppfeGet());
|
|
}
|
|
else
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
|
|
// If you get to here then the face name has not been found
|
|
// in either the Device or GDI fonts. A font of a different
|
|
// face name will have to be substituted. Try to match to a
|
|
// Device font, but the match better be a damn good one!
|
|
|
|
if (mapper.bDeviceFontsExist())
|
|
{
|
|
mapper.vAttemptDeviceMatch();
|
|
if (mapper.ppfeRet())
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
|
|
// Up until now we've reject fonts whose charset doesn't
|
|
// match the requested charset even though the facename
|
|
// matches. At this point we allow for the possibility
|
|
// of chosing a font whose charset doesn't match. However,
|
|
// we will make the penalty so high that for such a font that
|
|
// if any other font exists whose charset does match,
|
|
// it will alwats beat the font whose charset doesn't match.
|
|
|
|
mapper.vAcceptDiffCharset();
|
|
|
|
// Well ... we are left with attempting to match to GDI fonts.
|
|
// Since the original request face name was a flop,
|
|
// I will attempt a suitable GDI FaceName.
|
|
|
|
if( !(mapper.bCalled_bGetFaceName()))
|
|
{
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
DbgPrint("\n\tAttempting to match to an"
|
|
" engine font of a different name\n");
|
|
#endif
|
|
mapper.bGetFaceName();
|
|
mapper.vReset();
|
|
mapper.vNotDeviceFonts(); // put mapper in "check engine fonts" state
|
|
if
|
|
(
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFamily) ||
|
|
mapper.bFoundExactMatch(&pftoPublic.pPFT->pfhFace)
|
|
)
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
if (mapper.ppfeRet())
|
|
{
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
}
|
|
|
|
// We are in big trouble now! To recount the story to this point.
|
|
// We have failed to match the facename against either the device
|
|
// or engine fonts. Then we failed to match against any device font
|
|
// even though we ignored the name. Finally, we could not match
|
|
// default facenames against the GDI fonts.
|
|
// Now we call the emergency routine that gets a font, any font.
|
|
|
|
mapper.vEmergency();
|
|
|
|
// Either vEmergency() got a font or it didn't. It doesn't matter,
|
|
// we have no choice but to return at this point.
|
|
|
|
PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet());
|
|
}
|
|
/******************************Member*Function*****************************\
|
|
* MAPPER::vAttemptDeviceMatch() *
|
|
* *
|
|
* Considers every device font and tries to find the best match. *
|
|
* Facenames are ignored. *
|
|
* *
|
|
* History: *
|
|
* Thu 11-Mar-1993 15:44:59 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID MAPPER::vAttemptDeviceMatch()
|
|
{
|
|
FONTHASH **ppfh = (FONTHASH**) NULL;
|
|
PFE *ppfeRet = (PFE*) NULL;
|
|
PFE *ppfe;
|
|
BYTE jCharSet = DEFAULT_CHARSET;
|
|
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
DbgPrint("\n\tMAPPER::vAtteptDeviceMatch()\n");
|
|
}
|
|
#endif
|
|
|
|
// If the application asked for symbol then I will only allow GDI
|
|
// to do font substitution. This request will probably end with
|
|
// WingDings
|
|
|
|
if (jMapCharSet == SYMBOL_CHARSET)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DEVICE_PFTOBJ pftoDevice;
|
|
PFF *pPFF;
|
|
if (pPFF = pftoDevice.pPFFGet(pdco->hdev()))
|
|
{
|
|
PFFOBJ pffo(pPFF);
|
|
|
|
if (pffo.bValid())
|
|
{
|
|
ppfh = &pffo.pPFF->pfhFamily;
|
|
}
|
|
}
|
|
|
|
if (ppfh == (FONTHASH**) NULL)
|
|
{
|
|
RIP("MAPPER::vAttemptDeviceMatch() -- invalid FONTHASH\nReturning NULL");
|
|
return;
|
|
}
|
|
|
|
// Set a very stringent pruning criteria!
|
|
|
|
vReset(FM_WEIGHT_ITALIC-1);
|
|
|
|
// reset the mapping information
|
|
|
|
fl |= FM_BIT_DEVICE_FONT;
|
|
|
|
// Prepare to enumerate through all the device fonts
|
|
|
|
ENUMFHOBJ fho(ppfh);
|
|
for (ppfe = fho.ppfeFirst(); ppfe; ppfe = fho.ppfeNext())
|
|
{
|
|
PFEOBJ pfeo(ppfe);
|
|
|
|
|
|
|
|
|
|
if (this->bNearMatch(pfeo,&jCharSet))
|
|
{
|
|
DUMP_CHOSEN_FONT(pfeo);
|
|
vSetBest(ppfe, TRUE, jCharSet);
|
|
|
|
if (this->ulPenaltyTotal == 0)
|
|
{
|
|
// this is a slimey hack to get some excel scenario to work the same
|
|
// way it does on NT as it does on Win 95. In this scenario excel
|
|
// is asking for Ms Sans Serif on an HP Laser 4Si. On Win 95 this
|
|
// maps to Arial. However, on NT we map to Univers or some other
|
|
// font before we can even look at Arial as a result what used to
|
|
// print on 3 pages now prints on 6. Since the scenario is used for
|
|
// benchmarking this is undesireable. To fix this we penalize
|
|
// any fonts that are not Arial so that we will at least look at Arial
|
|
// and then choose it.
|
|
|
|
if(_wcsicmp( pfeo.pwszFamilyName(), L"Arial"))
|
|
{
|
|
this->ulPenaltyTotal += 1;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
this->ulMaxPenalty = this->ulPenaltyTotal; // prune the search
|
|
}
|
|
else
|
|
{
|
|
DUMP_REJECTED_FONT(pfeo);
|
|
}
|
|
}
|
|
|
|
if (this->ppfeBest)
|
|
{
|
|
// record code page, needed for correct
|
|
// code page to unicode translation
|
|
|
|
*pflAboutMatch |= (ulCharsetToCodePage((UINT) jCharSet) << 8);
|
|
}
|
|
|
|
// If we still don't have a device font and this is the generic
|
|
// printer driver then just take the first device font.
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* MAPPER::vEmergency *
|
|
* *
|
|
* Go through the Engine fonts without regard to name ... *
|
|
* *
|
|
* History: *
|
|
* Fri 05-Mar-1993 08:44:38 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID MAPPER::vEmergency()
|
|
{
|
|
int iCount;
|
|
PFE *ppfe;
|
|
BYTE jCharSet = DEFAULT_CHARSET;
|
|
BYTE jMatchCharset = DEFAULT_CHARSET;
|
|
|
|
#if DBG
|
|
if (gflFontDebug & DEBUG_MAPPER)
|
|
{
|
|
WARNING("\n\tMAPPER::vEmergency\n");
|
|
}
|
|
#endif
|
|
|
|
PUBLIC_PFTOBJ pftoPublic;
|
|
vReset();
|
|
fl &= ~FM_BIT_DEVICE_FONT;
|
|
|
|
ENUMFHOBJ fho(&pftoPublic.pPFT->pfhFamily);
|
|
for
|
|
(
|
|
iCount = 0, ppfe = fho.ppfeFirst();
|
|
ppfe && (iCount < FM_EMERGENCY_CUTOFF);
|
|
ppfe = fho.ppfeNext(), iCount++
|
|
)
|
|
{
|
|
PFEOBJ pfeo(ppfe);
|
|
if (this->bNearMatch(pfeo,&jCharSet))
|
|
{
|
|
DUMP_CHOSEN_FONT(pfeo);
|
|
vSetBest(ppfe, FALSE, jCharSet);
|
|
|
|
// bNearMatch modifies jCharSet even if it doesn't find a match
|
|
// so subsquent calls to bNearMatch could change jCharSet to
|
|
// something else. Save a copy for use down below.
|
|
|
|
jMatchCharset = jCharSet;
|
|
|
|
if (this->ulPenaltyTotal == 0)
|
|
{
|
|
*pflAboutMatch |= (ulCharsetToCodePage((UINT) jCharSet) << 8);
|
|
return;
|
|
}
|
|
this->ulMaxPenalty = this->ulPenaltyTotal; // prune the search
|
|
}
|
|
else
|
|
{
|
|
DUMP_REJECTED_FONT(pfeo);
|
|
}
|
|
}
|
|
|
|
// We can actually improve it here.
|
|
// If the device is not a plotter, then we can actually
|
|
// give it any bitmap font.
|
|
// We could attempt to match against any bitmap font.
|
|
|
|
if (!this->ppfeBest)
|
|
{
|
|
this->ppfeBest = gppfeMapperDefault;
|
|
this->ulBestTime = gppfeMapperDefault->ulTimeStamp;
|
|
}
|
|
|
|
// record the code page, needed for correct
|
|
// code page to unicode translation
|
|
|
|
*pflAboutMatch |= (ulCharsetToCodePage((UINT) jMatchCharset) << 8);
|
|
}
|