|
|
/******************************Module*Header*******************************\
* Module Name: fontmap.cxx * * * * Routines for mapping fonts. * * * * Created: 17-Jun-1992 11:12:16 * * Author: Kirk Olynyk [kirko] * * * * Copyright (c) 1992-1999 Microsoft Corporation * \**************************************************************************/
#include "precomp.hxx"
extern "C" VOID vInitMapper(); extern "C" NTSTATUS DefaultFontQueryRoutine(IN PWSTR, IN ULONG, IN PVOID, IN ULONG, IN PVOID, IN PVOID);
#pragma alloc_text(INIT, vInitMapper)
#pragma alloc_text(INIT, DefaultFontQueryRoutine)
// external procedures from draweng.cxx
VOID vArctan(EFLOAT, EFLOAT,EFLOAT&, LONG&);
// external procedure from FONTSUB.CXX
#ifdef LANGPACK
extern "C" BOOL EngLpkInstalled(); #endif
/*** 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
static const WCHAR gpwszDefFixedSysFaceName[] = 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: * 2-Jul-1997 -by- Yung-Jen Tony Tsai [yungt] * 17-Jan-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/
BYTE jMapCharset(BYTE lfCharSet, PFEOBJ &pfeo) { BYTE jCharSet; BYTE jLinkedCharSet; BYTE * ajCharSets; BYTE * ajCharSetsEnd; BYTE * pjCharSets;
IFIMETRICS *pifi = pfeo.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:
ajCharSets = (BYTE *)pifi + pifi->dpCharSets; ajCharSetsEnd = ajCharSets + MAXCHARSETS;
for (pjCharSets = ajCharSets; pjCharSets < ajCharSetsEnd; pjCharSets++) { if (*pjCharSets == lfCharSet) { return( lfCharSet ); } if (*pjCharSets == DEFAULT_CHARSET) // terminator
{
// The charset did not support in base font.
// We need to check the charset of linked font
// If there is one, then we get it
// otherwise, we return BaseFont.ajCharSets[0]
jCharSet = ajCharSets[0]; break; } }
if (pfeo.pGetLinkedFontEntry()) { // No charset in the base font matches the requested charset.
// And this base font has lined font. Then we should check
// the charsets in the linked font to see if there is a
// match there as well.
PLIST_ENTRY p = pfeo.pGetLinkedFontList()->Flink; while ( p != pfeo.pGetLinkedFontList() ) { PPFEDATA ppfeData = CONTAINING_RECORD(p,PFEDATA,linkedFontList); PFEOBJ pfeoEudc(ppfeData->appfe[PFE_NORMAL]);
pifi = pfeoEudc.pifi();
if (pifi->dpCharSets == 0 && pifi->jWinCharSet == lfCharSet) { return ( lfCharSet ); } else if (pifi->dpCharSets) { ajCharSets = (BYTE *)pifi + pifi->dpCharSets; ajCharSetsEnd = ajCharSets + MAXCHARSETS;
for (pjCharSets = ajCharSets; pjCharSets < ajCharSetsEnd; pjCharSets++) { if (*pjCharSets == lfCharSet) { return ( lfCharSet ); } if (*pjCharSets == DEFAULT_CHARSET) // terminator
{
break; // End of for loop
} } } p = p->Flink; } }
return(jCharSet);
}
/******************************Public*Routine******************************\
* GreGetCannonicalName( * * The input is the zero terminated name of the form * * foo_XXaaaYYbbb...ZZccc * * where XX, YY, ZZ are numerals (arbitrary number of them) and * aaa, bbb, ccc are not numerals, i.e. spaces, or another '_' signs or * letters with abbreviated axes names. * * This face name will be considered equivalent to face name foo * with DESIGNVECTOR [XX,YY, ...ZZ], number of axes being determined * by number of numeral sequences. * * * Effects: * * History: * 25-Jun-1997 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/
#define IS_DIGIT(x) (((x) >= L'0') && ((x) <= L'9'))
#define GET_DIGIT(X) ((X) - L'0')
#define WC_UNDERSCORE L'_'
VOID GreGetCannonicalName( const WCHAR *pwszIn, // foo_XX_YY
WCHAR *pwszOut, // Cannonical and capitalized name FOO
ULONG *pcAxes, DESIGNVECTOR *pdv // [XX,YY] on out
) { // The input is the zero terminated name of the form
//
// foo_XXaaaYYbbb...ZZccc
//
// where XX, YY, ZZ are numerals (arbitrary number of them) and
// aaa, bbb, ccc are not numerals, i.e. spaces, or another '_' signs or
// letters with abbreviated axes names.
//
// This face name will be considered equivalent to face name foo
// with DESIGNVECTOR [XX,YY, ...ZZ], number of axes being determined
// by number of numeral sequences.
const WCHAR *pwc; ULONG cAxes = 0; ULONG cwc;
for ( pwc = pwszIn ; (*pwc) && !((*pwc == WC_UNDERSCORE) && IS_DIGIT(pwc[1])); pwc++ ) { // do nothing;
}
// copy out, zero terminate
// Sundown safe truncation
cwc = (ULONG)(pwc - pwszIn); memcpy(pwszOut, pwszIn, cwc * sizeof(WCHAR)); pwszOut[cwc] = L'\0';
// If we found at least one WC_UNDERSCORE followed by the DIGIT
// we have to compute DV. Underscore followed by the DIGIT is Adobe's rule
if ((*pwc == WC_UNDERSCORE) && IS_DIGIT(pwc[1])) { // step to the next character behind undescore
pwc++;
while (*pwc) { // go until you hit the first digit
for ( ; *pwc && !IS_DIGIT(*pwc) ; pwc++) { // do nothing
}
if (*pwc) { // we have just hit the digit
ULONG dvValue = GET_DIGIT(*pwc);
// go until you hit first nondigit or the terminator
pwc++;
for ( ; *pwc && IS_DIGIT(*pwc); pwc++) { dvValue = dvValue * 10 + GET_DIGIT(*pwc); }
pdv->dvValues[cAxes] = (LONG)dvValue;
// we have just parsed a string of numerals
cAxes++; } } }
// record the findings
*pcAxes = cAxes; pdv->dvNumAxes = cAxes; pdv->dvReserved = STAMP_DESIGNVECTOR; }
/******************************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. \**************************************************************************/
extern "C" 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 ENUMLOGFONTEXDVW *pelfwWishSrc, // wish list in World Coordinates
const WCHAR * pwszFaceName_, ULONG ulMaxPenaltySrc, // pruning criteria
BOOL bIndexFont_, FLONG flOptions = 0 ) {
fl = 0; ifio.vSet((IFIMETRICS*) NULL); pdco = pdcoSrc; pelfwWish = pelfwWishSrc; pwszFaceName = pwszFaceName_;
// check if this face name might a long foo_XX_YY name of the instance
ULONG cAxes; flMM = 0;
GreGetCannonicalName( pwszFaceName_, // foo_XX_YY
this->awcBaseName, // Cannonical and capitalized name FOO
&cAxes, &this->dvWish);
ppfeMMInst = NULL; // no instances found yet that match this instances base font
// if GreGetCannonicalName did not find any axes info in the name,
// but the design vector is specified explicitly we use it.
// If however, cAxes from the name is not zero, we ignore
// whatever may be specified in the design vector explicitely.
if (cAxes == 0) { if (pelfwWish->elfDesignVector.dvNumAxes) { RtlCopyMemory( &this->dvWish, &pelfwWish->elfDesignVector, SIZEOFDV(pelfwWish->elfDesignVector.dvNumAxes) ); } else { awcBaseName[0] = 0; } } else { flMM |= FLMM_DV_FROM_NAME; }
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->elfEnumLogfontEx.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->elfEnumLogfontEx.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->elfEnumLogfontEx.elfLogFont.lfWeight == FW_NORMAL ) || ( pelfwWish->elfEnumLogfontEx.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->elfEnumLogfontEx.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; } // 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; }
// Copy over the requested sizes. We will transform them to device
// coordinates later if needed.
lDevWishHeight = pelfwWish->elfEnumLogfontEx.elfLogFont.lfHeight;
lDevWishWidth = ABS( pelfwWish->elfEnumLogfontEx.elfLogFont.lfWidth );
{ // Lock the PDEV to get some important information
PDEVOBJ pdo((HDEV)pdco->pdc->ppdev());
ulLogPixelsX = pdo.ulLogPixelsX(); ulLogPixelsY = pdo.ulLogPixelsY();
fl |= (pdo.flTextCaps() & TC_RA_ABLE) ? FM_BIT_DEVICE_RA_ABLE : 0; fl |= (pdo.flTextCaps() & TC_CR_90) ? FM_BIT_DEVICE_CR_90_ALL : 0; fl |= (pdo.cFonts()) ? FM_BIT_DEVICE_HAS_FONTS : 0; fl |= (pdo.ulTechnology() == DT_PLOTTER) ? FM_BIT_DEVICE_PLOTTER : 0; fl |= (pdo.ulTechnology() == DT_CHARSTREAM) ? FM_BIT_DEVICE_ONLY : 0;
ASSERTGDI( !((pdo.ulTechnology() == DT_PLOTTER) && (pdo.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.pdevinfoNotDynamic()->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->elfEnumLogfontEx.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->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily & (LOGFONT_PITCH_SET) ) == FIXED_PITCH ) { Signature |= DFS_FIXED_PITCH; }
if(( pelfwWish->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily & (FF_SET) ) == FF_ROMAN ) { // the font family is only important for variable pitch fonts
Signature |= DFS_FF_ROMAN; } else if(( pelfwWish->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily & (LOGFONT_PITCH_SET) ) == DEFAULT_PITCH && ( pelfwWish->elfEnumLogfontEx.elfLogFont.lfPitchAndFamily & (FF_SET) ) == FF_MODERN ) { // Windows95 may sometimes chooses Courier instead of Courier New
Signature |= DFS_FIXED_PITCH; }
if( fl & FM_BIT_VERT_FACE_REQUEST ) { Signature |= DFS_VERTICAL; }
// 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) { PFELINK *ppfel; 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 (ppfel = pbkt->ppfelEnumHead; ppfel; ppfel = ppfel->ppfelNext) { PFEOBJ pfeo(ppfel->ppfe); 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 ); } } } }
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()
iOrientationDevice = pelfwWish->elfEnumLogfontEx.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->elfEnumLogfontEx.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->elfEnumLogfontEx.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->elfEnumLogfontEx.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->elfEnumLogfontEx.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->elfEnumLogfontEx.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: * * 24-Sept-1196 -by- Xudong Wu [TesieW] * * Add checking on Private/Embedded fonts * * 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. * \**************************************************************************/
extern PW32PROCESS gpidSpool; // global
int MAPPER::bNearMatch(PFEOBJ &pfeo, BYTE *pjCharSet, BOOL bEmergency) { int iRet = FALSE; // return value
ULONG ul; // Temp variable.
BYTE jAsk, jHav; PFE *ppfeNew = pfeo.ppfeGet();
// 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 ); }
// private pfe NOT added by the current process.
// spooler has the right to access all the fonts
if (!pfeo.bEmbPvtOk() && (gpidSpool != (PW32PROCESS)W32GetCurrentProcess())) { ulPenaltyTotal = FM_REJECT; return( iRet ); }
// Skip the PFE_UFIMATCH fonts since they are added to the public font table temporarily
// for remote printing. These PFEs should be mapped only by bFoundForcedMatch() calls.
if (pfeo.bUFIMatchOnly()) { ulPenaltyTotal = FM_REJECT; return( iRet ); }
// spooler has the right to access all the fonts
if (pfeo.bPrivate() && (gpidSpool != (PW32PROCESS)W32GetCurrentProcess())) { // 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 (pfeo.bEmbedOk()) { if (!(pelfwWish->elfEnumLogfontEx.elfLogFont.lfClipPrecision & CLIP_EMBEDDED)) { #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 );
MSBREAKPOINT("msCheckForMMFont");
if ((fl & FM_BIT_BASENAME_MATCHED) && !(pfeo.pifi()->flInfo & FM_INFO_TECH_MM)) { CHECKPRINT("CheckForMMFont", FM_REJECT ); ulPenaltyTotal = FM_REJECT; return( iRet ); }
// 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->elfEnumLogfontEx.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 = (BYTE)(ifio.lfPitchAndFamily() & FF_SET); jAsk = (BYTE)(pelfwWish->elfEnumLogfontEx.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 = (BYTE)(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 = (BYTE)((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);
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, except, we do not want to give a
// big weight to the charset, the app does not care. We still want to give
// a small preference to the one that matches MAPPER::DefaultCharSet
*pjCharSet = jMapCharset(jMapCharSet, pfeo);
if ((jMapCharSet == DEFAULT_CHARSET) && !(fl & FM_BIT_MS_SHELL_DLG)) { if (MAPPER::DefaultCharset != *pjCharSet) { CHECKPRINT("CharSet",1); ulPenaltyTotal += 2; if (bNoMatch(ppfeNew)) { return( iRet ); } } } }
}
MSBREAKPOINT("msCheckFamilyName");
if (bEmergency) { // we only check facename in case we are in vEmergency() loop,
// else, face name match is guaranteed.
BOOL bAliasMatch;
if (!pfeo.bCheckFamilyName(pwszFaceName,0, &bAliasMatch)) { // no facename match, add penalty
CHECKPRINT("FamilyName",FM_WEIGHT_FACENAME); ulPenaltyTotal += FM_WEIGHT_FACENAME; } else { if (bAliasMatch) { // add a small penalty for matching alias, not the real name
CHECKPRINT("Alias Match",FM_WEIGHT_DEVICE_ALIAS); ulPenaltyTotal += FM_WEIGHT_DEVICE_ALIAS; } }
if (bNoMatch(ppfeNew)) { return( iRet ); } }
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.pwszFamilyName() != U_COMMERCIAL_AT ) { CHECKPRINT("VertAttr",FM_REJECT); ulPenaltyTotal = FM_REJECT; return(iRet); } } else if (*ifio.pwszFamilyName() == U_COMMERCIAL_AT) { // if the user hasn't requested a @face font then don't map to one
CHECKPRINT("VertAttr",FM_REJECT); ulPenaltyTotal = FM_REJECT; return(iRet); } }
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->elfEnumLogfontEx.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.
// bodind:
// we need to eliminate raster fonts on non square resolution printers
// you can not get any type of wysiwig with these
if (ifio.lfOutPrecision() == OUT_RASTER_PRECIS) { if ( (fl & FM_BIT_DEVICE_PLOTTER) || (pdco->flGraphicsCaps() & GCAPS_NUP) || !(((fl & FM_BIT_DEVICE_RA_ABLE) && (ulLogPixelsX == ulLogPixelsY)) || 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->elfEnumLogfontEx.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 ); }
// new value, reject non ps fonts
if ( (pelfwWish->elfEnumLogfontEx.elfLogFont.lfOutPrecision == OUT_PS_ONLY_PRECIS) && !(ifio.pifi->flInfo & FM_INFO_TECH_TYPE1)) { ulPenaltyTotal = FM_REJECT; CHECKPRINT("OutPrecision: font isn't PostScript font", 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->elfEnumLogfontEx.elfLogFont.lfOutPrecision == OUT_SCREEN_OUTLINE_PRECIS) // the following line will ensure that when user are not specifying lfOutPrecision,
// TrueType will be prefered when Lpk is installed.
// this will ensure correct font to be choosen in Arabic/Hebrew/Shaping printing
// while still allowing application to specify exactely what lfOutPrecision they want
// by selecting lfOutPrecision OUT_RASTER_PRECIS, OUT_DEVICE_PRECIS or OUT_PS_ONLY_PRECIS
|| ( EngLpkInstalled() && (pelfwWish->elfEnumLogfontEx.elfLogFont.lfOutPrecision != OUT_RASTER_PRECIS) && (pelfwWish->elfEnumLogfontEx.elfLogFont.lfOutPrecision != OUT_DEVICE_PRECIS) && (pelfwWish->elfEnumLogfontEx.elfLogFont.lfOutPrecision != OUT_PS_ONLY_PRECIS))
// gdi will map to tt, driver will do device font substitution when it
// finds appropriate, i.e. when glyphs needed for printout exist
// the device font that is being substituted
|| (pdco->flGraphicsCaps() & GCAPS_SCREENPRECISION) ) && ((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->elfEnumLogfontEx.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 { if( ulFontAspect == 0 ) { ulPenaltyTotal = FM_REJECT; return( iRet ); } 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) ) { if( ptlSimulations.y == 0 ) { ulPenaltyTotal = FM_REJECT; return( iRet ); } 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; }
if (ul && ifio.b90DegreeRotations()) { if (ul > (ULONG) iOrientationDevice) { ul = (ULONG) (- (LONG) ul); } ul = ul % ORIENTATION_90_DEG; } } 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 ); } } }
// The last thing we do is always design vector.
// If everything else matchhes exactly but the design vector
// we will record the pfe and have the atm driver create the instance
// corresponding to this design vector.
MSBREAKPOINT("msCheckDesignVector");
{ DESIGNVECTOR *pdv, *pdvWish;
if (fl & FM_BIT_BASENAME_MATCHED) { // the name takes precedance, ie if we have explicit dv == [UU,VV]
// as well as dv specified through font's family
// name of the form foo_XX_YY, we ignore dv in ENUMLOGFONTEXDV
// and use the one specified by the name, [XX,YY] in this case.
pdvWish = &dvWish; } else { pdvWish = (DESIGNVECTOR *)&pelfwWish->elfDesignVector; }
if (pdvWish->dvNumAxes) { pdv = ifio.pdvDesVect();
if ( pdv && pdv->dvNumAxes && (pdvWish->dvNumAxes == pdv->dvNumAxes) && (ulPenaltyTotal <= 35000) ) { ppfeMMInst = ppfeNew; }
if ( !pdv || (pdvWish->dvNumAxes != pdv->dvNumAxes) || memcmp(pdvWish->dvValues, pdv->dvValues, pdv->dvNumAxes*sizeof(LONG)) ) {
CHECKPRINT("DesignVector",FM_REJECT); ulPenaltyTotal = FM_REJECT; 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 ) { PFELINK *ppfelBest = NULL, *ppfel;
HASHBUCKET *apbkt[3]; BYTE ajCharSet[3];
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!
const WCHAR * pwszTarg = this->pwszFaceName;
// Attempt to locate the name.
#define I_ORIGINAL 0
#define I_ALTERNATE 1
#define I_BASE 2
apbkt[I_ORIGINAL] = apbkt[I_ALTERNATE] = apbkt[I_BASE] = NULL; ajCharSet[I_ORIGINAL] = ajCharSet[I_BASE] = ajCharSet[I_ALTERNATE] = (BYTE)pelfwWish->elfEnumLogfontEx.elfLogFont.lfCharSet;
FONTSUB* pfsub = pfsubGetFontSub(pwszTarg, (BYTE)pelfwWish->elfEnumLogfontEx.elfLogFont.lfCharSet);
if (pfsub) { // charsets specified or not in the substitution entry ?
if (pfsub->fcsAltFace.fjFlags & FJ_NOTSPECIFIED) { // old style substitution, no 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.
// When 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 { apbkt[I_ORIGINAL] = fho.pbktSearch(pwszTarg,(UINT*)NULL); }
// now search for the bucket corresponding to the cannonical name if any
// We will only do this for FAMILY i.e menu names, not for face names:
if (awcBaseName[0] && (fht == FHT_FAMILY)) apbkt[I_BASE] = fho.pbktSearch(this->awcBaseName,(UINT*)NULL, NULL, FALSE);
if (!apbkt[I_ORIGINAL] && !apbkt[I_ALTERNATE] && !apbkt[I_BASE]) { 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 < 3; 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; }
if (i == I_BASE) { fl |= FM_BIT_BASENAME_MATCHED; } else { fl &= ~FM_BIT_BASENAME_MATCHED; }
for ( ppfelBest = NULL, ppfel = apbkt[i]->ppfelEnumHead; ppfel; ppfel = ppfel->ppfelNext ) { #if DBG
if (gflFontDebug & DEBUG_MAPPER && ppfel->ppfe == ppfeBreak) { DbgPrint(" **** breaking on ppfel = %-#8lx\n\n", ppfel); DbgBreakPoint(); } #endif
PFEOBJ pfeo(ppfel->ppfe);
if (this->bNearMatch(pfeo,&jCharSet)) { DUMP_CHOSEN_FONT(pfeo); iBest = i;
// remember the good one
ppfelBest = ppfel;
// remember the simulation information for the best font
// choice to this time
vSetBest(ppfel->ppfe, 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 compatibile!
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); }
} if (bRet == TRUE) { break; } } // Return a good one if we found it.
if (ppfelBest) { // 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 roundtrupe conversion and
// 2) the charset of the font is DBCS
ULONG ulCodePage;
// the best charset so far is remembered in pflAboutMatch
BYTE jBestCharSet = (BYTE)(*pflAboutMatch >> 24);
if ( (jBestCharSet != OEM_CHARSET) || ppfelBest->ppfe->pifi->dpCharSets || (ppfelBest->ppfe->flPFE & PFE_DEVICEFONT) || IS_ANY_DBCS_CHARSET(jBestCharSet) ) { ulCodePage = ulCharsetToCodePage(jBestCharSet); } else { // 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: * Oct-21-97 by Xudong Wu [tessiew] * Disable the ufi matching for device fonts * 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;
// for device font, the ufi on the print server side
// might not match the one on the client side
// so we don't use the ufi-match on device fonts any more
if(UFI_DEVICE_FONT(pufi)) { ppfe = NULL; } else if(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; } } } } else { ppfe = ppfeGetPFEFromUFI(pufi, FALSE, // public font table
TRUE); // check process
}
if ( ppfe == NULL ) { WARNING1("MAPPER::bFoundForcedMatch unable to find forced match\n"); return( FALSE ); }
// 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->elfEnumLogfontEx.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->elfEnumLogfontEx.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 { if (ulFontAspect == 0) { WARNING1("MAPPER::bFoundForcedMatch " "ulFontAspect == 0\n"); return( FALSE ); } 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
// Another important point to note here is that the charset and code page
// needed for ansi to unicode conversion will remain uninitialized.
// I think that this is ok because for metafile spooled printing the text is
// always going to recorded as unicode so that this conversion will never
// have to be performed [bodind]
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
ENUMLOGFONTEXDVW *pelfwWishSrc, // defines the font that is wished
// for by the application
const WCHAR * pwszFaceName, // The sought name.
ULONG ulMaxPenalty, // a cutoff for the sum of all the
// individual penalties of each of the
// fields of the LOGFONT 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 Private PFT before device and public PFT if gpPFTPrivate != NULL
// We do not want to go through small font hack for private fonts.
if (gpPFTPrivate && gpPFTPrivate->cFiles) { PUBLIC_PFTOBJ pftoPrivate(gpPFTPrivate); mapper.vNotDeviceFonts(); // put mapper in "check engine fonts" state
if ( mapper.bFoundExactMatch(&pftoPrivate.pPFT->pfhFamily) || mapper.bFoundExactMatch(&pftoPrivate.pPFT->pfhFace) ) { PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet()); } }
// 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() ) { //
// If the device insists that we use only its fonts then
// we will do so. If the application requested a device
// font then we will map to that font and that font
// is contained in mapper.ppfeRet(). Otherwise, if the
// application asked for a face name that is not contained
// in the list of device fonts, then the current value
// of mapper.ppfeRet() will be NULL. In that case we
// will simply map to an arbitrary device font without
// regard to the size requested by the application.
// Caveat Emptor.
//
PFE *ppfeRet;
ppfeRet = mapper.ppfeRet();
if (ppfeRet == 0 || ppfeRet->pPFF != pPFF) { *pflSim = 0; *pflAboutMatch = 0; pptlSim->x = pptlSim->y = 1;
FONTHASH **ppfh = &pffo.pPFF->pfhFamily; ENUMFHOBJ fho(ppfh); ppfeRet = fho.ppfeFirst(); }
PPFEGETAMATCH_DEBUG_RETURN( ppfeRet ); } } }
// 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) ) { 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()) { PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet()); }
// At this point we know that no exact match will be found
// amongst the fonts installed on the system at this time.
// We shall therefore try to see if this was a request for mm instance
// for an mm font whose other instance is installed and create the
// requested instance dynamically.
// In the future we may exted this function to go out and search for the
// font that has not been addfontresource'ed at this time
// (perhaps by calling to font drivers, or maybe not)
// and install it dynamically.
PFE *ppfeRet = mapper.ppfeSynthesizeAMatch(pflSim, pflAboutMatch, pptlSim);
if (ppfeRet) { PPFEGETAMATCH_DEBUG_RETURN(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 good one!
if (!(dco.flGraphicsCaps() & GCAPS_SCREENPRECISION)) { if (mapper.bDeviceFontsExist()) { mapper.vAttemptDeviceMatch(); if (mapper.ppfeRet()) { PPFEGETAMATCH_DEBUG_RETURN(mapper.ppfeRet()); } } } // 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()); } }
// 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();
// 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);
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.
// bad news, some customers rely on the first device font matched by bNearMatch()
// for printing. Without the hack, it picks the first match and returns. With the
// hack, it picks the last device font matched by bNearMatch() and returns.
// in oder to make sure that the apps will still get the first device font matched by
// bNearMatch(), we only update the ppfeBest if this->ulPenaltyTotal < this->ulMaxPenalty.
if(_wcsicmp( pfeo.pwszFamilyName(), L"Arial")) { this->ulPenaltyTotal += 1; } else { vSetBest(ppfe, TRUE, jCharSet); return; } }
// keep the first device font that we picked
if (this->ulPenaltyTotal < this->ulMaxPenalty) { vSetBest(ppfe, TRUE, jCharSet); 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) (*pflAboutMatch >> 24)) << 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() { 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 ( ppfe = fho.ppfeFirst(); ppfe; ppfe = fho.ppfeNext() ) { PFEOBJ pfeo(ppfe); if (this->bNearMatch(pfeo,&jCharSet, TRUE)) // called from vEmergency
{ 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); }
/******************************Public*Routine******************************\
* * PFE * MAPPER::ppfeSynthesizeAMatch (FLONG *pflSim, FLONG *pflAboutMatch, POINTL *pptlSim) * * * Effects: if no exact instance is found, install one on the fly * * History: * 30-Jan-1998 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/
PFE * MAPPER::ppfeSynthesizeAMatch (FLONG *pflSim, FLONG *pflAboutMatch, POINTL *pptlSim) { PFE *ppfeRet = NULL;
DESIGNVECTOR *pdvWish; // dv of the instance we wish to load
ULONG cjDV; ULONG cFonts = 0; // number of fonts faces loaded
// let us get the pdv:
if (flMM & FLMM_DV_FROM_NAME) // we got the axes from the name
{ // the name takes precedance, ie if we have explicit dv == [UU,VV]
// as well as dv specified through font's family
// name of the form foo_XX_YY, we ignore dv in ENUMLOGFONTEXDV
// and use the one specified by the name, [XX,YY] in this case.
pdvWish = &dvWish; } else { pdvWish = (DESIGNVECTOR *)&pelfwWish->elfDesignVector; }
cjDV = SIZEOFDV(pdvWish->dvNumAxes);
// for now we do this only if another instance is already loaded
if (ppfeMMInst) { // get to the PFF of the other instance, need file path data
PFFOBJ pffMMInst(ppfeMMInst->pPFF) ;
PFF *pPFF; // placeholder for the returned PFF
if (pffMMInst.bValid()) { // need to initialize the private PFT if it is NULL, these on the fly
// instances are always added to private table
if (gpPFTPrivate == NULL) { if (!bInitPrivatePFT()) { return ppfeRet; } }
// temp instances go to private table
PUBLIC_PFTOBJ pfto(gpPFTPrivate);
if (!pffMMInst.bMemFont()) { if (!pfto.bLoadFonts( pffMMInst.pwszPathname(), pffMMInst.cSizeofPaths(), pffMMInst.cNumFiles(), pdvWish, cjDV, &cFonts, PFF_STATE_SYNTH_FONT, // flPFF
&pPFF, (FR_PRIVATE | FR_NOT_ENUM), // always
TRUE, // skip the check if already loaded
NULL ) ) // peudc
{ cFonts = 0; }
if (cFonts) { GreQuerySystemTime( &PFTOBJ::FontChangeTime ); } }
} else // memory fonts
{ RIP("MEMORY FONT CASE NOT IMPLEMENTED\n"); }
// now need to get to the pfe of the font that we just added:
if (cFonts) { PFFOBJ pffoNewInst(pPFF);
if (pffoNewInst.bValid()) { if (cFonts == 1) { ppfeRet = pffoNewInst.ppfe(0); } else { // this is either an mm font which has a weight axis,
// so that normal and bold faces are returned or this is a
// also a FE mm font, in which case there may be
// horiz and vertical variances as well. Therefore, in this case
// we shall have to do mini-mapping process in order to decide which
// face to return among those returned by by DrvLoadFontFile.
ULONG iFound = 0; ULONG iFace = 0; LONG lMinSoFar = LONG_MAX;
for (iFace = 0; iFace < cFonts; iFace++) { IFIMETRICS *pifi = pffoNewInst.ppfe(iFace)->pifi;
IFIOBJ ifio(pifi);
LONG lDiff = (LONG)pifi->usWinWeight - lWishWeight; if (lDiff < 0) lDiff = -lDiff;
// <= on the next line is important because foo and @foo have the same weight
if (lDiff <= lMinSoFar) { lMinSoFar = lDiff;
// 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.pwszFamilyName() == U_COMMERCIAL_AT) { iFound = iFace; } } else { if (*ifio.pwszFamilyName() != U_COMMERCIAL_AT) { iFound = iFace; } } } }
ppfeRet = pffoNewInst.ppfe(iFound); }
// now that we know that we are returning ok we need to
// fill in other output fields:
*pflSim = 0;
IFIOBJ ifio(ppfeRet->pifi);
// next check for italic simulations
if (pelfwWish->elfEnumLogfontEx.elfLogFont.lfItalic) { // if you get here then the application wants an italicized font
if (!ifio.bNonSimItalic() && ifio.bSimItalic()) { *pflSim |= 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) ) { *pflSim |= FO_SIM_BOLD; } }
UINT CharSet = pelfwWish->elfEnumLogfontEx.elfLogFont.lfCharSet;
*pflAboutMatch = (FLONG)(CharSet << 24); *pflAboutMatch |= (ulCharsetToCodePage(CharSet) << 8); pptlSim->x = pptlSim->y = 1; } } } return ppfeRet; }
|