You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3993 lines
137 KiB
3993 lines
137 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: fontmap.cxx *
|
|
* *
|
|
* Routines for mapping fonts. *
|
|
* *
|
|
* Created: 17-Jun-1992 11:12:16 *
|
|
* Author: Kirk Olynyk [kirko] *
|
|
* *
|
|
* Copyright (c) 1992-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;
|
|
}
|