mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3538 lines
121 KiB
3538 lines
121 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: pftobj.cxx *
|
|
* *
|
|
* Non-inline methods for physical font table objects. *
|
|
* *
|
|
* Created: 30-Oct-1990 09:32:48 *
|
|
* Author: Gilman Wong [gilmanw] *
|
|
* *
|
|
* Tue 09-Aug-1994 10:04:09 by Kirk Olynyk [kirko] *
|
|
* Prior to build ### there was only a single font table on which all *
|
|
* fonts, be they public (engine) or device, where attached. I have *
|
|
* changed the font architecture so that there will be two font tables. *
|
|
* One for public fonts and the other font device fonts. The public font *
|
|
* table will be string based. That is, the fonts were added to this *
|
|
* using GreAddFontResourceW() with the name of the associated font file. *
|
|
* The name of the font file and path will be hashed and the font files *
|
|
* will hang off of the collision list. The number of hash buckets is *
|
|
* set at boot time. *
|
|
* *
|
|
* The device font table will be for device fonts (suprise). *
|
|
* In this case the fonts will be placed in hash collisions *
|
|
* lists depending upon the value of their hdev. *
|
|
* *
|
|
* Copyright (c) 1994-1995 Microsoft Corporation *
|
|
* *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
PFT *gpPFTPublic; // global public font table (for font drivers)
|
|
PFT *gpPFTDevice; // global device font table (for printers)
|
|
|
|
|
|
LARGE_INTEGER PFTOBJ::FontChangeTime; // time of most recent addition or
|
|
// removal of a font file
|
|
extern USHORT gusLanguageID;
|
|
|
|
// Definitions for local functions used to remove font files from system.
|
|
|
|
RFONT* prfntKillList(PFFOBJ &);
|
|
BOOL bKillRFONTList(PFFOBJ &, RFONT *);
|
|
UINT iHash(PWSZ, UINT);
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pAllocateAndInitializePFT *
|
|
* *
|
|
* Allocates and initializes a font table with cBuckets *
|
|
* This allows the public (engine) font table and the device *
|
|
* font table to share the same code. *
|
|
* *
|
|
* input: cBuckets = number of members in allocated PFF* table *
|
|
* output: address of new PFT *
|
|
* *
|
|
* Notes: *
|
|
* *
|
|
* it is not necessary to check for error in the creation *
|
|
* of the hash tables because the system will still work *
|
|
* *
|
|
* error: return 0 *
|
|
* *
|
|
* History: *
|
|
* Fri 05-Aug-1994 07:41:50 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
PFT *pAllocateAndInitializePFT(unsigned cBuckets)
|
|
{
|
|
PFT *pPFT;
|
|
|
|
register SIZE_T size = offsetof(PFT, apPFF) + cBuckets * sizeof(PFF*);
|
|
if (pPFT = (PFT*) PALLOCMEM(size, 'tfpG'))
|
|
{
|
|
pPFT->cBuckets = cBuckets;
|
|
pPFT->cFiles = 0;
|
|
}
|
|
return(pPFT);
|
|
}
|
|
|
|
// strings used to identify values stored in the registry
|
|
|
|
static CONST PWSZ pwszP0 = L"NumberOfPublicFontFilesAtLastLogOff";
|
|
static CONST PWSZ pwszP1 = L"NumberOfPublicFontFilesSetByUser";
|
|
static CONST PWSZ pwszD0 = L"NumberOfDeviceFontFilesAtLastLogOff";
|
|
static CONST PWSZ pwszD1 = L"NumberOfDeviceFontFilesSetByUser";
|
|
static CONST PWSZ pwszFC =
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontCache";
|
|
|
|
// Define some default values in case the registry numbers are bogus
|
|
|
|
#define MIN_PUBLIC_BUCKETS 100
|
|
#define MAX_PUBLIC_BUCKETS 10000
|
|
#define MIN_DRIVER_BUCKETS 5
|
|
#define MAX_DRIVER_BUCKETS 100
|
|
|
|
// PIR :== Put In Range
|
|
|
|
#define PIR(x,a,b) ((x)<(a)?(a):((x)>(b)?(b):(x)))
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vQueryRegistryForNumberOfBuckets
|
|
*
|
|
* Gets from the registry the number of buckets needed for the public
|
|
* and driver font tables.
|
|
*
|
|
* History:
|
|
* Mon 26-Sep-1994 09:59:52 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void vQueryRegistryForNumberOfBuckets(
|
|
unsigned *puPublic // recieves # buckets for Public fonts
|
|
, unsigned *puDevice // recieves # buckets for Device fonts
|
|
)
|
|
{
|
|
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[5];
|
|
HANDLE hDevMode;
|
|
DWORD Status;
|
|
|
|
ULONG cPublicBucketsSys = 0;
|
|
ULONG cPublicBucketsUser = 0;
|
|
ULONG cDeviceBucketsSys = 0;
|
|
ULONG cDeviceBucketsUser = 0;
|
|
|
|
//
|
|
// Initialize registry query table.
|
|
//
|
|
|
|
QueryTable[0].QueryRoutine = NULL;
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[0].Name = L"NumberOfPublicFontFilesAtLastLogOff";
|
|
QueryTable[0].EntryContext = &cPublicBucketsSys;
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
QueryTable[0].DefaultData = NULL;
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
QueryTable[1].QueryRoutine = NULL;
|
|
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[1].Name = L"NumberOfPublicFontFilesSetByUser";
|
|
QueryTable[1].EntryContext = &cPublicBucketsUser;
|
|
QueryTable[1].DefaultType = REG_NONE;
|
|
QueryTable[1].DefaultData = NULL;
|
|
QueryTable[1].DefaultLength = 0;
|
|
|
|
QueryTable[2].QueryRoutine = NULL;
|
|
QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[2].Name = L"NumberOfDeviceFontFilesAtLastLogOff";
|
|
QueryTable[2].EntryContext = &cDeviceBucketsSys;
|
|
QueryTable[2].DefaultType = REG_NONE;
|
|
QueryTable[2].DefaultData = NULL;
|
|
QueryTable[2].DefaultLength = 0;
|
|
|
|
QueryTable[3].QueryRoutine = NULL;
|
|
QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[3].Name = L"NumberOfDeviceFontFilesSetByUser";
|
|
QueryTable[3].EntryContext = &cDeviceBucketsUser;
|
|
QueryTable[3].DefaultType = REG_NONE;
|
|
QueryTable[3].DefaultData = NULL;
|
|
QueryTable[3].DefaultLength = 0;
|
|
|
|
QueryTable[4].QueryRoutine = NULL;
|
|
QueryTable[4].Flags = 0;
|
|
QueryTable[4].Name = NULL;
|
|
|
|
//
|
|
// If the open was succesdsful, then query the registry for the
|
|
// specified printer.
|
|
//
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
|
|
L"FontCache",
|
|
&QueryTable[0],
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
WARNING("vQueryRegistryForNumberOfBuckets failure\n");
|
|
}
|
|
else
|
|
{
|
|
if (!cPublicBucketsUser)
|
|
{
|
|
cPublicBucketsUser = cPublicBucketsSys;
|
|
}
|
|
if (!cDeviceBucketsUser)
|
|
{
|
|
cDeviceBucketsUser = cDeviceBucketsSys;
|
|
}
|
|
}
|
|
*puPublic = PIR(cPublicBucketsUser, MIN_PUBLIC_BUCKETS, MAX_PUBLIC_BUCKETS);
|
|
*puDevice = PIR(cDeviceBucketsUser, MIN_DRIVER_BUCKETS, MAX_DRIVER_BUCKETS);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bInitFontTables *
|
|
* *
|
|
* Create the global public PFT and driver PFT *
|
|
* *
|
|
* Create the public PFT semaphore to serialize access to both the *
|
|
* public and driver font tables and their releated PFF's and PFE's *
|
|
* Access to the RFONT's (realized font instances) are regulated *
|
|
* by a separate semaphore. *
|
|
* *
|
|
* History: *
|
|
* Fri 05-Aug-1994 07:07:27 by Kirk Olynyk [kirko] *
|
|
* Made it allocate both the public and driver font tables. Both *
|
|
* allocations and initializations are done by a common routine. *
|
|
* 21-Jan-1991 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL bInitFontTables()
|
|
{
|
|
unsigned cPublicBuckets;
|
|
unsigned cDeviceBuckets;
|
|
register BOOL bRet = FALSE;
|
|
|
|
vQueryRegistryForNumberOfBuckets(&cPublicBuckets, &cDeviceBuckets);
|
|
if (
|
|
bRet = (
|
|
(gpPFTPublic = pAllocateAndInitializePFT(cPublicBuckets))
|
|
&& (gpPFTDevice = pAllocateAndInitializePFT(cDeviceBuckets))
|
|
&& (gpsemPublicPFT = hsemCreate()))
|
|
)
|
|
{
|
|
FHMEMOBJ fhmo1(&gpPFTPublic->pfhFace , FHT_FACE , cPublicBuckets);
|
|
FHMEMOBJ fhmo2(&gpPFTPublic->pfhFamily, FHT_FAMILY, cPublicBuckets);
|
|
FHMEMOBJ fhmo3(&gpPFTPublic->pfhUFI, FHT_UFI, cPublicBuckets);
|
|
}
|
|
|
|
#if DBG
|
|
if (!bRet)
|
|
{
|
|
if (!gpPFTPublic) WARNING("gpPFTPublic == 0\n");
|
|
if (!gpPFTDevice) WARNING("gpPFTDevice == 0\n");
|
|
if (!gpsemPublicPFT) WARNING("gpsemPublicPFT == 0\n");
|
|
}
|
|
#endif
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL PFTOBJ::bDelete() *
|
|
* *
|
|
* Destroy the PFT physical font table object. *
|
|
* *
|
|
* If this method succeeds the pointer to the public font table is *
|
|
* set to 0 and then this method returns TRUE. If the table contains *
|
|
* any files, then this method will fail and return FALSE. *
|
|
* *
|
|
* History: *
|
|
* 30-Oct-1990 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL PFTOBJ::bDelete()
|
|
{
|
|
if (pPFT->cFiles)
|
|
{
|
|
VFREEMEM(pPFT);
|
|
pPFT = 0;
|
|
}
|
|
else
|
|
{
|
|
WARNING("gdisrv!bDeletePFTOBJ(): cFiles != 0");
|
|
}
|
|
return(!pPFT);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PFTOBJ::chpfeIncrPFF *
|
|
* *
|
|
* If this was an attempt to load a font that was embeded and the *
|
|
* client ID didn't match that in the *.fot file FALSE will be *
|
|
* return via pbEmbedStatus ortherwise TRUE is returned. *
|
|
* *
|
|
* If found, the load count of the PFF is incremented. *
|
|
* *
|
|
* Note: *
|
|
* Caller should be holding the gpsemPublicPFT *
|
|
* semaphore when calling this routine in order *
|
|
* to access the table and load count. *
|
|
* *
|
|
* Returns: *
|
|
* Number of PFEs in the PFF, 0 if PFF not found. *
|
|
* *
|
|
* History: *
|
|
* Fri 05-Aug-1994 13:37:11 by Kirk Olynyk [kirko] *
|
|
* The PFF has been found up front and is guaranteed to exist. *
|
|
* I have removed the check to see if it is a device font. This check *
|
|
* is now redundant because you can tell if it is a device font by the *
|
|
* table that you are on. If device fonts cannot be loaded via *
|
|
* AddFontResouce, then this function should not be called for a *
|
|
* device font. *
|
|
* 28-Jun-1991 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
COUNT PFTOBJ::chpfeIncrPFF(
|
|
PFF *pPFF, // address of PFF to be, incremented
|
|
BOOL *pbEmbedStatus // tried to load an embeded font illegally
|
|
#ifdef FE_SB
|
|
,PEUDCLOAD pEudcLoadData // PFE's in file if EUDC
|
|
#endif
|
|
)
|
|
{
|
|
// Caller should be holding gpsemPublicPFT semaphore!
|
|
|
|
#ifdef FE_SB
|
|
BOOL bEUDC = ( pEudcLoadData != NULL );
|
|
#endif
|
|
|
|
COUNT cRet = 0;
|
|
PFFOBJ pffo(pPFF);
|
|
if (!pffo.bValid())
|
|
{
|
|
RIP("Invalid PFFOBJ\n");
|
|
}
|
|
else
|
|
{
|
|
#ifdef FE_SB
|
|
if ((bEUDC && pffo.bEUDC()) || (!bEUDC && !pffo.bEUDC()) )
|
|
#endif
|
|
{
|
|
if(*pbEmbedStatus = pffo.bEmbedOk())
|
|
{
|
|
|
|
#ifdef FE_SB
|
|
if(bEUDC)
|
|
{
|
|
if((pEudcLoadData->LinkedFace == NULL) &&
|
|
(pffo.cFonts() > 2))
|
|
{
|
|
// EUDC font file can have at most two fonts (one regular
|
|
// and one @) unless the user specifies a face name.
|
|
// we return failure by setting embed status to false
|
|
|
|
*pbEmbedStatus = FALSE;
|
|
|
|
// return non-zero so calling function returns right away
|
|
|
|
return(1);
|
|
}
|
|
pffo.vGetEUDC(pEudcLoadData);
|
|
}
|
|
#endif
|
|
pffo.vLoadIncr();
|
|
cRet = pffo.cFonts();
|
|
}
|
|
else
|
|
{
|
|
cRet = ~cRet;
|
|
ASSERTGDI(cRet,
|
|
"cRet should be non zero so calling function"
|
|
" will return right away\n");
|
|
}
|
|
}
|
|
}
|
|
return(cRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PFTOBJ::pPFFGet *
|
|
* *
|
|
* Note: *
|
|
* Caller should be holding the gpsemPublicPFT semaphore when *
|
|
* this method calling this in order to guarantee a stable font *
|
|
* table. *
|
|
* Note that since all the strings in the table are in upper case *
|
|
* and the input string must be upper case, we are allowed to *
|
|
* compare strings with the faster case sensitive compare *
|
|
* wcscmp(). *
|
|
* *
|
|
* Returns: *
|
|
* PPFF of the PFF if found, (PPFF) NULL if the PFF not found. *
|
|
* *
|
|
* History: *
|
|
* Thu 04-Aug-1994 08:18:27 by Kirk Olynyk [kirko] *
|
|
* Modified to make the public font table hash based *
|
|
* 06-May-1992 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
PPFF PUBLIC_PFTOBJ::pPFFGet (
|
|
PWSZ pwszPathname // address of upper case string
|
|
, ULONG cwc
|
|
, ULONG cFiles
|
|
, PFF ***pppPFF // write address of bucket here
|
|
#ifdef FE_SB
|
|
, BOOL bEUDC // be true if EUDC
|
|
#endif
|
|
)
|
|
{
|
|
PFF *pPFF, **ppPFF;
|
|
|
|
// it is enough to hash on the first file only, no need to include the
|
|
// second and or third file to the hashing routine [bodind]
|
|
|
|
ppPFF = pPFT->apPFF + iHash(pwszPathname,pPFT->cBuckets);
|
|
if (pppPFF)
|
|
{
|
|
*pppPFF = ppPFF;
|
|
}
|
|
pPFF = *ppPFF;
|
|
while(pPFF)
|
|
{
|
|
if
|
|
(
|
|
#ifdef FE_SB
|
|
(bEUDC == ((pPFF->flState & PFF_STATE_EUDC_FONT) != 0)) &&
|
|
#endif
|
|
(cwc == pPFF->cwc) && (cFiles == pPFF->cFiles) &&
|
|
!memcmp(pPFF->pwszPathname_, pwszPathname, cwc * sizeof(WCHAR))
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
pPFF = pPFF->pPFFNext;
|
|
}
|
|
return(pPFF);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PFTOBJ::pPFFGet *
|
|
* *
|
|
* This function searches for the PFF that contains the device fonts for *
|
|
* the PDEV specified by the HPDEV passed in. *
|
|
* *
|
|
* Note: *
|
|
* Caller should be holding the gpsemPublicPFT semaphore *
|
|
* when calling this in order to have access to the font tables. *
|
|
* *
|
|
* Returns: *
|
|
* pointer to the PFF if found. 0 returned on error. *
|
|
* *
|
|
* History: *
|
|
* Fri 05-Aug-1994 13:39:04 by Kirk Olynyk [kirko] *
|
|
* Changed this to a hash based search. *
|
|
* 06-May-1992 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
#define iHashHPDEV(hdev, c) (((unsigned) hdev >> 4) % c)
|
|
|
|
PPFF DEVICE_PFTOBJ::pPFFGet(
|
|
HDEV hdev
|
|
, PFF ***pppPFF // write address of bucket here
|
|
)
|
|
{
|
|
PFF *pPFF, **ppPFF;
|
|
|
|
ppPFF = pPFT->apPFF + iHashHPDEV(hdev, pPFT->cBuckets);
|
|
pPFF = *ppPFF;
|
|
if (pppPFF)
|
|
{
|
|
*pppPFF = ppPFF;
|
|
}
|
|
while (pPFF)
|
|
{
|
|
PFFOBJ pffo(pPFF);
|
|
if (!pffo.bValid())
|
|
{
|
|
RIP("PFTOBJ::PPFFGet(HPDEV) encountered invalid PFFOBJ\n");
|
|
}
|
|
else if (hdev == pffo.hdev())
|
|
{
|
|
break;
|
|
}
|
|
pPFF = pPFF->pPFFNext;
|
|
}
|
|
return(pPFF);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bLoadAFont, wrapper for one file only
|
|
*
|
|
*
|
|
* History:
|
|
* 28-Mar-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL PUBLIC_PFTOBJ::bLoadAFont(
|
|
PWSZ pwszPathname, // font file pathname
|
|
PULONG pcFonts, // number of fonts faces loaded
|
|
FLONG fl, // permanent
|
|
PPFF *pPPFF
|
|
#ifdef FE_SB
|
|
,PEUDCLOAD pEudcLoadData
|
|
#endif
|
|
)
|
|
{
|
|
|
|
WCHAR awcUcPathName[MAX_PATH + 1];
|
|
ULONG cwc = wcslen(pwszPathname) + 1;
|
|
cCapString(awcUcPathName, pwszPathname, cwc);
|
|
|
|
return bLoadFonts(awcUcPathName, cwc, 1, pcFonts, fl, pPPFF
|
|
, 0, 0
|
|
#ifdef FE_SB
|
|
, pEudcLoadData
|
|
#endif
|
|
);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL PUBLIC_PFTOBJ::bLoadFonts *
|
|
* *
|
|
* The bLoadFont function searches for an IFI font driver which can load *
|
|
* the requested font file. If a driver is found, a new Pysical Font *
|
|
* File object is created and is used to load the font file. *
|
|
* *
|
|
* Note that if the font file has already been loaded (i.e., a PFF object *
|
|
* already exists for it), the ref count in the PFF is incremented without *
|
|
* reloading the file. *
|
|
* *
|
|
* If pppfeEUDC != NULL then we are loading an EUDC font file. This has *
|
|
* the restriction the font file has only one face or two if the other is *
|
|
* an @face. If either of these aren't true the call fails. Also, an EUDC *
|
|
* font wont be enumerated. Finally the PFE will be returned for the one *
|
|
* font in the EUDC font file via pppfeEUDC. *
|
|
* *
|
|
* Returns FALSE on failure. *
|
|
* *
|
|
* History: *
|
|
* Thu 28-Mar-1996 -by- Bodin Dresevic [BodinD]
|
|
* update: added multiple file support
|
|
* Thu 04-Aug-1994 08:04:03 by Kirk Olynyk [kirko] *
|
|
* Made the font table hash based. *
|
|
* 06-Nov-1990 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL PUBLIC_PFTOBJ::bLoadFonts(
|
|
PWSZ pwszPathname, // font file pathname
|
|
ULONG cwc, // cwc in PathName
|
|
ULONG cFiles, // number of distinct files in path
|
|
PULONG pcFonts, // number of fonts faces loaded
|
|
FLONG fl, // permanent
|
|
PPFF *pPPFF,
|
|
FLONG flEmbed,
|
|
DWORD dwPidTid
|
|
#ifdef FE_SB
|
|
,PEUDCLOAD pEudcLoadData // returns PFE for EUDC font file
|
|
#endif // FONTLINK
|
|
)
|
|
{
|
|
COUNT cFonts; // count of fonts in font file
|
|
BOOL bRet = FALSE; // assume failuer
|
|
PFF *pPFF; // convenient pointer2
|
|
PFF **ppPFF; // address of bucket
|
|
#ifdef FE_SB
|
|
BOOL bEUDC = ( pEudcLoadData != NULL );
|
|
PPFE *pppfeEUDC = ((bEUDC) ? pEudcLoadData->pppfeData : NULL);
|
|
#endif
|
|
|
|
if (!pwszPathname)
|
|
{
|
|
RIP("pwszPathname != 0\n");
|
|
return(bRet);
|
|
}
|
|
|
|
if (dwPidTid)
|
|
{
|
|
if (flEmbed & AFRW_ADD_EMB_TID)
|
|
{
|
|
if (dwPidTid != (ULONG)W32GetCurrentThread())
|
|
return (bRet);
|
|
}
|
|
else
|
|
{
|
|
if (dwPidTid != (ULONG)W32GetCurrentProcess())
|
|
return (bRet);
|
|
}
|
|
}
|
|
|
|
// if (already_loaded) increment_ref_count_then_exit_immediately
|
|
|
|
{
|
|
SEMOBJ so(gpsemPublicPFT);
|
|
*pcFonts = 0;
|
|
|
|
if (
|
|
#ifdef FE_SB
|
|
(*pPPFF = pPFFGet((PWSZ) pwszPathname, cwc, cFiles, &ppPFF, bEUDC)) &&
|
|
#else
|
|
(*pPPFF = pPFFGet((PWSZ) pwszPathname, cwc, cFiles, &ppPFF)) &&
|
|
#endif
|
|
(*pcFonts = chpfeIncrPFF(
|
|
*pPPFF
|
|
, &bRet
|
|
#ifdef FE_SB
|
|
, pEudcLoadData
|
|
#endif
|
|
)))
|
|
{
|
|
return(bRet);
|
|
}
|
|
}
|
|
|
|
// Grab the head of the font driver list under semaphore and find
|
|
// the first font driver in the list that loads the font
|
|
//
|
|
// Release the semaphore so we can go and see if the
|
|
// driver supports the font. If it does, then keep
|
|
// the reference count and exit. Otherwise, grab the
|
|
// semaphore again, release the reference count and
|
|
// find the next driver in the list.
|
|
|
|
HFF hffNew = HFF_INVALID; // IFI handle to font file
|
|
|
|
// alloc temp memory, this could be done on the stack if it were not
|
|
// for the fact that we do not know ahead the upper bound on cFiles
|
|
|
|
MALLOCOBJ moViews(cFiles * (sizeof(PVOID) + sizeof(ULONG)));
|
|
if (!moViews.bValid())
|
|
return FALSE;
|
|
|
|
PVOID *apvView = (PVOID *)moViews.pv();
|
|
ULONG *acjView = (ULONG *)&apvView[cFiles];
|
|
|
|
|
|
FONTFILEVIEW **apfv;
|
|
|
|
// apfv - pointer to a block of memory that begins with an array
|
|
// of cFiles pointers to FONTFILEVIEW structures followed
|
|
// by a corretly aligned FONTFILEVIEW structure
|
|
|
|
unsigned offset;
|
|
|
|
// offset - offset of FONTFILEVIEW structure from the beginning
|
|
// of the block of memory pointed to by apfv. This is equal to the
|
|
// offset of the nearest double following the array of pointers.
|
|
// In C, a double is maximally aligned.
|
|
|
|
offset = sizeof(double) * ((cFiles * sizeof(void*) + sizeof(double) - 1) / sizeof(double));
|
|
|
|
apfv = (FONTFILEVIEW**) PALLOCMEM(offset + cFiles*sizeof(FONTFILEVIEW),'vffG');
|
|
|
|
if (apfv == NULL)
|
|
{
|
|
WARNING("PUBLIC_PFTOBJ::bLoadFonts: out of memory\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// pfv - pointer to FONTFILEVIEW structure following the array of
|
|
// cFiles pointers.
|
|
|
|
FONTFILEVIEW *pfv = (FONTFILEVIEW*)(((char*) apfv) + offset);
|
|
|
|
// init the data for all files;
|
|
|
|
PWSZ pwszTmp = pwszPathname;
|
|
ULONG iFile;
|
|
|
|
for (iFile = 0; iFile < cFiles; iFile++)
|
|
{
|
|
apfv[iFile] = &pfv[iFile];
|
|
|
|
apfv[iFile]->pwszPath = pwszTmp;
|
|
|
|
if (!EngMapFontFile((ULONG)apfv[iFile], (PULONG*)&apvView[iFile], &acjView[iFile]))
|
|
{
|
|
WARNING("PUBLIC_PFTOBJ::bLoadFonts: EngMapFontFile failed\n");
|
|
|
|
// clean up, unmap all of those mapped so far
|
|
|
|
for (ULONG jFile = 0; jFile < iFile; jFile++)
|
|
EngUnmapFontFile((ULONG)apfv[jFile]);
|
|
|
|
VFREEMEM(apfv);
|
|
return(FALSE);
|
|
}
|
|
|
|
// get to the next file in the multiple path
|
|
|
|
while (*pwszTmp++)
|
|
;
|
|
}
|
|
|
|
VACQUIRESEM(gpsemDriverMgmt);
|
|
|
|
PPDEV ppDevList = gppdevList;
|
|
|
|
do
|
|
{
|
|
PDEVOBJ pdo((HDEV)ppDevList);
|
|
|
|
ULONG ulFontCaps = 0;
|
|
|
|
if (PPFNVALID(pdo, QueryFontCaps))
|
|
{
|
|
ULONG ulBuf[2];
|
|
|
|
if ( (*PPFNDRV(pdo, QueryFontCaps))(2, ulBuf) != FD_ERROR )
|
|
{
|
|
ulFontCaps = ulBuf[1];
|
|
}
|
|
}
|
|
|
|
if (ulFontCaps & (QC_FONTDRIVERCAPS))
|
|
{
|
|
// make a reference to the font driver under the protection
|
|
// of the semaphore. This will guarantee that the font
|
|
// driver will not be unloaded unexpectedly. After that
|
|
|
|
// BUGBUG put back after LDEVs are cleaned up
|
|
//ldo.vReference();
|
|
|
|
|
|
VRELEASESEM(gpsemDriverMgmt);
|
|
|
|
|
|
// Attempt to load the font file.
|
|
// It is acceptable to release the lock at this point because
|
|
// we know this font driver has at least one reference to it.
|
|
// We also do not care if other font drivers are added or removed
|
|
// from the list while we are scanning it ...
|
|
|
|
hffNew = (*PPFNDRV(pdo, LoadFontFile)) (cFiles,
|
|
(ULONG *) apfv,
|
|
apvView, acjView,
|
|
(ULONG) gusLanguageID);
|
|
|
|
|
|
// Grab the lock again here (so we exit the loop properly)
|
|
|
|
VACQUIRESEM(gpsemDriverMgmt);
|
|
|
|
if (hffNew != HFF_INVALID)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// We did not load the font file properly
|
|
// Release the reference and go on.
|
|
|
|
// BUGBUG put back after LDEVs are cleaned up
|
|
// ldo.vUnreference();
|
|
}
|
|
}
|
|
|
|
} while (ppDevList = ppDevList->ppdevNext);
|
|
|
|
PDEVOBJ pdo((HDEV)ppDevList);
|
|
|
|
VRELEASESEM(gpsemDriverMgmt);
|
|
|
|
ASSERTGDI(bRet==FALSE,"bRet != FALSE\n");
|
|
|
|
if (hffNew != HFF_INVALID)
|
|
{
|
|
// cFonts = number of faces in the file
|
|
|
|
cFonts = (*PPFNDRV(pdo, QueryFontFile)) (hffNew,
|
|
QFF_NUMFACES,
|
|
0,
|
|
NULL);
|
|
|
|
if (cFonts && cFonts != FD_ERROR)
|
|
{
|
|
#ifdef FE_SB
|
|
// EUDC font file can have at most two fonts. If it
|
|
// has two fonts then one of the face names must begin
|
|
// with the '@' character. We check the number of fonts
|
|
// here but we do not check the characters of the
|
|
// face names.
|
|
|
|
if(bEUDC && (pEudcLoadData->LinkedFace == NULL) && (cFonts > 2))
|
|
{
|
|
WARNING("EUDC font file has more than two faces.");
|
|
return(bRet);
|
|
}
|
|
#endif
|
|
|
|
*pcFonts = cFonts;
|
|
|
|
// Create new PFF with table big enough to accomodate
|
|
// the new fonts and pathname.
|
|
|
|
PFFCLEANUP *pPFFC = 0;
|
|
|
|
PFFMEMOBJ pffmo(cFonts,
|
|
pwszPathname,cwc, cFiles,
|
|
hffNew,pdo.hdev(),0,pPFT,fl,flEmbed,dwPidTid,apfv
|
|
);
|
|
|
|
if (pffmo.bValid())
|
|
{
|
|
// Tell the PFF user object to load its table of
|
|
// HPFE's for each font in file.
|
|
|
|
if (!pffmo.bLoadFontFileTable(pwszPathname,
|
|
cFonts,
|
|
(HANDLE) 0
|
|
#ifdef FE_SB
|
|
,pEudcLoadData
|
|
#endif
|
|
))
|
|
{
|
|
*pcFonts = 0;
|
|
}
|
|
else
|
|
{
|
|
// Font load has succeeded. If some other process hasn't
|
|
// already snuck in and added it while the gpsemPublicPFT
|
|
// semaphore was released, add the new PFF to the PFT.
|
|
// Stabilize font table before searching or modifying it.
|
|
|
|
SEMOBJ so2(gpsemPublicPFT);
|
|
|
|
// Is PFF already in table? We check this by
|
|
// assuming that it already is and attempt to
|
|
// increment the load count. If it succeeds, its
|
|
// there. If it fails, it not there and we can add
|
|
// our new PFF to the PFT.
|
|
|
|
|
|
if(
|
|
#ifdef FE_SB
|
|
(*pPPFF = pPFFGet(pwszPathname, cwc, cFiles, &ppPFF, bEUDC)) &&
|
|
#else
|
|
(*pPPFF = pPFFGet(pwszPathname, cwc, cFiles, &ppPFF)) &&
|
|
#endif
|
|
(cFonts = chpfeIncrPFF(
|
|
*pPPFF
|
|
, &bRet
|
|
#ifdef FE_SB
|
|
, pEudcLoadData
|
|
#endif
|
|
)) )
|
|
{
|
|
// Some other process got in and put it in before we
|
|
// could. chpfeIncrPFF has already incremented the
|
|
// count for us. We only need to delete the PFF that
|
|
// we made which will occur automatically if
|
|
// bRet = FALSE
|
|
|
|
*pcFonts = cFonts;
|
|
}
|
|
else
|
|
{
|
|
// Not already in the table, so we really are going
|
|
// to add it to the PFT.
|
|
|
|
*pPPFF = pffmo.pPFFGet();
|
|
if (
|
|
#ifdef FE_SB
|
|
// if this font file is loaded as EUDC,
|
|
// don't add to hash tables.
|
|
// don't want to execute pffmo.bAddHash().
|
|
(bEUDC) ||
|
|
#endif
|
|
pffmo.bAddHash()
|
|
)
|
|
{
|
|
// add entry to head of a doubly linked collision
|
|
// list
|
|
|
|
pPFT->cFiles++;
|
|
if (*ppPFF)
|
|
{
|
|
(*ppPFF)->pPFFPrev = *pPPFF;
|
|
}
|
|
(*pPPFF)->pPFFNext = *ppPFF;
|
|
(*pPPFF)->pPFFPrev = 0;
|
|
*ppPFF = *pPPFF;
|
|
|
|
pffmo.vKeepIt();
|
|
|
|
// need to reset the file paths pointers
|
|
|
|
pwszTmp = pffmo.pwszPathname();
|
|
|
|
for (iFile = 0; iFile < cFiles; iFile++)
|
|
{
|
|
apfv[iFile]->pwszPath = pwszTmp;
|
|
|
|
// get to the next file in the multiple path
|
|
|
|
while (*pwszTmp++)
|
|
;
|
|
}
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("pffmo.bAddHash() failed\n");
|
|
*pcFonts = 0;
|
|
pffmo.vRemoveHash();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
// must unmap the files before calling pPFFC_Delete()
|
|
// because this function will delete apfv memory so that unmap
|
|
// will fail
|
|
|
|
for (iFile = 0; iFile < cFiles; iFile++)
|
|
EngUnmapFontFile((ULONG)apfv[iFile]);
|
|
|
|
VOID *pv = (VOID*) pffmo.pPFFC_Delete();
|
|
if (pv && pv != (VOID *)-1)
|
|
{
|
|
vCleanupFontFile((PFFCLEANUP*) pv);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the font driver accepted the font, then it will have called
|
|
// EngMapFontFile and incremented the reference count. In that
|
|
// case the call to EngUnmapFontFile below will simply decrement
|
|
// the reference count. However, in the case where the font driver
|
|
// did not succeed, then the font driver will have matched every
|
|
// call that it made to EngMapFont file with a call to EngUnmapFontFile
|
|
// and as a result, the total reference count for this font file
|
|
// will be 1 corresponding to the call made to EngMapFontFile
|
|
// made earlier in this routine. In this case of failure the
|
|
// call to EngUnmapFontFile below will cause the font mapping
|
|
// to be freed.
|
|
|
|
for (iFile = 0; iFile < cFiles; iFile++)
|
|
EngUnmapFontFile((ULONG)apfv[iFile]);
|
|
|
|
if (!bRet)
|
|
{
|
|
VFREEMEM(apfv);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL PUBLIC_PFTOBJ::bLoadRemoteFonts
|
|
*
|
|
* Warning:
|
|
*
|
|
* This routine or any of the routines that it calls must
|
|
* call EngMapFontFile and EngUnmapFontFile in pairs.
|
|
*
|
|
* History:
|
|
* Thu 02-Feb-1995 2:04:06 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define QUICK_VIEWS 4
|
|
|
|
ULONG PUBLIC_PFTOBJ::ulRemoteUnique = 0;
|
|
|
|
|
|
BOOL PUBLIC_PFTOBJ::bLoadRemoteFonts(
|
|
XDCOBJ &dco,
|
|
PFONTFILEVIEW *ppfv, // points to a pre mapped view of the font
|
|
// EngMapFontFile must NOT be called
|
|
// before sending it to the font driver
|
|
// EngUnmapFontFile must be called at
|
|
// the end of this routine for possible
|
|
// error cleanup
|
|
UINT cNumFonts
|
|
)
|
|
{
|
|
COUNT cFonts; // count of fonts in font file
|
|
BOOL bRet = FALSE; // assume failuer
|
|
HFF hffNew = HFF_INVALID; // IFI handle to font file
|
|
|
|
PVOID pvQuickBuffer[QUICK_VIEWS], *ppvViews;
|
|
ULONG pcjQuickBuffer[QUICK_VIEWS], *pcjViews;
|
|
|
|
if(cNumFonts > QUICK_VIEWS)
|
|
{
|
|
if(!(ppvViews = (VOID**) PALLOCMEM((sizeof(void*)+sizeof(ULONG*))*cNumFonts,
|
|
'vffG')))
|
|
{
|
|
WARNING("bLoadRemoteFonts unable to allocate memory\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pcjViews = (ULONG*) &ppvViews[QUICK_VIEWS];
|
|
}
|
|
else
|
|
{
|
|
ppvViews = pvQuickBuffer;
|
|
pcjViews = pcjQuickBuffer;
|
|
}
|
|
|
|
UINT i;
|
|
|
|
for(i = 0; i < cNumFonts; i++)
|
|
{
|
|
ppvViews[i] = ppfv[i]->fv.pvView;
|
|
pcjViews[i] = ppfv[i]->fv.cjView;
|
|
}
|
|
|
|
VACQUIRESEM(gpsemDriverMgmt);
|
|
PPDEV ppDevList = gppdevList;
|
|
|
|
do
|
|
{
|
|
PDEVOBJ pdo((HDEV)ppDevList);
|
|
|
|
ULONG ulFontCaps = 0;
|
|
|
|
if (PPFNVALID(pdo, QueryFontCaps))
|
|
{
|
|
ULONG ulBuf[2];
|
|
|
|
if ( (*PPFNDRV(pdo, QueryFontCaps))(2, ulBuf) != FD_ERROR )
|
|
{
|
|
ulFontCaps = ulBuf[1];
|
|
}
|
|
}
|
|
|
|
if (ulFontCaps & (QC_FONTDRIVERCAPS))
|
|
{
|
|
// make a reference to the font driver under the protection
|
|
// of the semaphore. This will guarantee that the font
|
|
// driver will not be unloaded unexpectedly. After that
|
|
|
|
// BUGBUG put back after LDEVs are cleaned up
|
|
// ldo.vReference();
|
|
|
|
|
|
VRELEASESEM(gpsemDriverMgmt);
|
|
|
|
// Attempt to load the font file.
|
|
// It is acceptable to release the lock at this point because
|
|
// we know this font driver has at least one reference to it.
|
|
// We also do not care if other font drivers are added or removed
|
|
// from the list while we are scanning it ...
|
|
|
|
// We are assuming that DrvLoadFontFile will call EngMapFontFile
|
|
// and EngUnmapFontFile in balanced pairs upon the view.
|
|
|
|
hffNew = (*PPFNDRV(pdo, LoadFontFile)) (cNumFonts,
|
|
(ULONG *) ppfv,
|
|
ppvViews, pcjViews,
|
|
(ULONG) gusLanguageID);
|
|
|
|
// Grab the lock again here (so we exit the loop properly)
|
|
|
|
VACQUIRESEM(gpsemDriverMgmt);
|
|
|
|
if (hffNew != HFF_INVALID)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// We did not load the font file properly
|
|
// Release the reference and go on.
|
|
|
|
// BUGBUG put back after LDEVs are cleaned up
|
|
// ldo.vUnreference();
|
|
}
|
|
}
|
|
|
|
} while(ppDevList = ppDevList->ppdevNext);
|
|
|
|
PDEVOBJ pdo((HDEV)ppDevList);
|
|
|
|
VRELEASESEM(gpsemDriverMgmt);
|
|
|
|
if(ppvViews != pvQuickBuffer)
|
|
{
|
|
VFREEMEM(ppvViews);
|
|
}
|
|
|
|
ASSERTGDI(bRet==FALSE,"bRet != FALSE\n");
|
|
|
|
if (hffNew != HFF_INVALID)
|
|
{
|
|
//
|
|
// cFonts = number of faces in the file
|
|
//
|
|
|
|
cFonts = (*PPFNDRV(pdo, QueryFontFile)) (hffNew,
|
|
QFF_NUMFACES,
|
|
0,
|
|
NULL);
|
|
|
|
if (cFonts && cFonts != FD_ERROR)
|
|
{
|
|
WCHAR awc[30];
|
|
|
|
// Create a (hopefully) unique file name for
|
|
// the remote font of the form "REMOTE nnnnnnnn"
|
|
|
|
swprintf(
|
|
awc,
|
|
L"REMOTE-%u",
|
|
ulGetNewUniqueness(PUBLIC_PFTOBJ::ulRemoteUnique));
|
|
ULONG cwc = wcslen(awc) + 1;
|
|
|
|
// Create new PFF with table big enough to accomodate
|
|
// the new fonts and pathname.
|
|
|
|
PFFCLEANUP *pPFFC = 0;
|
|
PFFMEMOBJ
|
|
pffmo (cFonts,
|
|
awc, cwc, cNumFonts, // pwsz, cwc, cFiles
|
|
hffNew,
|
|
pdo.hdev(),
|
|
0,
|
|
pPFT,
|
|
AFRW_ADD_REMOTE_FONT,
|
|
0, // flEmbed
|
|
0, // dwPidTid
|
|
ppfv );
|
|
|
|
if (pffmo.bValid())
|
|
{
|
|
// Tell the PFF user object to load its table of
|
|
// HPFE's for each font in file.
|
|
|
|
|
|
if ( pffmo.bLoadFontFileTable(awc,
|
|
cFonts,
|
|
dco.hdc()
|
|
))
|
|
{
|
|
// Stabilize font table before searching or modifying it.
|
|
|
|
SEMOBJ so2(gpsemPublicPFT);
|
|
|
|
if( bRet = pffmo.bAddHash() )
|
|
{
|
|
PFF **ppPFF, *pPFF;
|
|
|
|
pPFF = pPFFGet(awc, cwc, 1, &ppPFF);
|
|
if (pPFF)
|
|
{
|
|
KdPrint(("\"%ws\" has been found on the font table\n"));
|
|
KdBreakPoint();
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pPFF = pffmo.pPFFGet();
|
|
if( bRet = dco.bAddRemoteFont( pPFF ) )
|
|
{
|
|
pPFT->cFiles++;
|
|
|
|
// place the pointer to this new remote
|
|
// PFF at the head of the list
|
|
|
|
if (*ppPFF) // head of list exist?
|
|
{ // yes make it follow new PFF
|
|
(*ppPFF)->pPFFPrev = pPFF;
|
|
}
|
|
pPFF->pPFFNext = *ppPFF;
|
|
pPFF->pPFFPrev = 0; // new PFF is first in list
|
|
*ppPFF = pPFF;
|
|
|
|
pffmo.vKeepIt();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pffmo.vRemoveHash();
|
|
}
|
|
|
|
// Here we should add it to our HDC's font table.
|
|
}
|
|
|
|
// call this if the above addition to the HDC's font table
|
|
// fails
|
|
|
|
if (!bRet)
|
|
{
|
|
VOID *pv = (VOID*) pffmo.pPFFC_Delete();
|
|
if (pv && pv != (VOID *)-1)
|
|
{
|
|
vCleanupFontFile((PFFCLEANUP*) pv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PFTOBJ::bLoadDeviceFonts
|
|
*
|
|
* This function loads the device fonts of the device identified by the pair
|
|
* (pldo, hdev) into the public table. There are cFonts number of device
|
|
* fonts.
|
|
*
|
|
* The function will enlarge the PFT and create a PFF to contain the new fonts.
|
|
* The actual work of loading each device font into the tables is carrided
|
|
* out by PFF::bLoadDeviceFontTable().
|
|
*
|
|
* Note:
|
|
* All the device fonts of a particular physical device are grouped together
|
|
* as if they were in a single file and are placed all within a single PFF,
|
|
* with each font represented by a single PFE.
|
|
*
|
|
* Note:
|
|
* The function does not bother to check if the device fonts already are
|
|
* in the tree.*
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE if an error occurs.
|
|
*
|
|
* History:
|
|
* Mon 15-Aug-1994 11:57:14 by Kirk Olynyk [kirko]
|
|
* Modified it for the new hashing scheme (not the same thing as font name
|
|
* hashing, which remains unchanged).
|
|
* 18-Mar-1991 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
DEVICE_PFTOBJ::bLoadFonts(
|
|
PPDEVOBJ ppdo
|
|
)
|
|
{
|
|
PFF *pPFF, **ppPFF;
|
|
BOOL bRet = FALSE;
|
|
|
|
{
|
|
SEMOBJ so(gpsemPublicPFT);
|
|
if (pPFFGet(ppdo->hdev(), &ppPFF))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
//
|
|
// create new PFF with table big enough to accomodate the
|
|
// new device fonts
|
|
//
|
|
// the 'dhpdev' is used only for drivers that are font producers,
|
|
// and consequently are not affected by dynamic mode changing.
|
|
// We have to call 'dhpdevNotDynamic' to avoid an assert
|
|
//
|
|
|
|
PFFMEMOBJ pffmo(ppdo->cFonts(),
|
|
NULL,0,0, // no path, no files
|
|
HFF_INVALID,
|
|
ppdo->hdev(),
|
|
ppdo->dhpdevNotDynamic(),
|
|
pPFT,
|
|
0,
|
|
0, // flEmbed
|
|
0, // dwPidTid
|
|
NULL // no views of the mapped font files
|
|
);
|
|
|
|
if (pffmo.bValid())
|
|
{
|
|
if (!pffmo.bLoadDeviceFontTable(ppdo))
|
|
{
|
|
WARNING("pffmo.bLoadDeviceFontTable() failed\n");
|
|
}
|
|
else
|
|
{
|
|
SEMOBJ so(gpsemPublicPFT);
|
|
|
|
// if (!font_is_loaded_already) add_font_to_table;
|
|
|
|
if (!(pPFF = pPFFGet(ppdo->hdev(), &ppPFF)))
|
|
{
|
|
if (!pffmo.bAddHash())
|
|
{
|
|
WARNING("gdisrv!bLoadDeviceFontsPFTOBJ()"
|
|
": failed to add to font hash\n");
|
|
pffmo.vRemoveHash();
|
|
}
|
|
else
|
|
{
|
|
// Add file to font table
|
|
|
|
// Insert PFF at the head of the linked list
|
|
// pointed to by ppPFF
|
|
|
|
pPFF = pffmo.pPFF; // convenient pointer.
|
|
pPFT->cFiles += 1; // Increment total number
|
|
// of files in table.
|
|
if (*ppPFF) // Is there a PFF at the head
|
|
// of the linked list?
|
|
(*ppPFF)->pPFFPrev = pPFF; // Yes, put this new
|
|
pPFF->pPFFNext = *ppPFF; // PFF in front of old.
|
|
pPFF->pPFFPrev = 0; // Nothing before new font.
|
|
*ppPFF = pPFF; // Reset pointer to head of list.
|
|
pffmo.vKeepIt(); // Prevent ~PFFMEMOBJ from
|
|
// freeing memory.
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!bRet)
|
|
{
|
|
VOID *pv;
|
|
if ((pv = (VOID*)pffmo.pPFFC_Delete()) && pv != (VOID*)-1)
|
|
{
|
|
vCleanupFontFile((PFFCLEANUP*) pv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pwszBareName
|
|
*
|
|
* Given a string that may be either a complete path or a bare file name
|
|
* pwszBareName returns the bare file name with out the path.
|
|
*
|
|
* History:
|
|
* 7-Nov-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LPWSTR pwszBare( LPWSTR pwszPath )
|
|
{
|
|
LPWSTR pwszTmp,pwszBareName;
|
|
|
|
for( pwszTmp = pwszPath, pwszBareName = pwszPath ;
|
|
*pwszTmp != (WCHAR) 0 ;
|
|
pwszTmp ++ )
|
|
{
|
|
if( *pwszTmp == (WCHAR) '\\' )
|
|
{
|
|
pwszBareName = pwszTmp+1;
|
|
}
|
|
}
|
|
return(pwszBareName);
|
|
}
|
|
|
|
#if 0
|
|
|
|
typedef struct _FONT_STRUCT_DATA {
|
|
ULONG fontDataSize;
|
|
ULONG fontMaxDataSize;
|
|
ULONG cRegistryFonts;
|
|
ULONG cMaxRegistryFonts;
|
|
ULONG cHashBuckets;
|
|
PBYTE pFont;
|
|
} FONT_STRUCT_DATA, *PFONT_STRUCT_DATA;
|
|
|
|
extern "C"
|
|
NTSTATUS
|
|
QueryRegistryFontListRoutine
|
|
(
|
|
PWSTR ValueName,
|
|
ULONG ValueType,
|
|
PVOID ValueData,
|
|
ULONG ValueLength,
|
|
PVOID Context,
|
|
PVOID EntryContext
|
|
)
|
|
{
|
|
|
|
PFONT_STRUCT_DATA pFontStructData = (PFONT_STRUCT_DATA) Context;
|
|
ULONG Length;
|
|
|
|
if ( (pFontStructData->fontDataSize + ValueLength >
|
|
pFontStructData->fontMaxDataSize) ||
|
|
(pFontStructData->cRegistryFonts >= pFontStructData->cMaxRegistryFonts) ||
|
|
(pFontStructData->cRegistryFonts >= pFontStructData->cHashBuckets) )
|
|
{
|
|
//
|
|
// The buffer is too small - reallocate it (leave lots of place to
|
|
// build the hash table at the end
|
|
//
|
|
|
|
PBYTE pjBuffer;
|
|
ULONG i;
|
|
ULONG oldMaxSize = pFontStructData->fontMaxDataSize;
|
|
|
|
pFontStructData->fontMaxDataSize += 0x100;
|
|
pFontStructData->cMaxRegistryFonts += 10;
|
|
pFontStructData->cHashBuckets = pFontStructData->cMaxRegistryFonts * 2;
|
|
|
|
pjBuffer = (PBYTE) PALLOCMEM(pFontStructData->fontMaxDataSize +
|
|
pFontStructData->cMaxRegistryFonts *
|
|
sizeof(PBYTE) +
|
|
pFontStructData->cHashBuckets *
|
|
sizeof(REGHASHBKT) * 2, 'gerG');
|
|
|
|
//
|
|
// The buffer has three sections
|
|
// 1) the first part of the buffer contains all the NULL terminated
|
|
// strings of the font files.
|
|
// 2) an array of pointers to these strings.
|
|
// 3) space for the hash table
|
|
//
|
|
// When copying the buffer, 1) can just be moved, 2) has to be adjusted
|
|
// and 3) is not touched - has to be zero initialized
|
|
//
|
|
|
|
if (pjBuffer)
|
|
{
|
|
//
|
|
// If we have an old one, move it to the new one, and then
|
|
// always reset the pointer.
|
|
//
|
|
|
|
if (pFontStructData->fontDataSize)
|
|
{
|
|
//
|
|
// Adjust the pointers - requires doing arithmetic on the
|
|
// pointers themselves !
|
|
//
|
|
|
|
for (i=0; i < pFontStructData->cRegistryFonts; i++)
|
|
{
|
|
*( ((PULONG)(pjBuffer +
|
|
pFontStructData->fontMaxDataSize)) + i ) =
|
|
*( ((PULONG)(pFontStructData->pFont + oldMaxSize)) + i )
|
|
+ pjBuffer - pFontStructData->pFont;
|
|
}
|
|
|
|
//
|
|
// Copy all the data to the new Buffer
|
|
//
|
|
|
|
RtlMoveMemory(pjBuffer,
|
|
pFontStructData->pFont,
|
|
pFontStructData->fontDataSize);
|
|
|
|
VFREEMEM(pFontStructData->pFont);
|
|
}
|
|
|
|
pFontStructData->pFont = pjBuffer;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we do not have enough memory - return failiure
|
|
//
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
Length = cCapString((PWSTR) (pFontStructData->pFont +
|
|
pFontStructData->fontDataSize),
|
|
(PWSTR) ValueData,
|
|
ValueLength / 2);
|
|
|
|
ASSERTGDI(Length * 2 + 2 == ValueLength,
|
|
"QueryRegistryFontListRoutine CapString problem\n");
|
|
|
|
* ( ((PBYTE *)(pFontStructData->pFont + pFontStructData->fontMaxDataSize)) +
|
|
pFontStructData->cRegistryFonts) =
|
|
pFontStructData->pFont + pFontStructData->fontDataSize;
|
|
|
|
pFontStructData->fontDataSize += ValueLength;
|
|
pFontStructData->cRegistryFonts += 1;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL PFTOBJ::bUnloadAllButPermanentFonts
|
|
*
|
|
* Called at log-off time to force unloading off all but permanent
|
|
* fonts Permanent fonts are defined as either console fonts or
|
|
* fonts from Gre_Initialize section of win.ini (i.e. registry).
|
|
* Fonts from the "Fonts" section in win.ini (registry) are also
|
|
* permanent if they are on the local hard drive. If they are
|
|
* remote they will get reloaded at the log on time. This should
|
|
* be done after the net connections from the user profile are
|
|
* restored so that the font can get reloaded.
|
|
*
|
|
* History:
|
|
* 30-Nov-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
typedef struct _FONTVICTIM
|
|
{
|
|
PFF *pPFFVictim;
|
|
RFONT *prfntVictims;
|
|
} FONTVICTIM;
|
|
|
|
BOOL PFTOBJ::bUnloadAllButPermanentFonts ()
|
|
{
|
|
// pointer to the array of cFonts victim structures. Only as
|
|
// many entries of this array will be initialized as there are
|
|
// non-permanent fonts in the pft. These fonts will be deleted
|
|
// outside of the pft semaphore.
|
|
|
|
FONTVICTIM *pvict, *pvictCur;
|
|
COUNT cFile, cFonts;
|
|
PFF *pPFF;
|
|
|
|
|
|
// Look for the PFF to unload.
|
|
|
|
{
|
|
// Stablize table while we scan it for victims.
|
|
|
|
SEMOBJ so(gpsemPublicPFT);
|
|
|
|
// alloc mem for the array of font victims
|
|
// It is essential that this memory is zero initialized
|
|
// This must be done under semaphore, otherwise cFonts might change;
|
|
|
|
//!!! Don't you mean PALLOCMEM??? [kirko]
|
|
|
|
cFonts = pPFT->cFiles;
|
|
if (!(pvict = (FONTVICTIM *)PALLOCNOZ(cFonts * sizeof(FONTVICTIM),'ivfG')))
|
|
{
|
|
WARNING(
|
|
"PFTOBJ::bUnloadAllButPermanentFonts failure\n"
|
|
"Failed to allocate memeory for font victim list\n");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pvictCur = pvict;
|
|
|
|
// Caution with this code: pPFT->cFiles changes in the loop
|
|
// This loop does two things:
|
|
// a) stores the pPFFVictim information in the pvict array
|
|
// for the fonts that are going to be unloaded outside
|
|
// the semaphore.
|
|
// b) contracts the pft table to contain only the permanent
|
|
// fonts upon the exit of the loop
|
|
|
|
for (
|
|
PFF **ppPFF = pPFT->apPFF
|
|
; ppPFF < pPFT->apPFF + pPFT->cBuckets
|
|
; ppPFF++
|
|
)
|
|
{
|
|
for (pPFF = *ppPFF; pPFF; pPFF = pPFF->pPFFNext)
|
|
{
|
|
// Create a PFF user object. There shouldn't be any invalid
|
|
// handles in the PFT.
|
|
|
|
PFFOBJ pffo(pPFF);
|
|
ASSERTGDI(pffo.bValid(),
|
|
"gdisrv!bUnloadFontPFTOBJ(file): bad PPFF in public PFT\n");
|
|
|
|
// Is it a font driver loaded file? And if so, is this not a
|
|
// permanent file (listed in Gre_Initialize or loaded by
|
|
// console or local font from "fonts" section of the registry)
|
|
|
|
|
|
if (!pffo.bPermanent() /* && pffo.bEmbedOk() */)
|
|
{
|
|
// Tell PFF to decrement its load count and ask it if is
|
|
// ready to die. If it returns TRUE, we will need to delete
|
|
// (outside of semaphore since PFF deletion may cause driver
|
|
// to be called).
|
|
|
|
// we force the load count to zero. We are forcing the unload
|
|
// of this font
|
|
|
|
pffo.vSet_cLoaded((COUNT)0); // not loaded any more,
|
|
// avoid asserts
|
|
pffo.vKill();
|
|
|
|
{
|
|
// unlink the PFF from the collision list
|
|
|
|
if (*ppPFF == pPFF)
|
|
{
|
|
// The hash bucket contains a pointer to the first
|
|
// PFF in the collision list. If it turns out that
|
|
// the victim is this first in the list, then the
|
|
// address storred in the hash bucket must be changed
|
|
|
|
*ppPFF = pPFF->pPFFNext;
|
|
}
|
|
if (pPFF->pPFFNext)
|
|
{
|
|
pPFF->pPFFNext->pPFFPrev = pPFF->pPFFPrev;
|
|
}
|
|
if (pPFF->pPFFPrev)
|
|
{
|
|
pPFF->pPFFPrev->pPFFNext = pPFF->pPFFNext;
|
|
}
|
|
}
|
|
// Save handle of victim.
|
|
|
|
pvictCur->pPFFVictim = pffo.pPFFGet();
|
|
|
|
// Remove PFF and PFEs from hash tables. Fonts in this
|
|
// font file will no longer be enumerated or mapped to.
|
|
|
|
pffo.vRemoveHash();
|
|
pPFT->cFiles--;
|
|
|
|
// Construct a "kill" list of RFONTs.
|
|
|
|
pvictCur->prfntVictims = prfntKillList(pffo);
|
|
|
|
// point to the next entry in pvictCur array
|
|
|
|
pvictCur++;
|
|
}
|
|
else
|
|
{
|
|
// this is a permanent or a device font, leave them in
|
|
// set init to 1 for the next logon session
|
|
|
|
pffo.vSet_cLoaded((COUNT)1);
|
|
}
|
|
}
|
|
} // end of the for loop
|
|
}
|
|
|
|
// Delete the victims that were found:
|
|
// Overload cFonts to mean cFontsToBeDeleted:
|
|
|
|
cFonts = pvictCur - pvict;
|
|
|
|
for (cFile = 0; cFile < cFonts; cFile++)
|
|
{
|
|
ASSERTGDI(
|
|
pvict[cFile].pPFFVictim != (PPFF) NULL,
|
|
"GreRemoveAllButPermanentFonts, pPFFVictim IS null\n"
|
|
);
|
|
PFFOBJ pffoVictim(pvict[cFile].pPFFVictim);
|
|
ASSERTGDI(pffoVictim.bValid(),
|
|
"gdisrv!bUnloadFontPFTOBJ(device): PFF victim bad\n");
|
|
|
|
// If we need to kill any RFONT victims, now is the time to do it.
|
|
// bKillRFONTList() can handle NULL prfntVictims case.
|
|
// Note that we do not check the return, we go on to the
|
|
// next font [bodind]
|
|
|
|
bKillRFONTList(pffoVictim, pvict[cFile].prfntVictims);
|
|
}
|
|
|
|
// release memory
|
|
|
|
VFREEMEM(pvict);
|
|
|
|
// We didn't delete anything, but we're ok as long as we found the right
|
|
// PFF. PFF still referenced (either load count or RFONT count) and will
|
|
// be deleted later.
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bUnloadWorkhorse
|
|
*
|
|
* History:
|
|
* Mon 15-Aug-1994 14:10:53 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL PFTOBJ::bUnloadWorkhorse(
|
|
PFF *pPFF,
|
|
PFF **ppPFFHead, // bucket address
|
|
ERESOURCE *pSem // if the pointer is not zero,
|
|
// then this must be a pointer
|
|
// to the public font table
|
|
// semaphore and must be released
|
|
// before this procedure returns
|
|
)
|
|
{
|
|
PFF *pPFFVictim = 0; // Pointer to PFF to be deleted, only
|
|
// non zero when found and deleted
|
|
|
|
RFONT *prfntVictims = 0; // Pointer to RFONT kill list.
|
|
// These fonts are killed in an attempt
|
|
// to drive the cRFONT to zero so that
|
|
// the PFF may be deleted.
|
|
BOOL bFoundPFF = FALSE; // signals PFF was found (does not
|
|
// indicate deletion status);
|
|
#if DBG
|
|
static const PSZ pszReleaseSem = "PFTOBJ::bUnloadWorkhorse()"
|
|
" releasing gpPFTPublic";
|
|
#endif
|
|
|
|
TRACE_FONT((
|
|
"Entering PFTOBJ::bUnloadWorkhorse\n"
|
|
"\tpPFF=%-#x\n"
|
|
"\tppPFFHead=%-#x\n",
|
|
"\tpSem=%-#x\n",
|
|
pPFF, ppPFFHead, pSem
|
|
));
|
|
ASSERTGDI(!pSem || pSem==gpsemPublicPFT, "pSem!=gpsemPublicPFT\n");
|
|
|
|
if ( pPFF )
|
|
{
|
|
PFFOBJ pffo(pPFF);
|
|
ASSERTGDI(pffo.bValid(), "bad PPFF in public PFT\n");
|
|
if ( pffo.bEmbedOk() )
|
|
{
|
|
// Tell PFF to decrement its load count and ask it if is
|
|
// ready to die. If it returns TRUE, we will need to
|
|
// delete (outside of semaphore since PFF deletion may
|
|
// cause driver to be called).
|
|
|
|
bFoundPFF = TRUE;
|
|
if ( pffo.bDeleteLoadRef() )
|
|
{
|
|
// Remove PFF and PFEs from hash tables. Fonts in this
|
|
// font file will no longer be enumerated or mapped to.
|
|
|
|
pffo.vRemoveHash();
|
|
|
|
// now remove it from the font table hash
|
|
|
|
pPFFVictim = pPFF;
|
|
|
|
// If ppPFFHead is NULL then it means that we are
|
|
// unloading a font that has been added to the DC
|
|
// as a remote font and the this must be the public
|
|
// font table
|
|
|
|
PFF **ppPFF = ppPFFHead;
|
|
if( ppPFF == 0 )
|
|
{
|
|
ASSERTGDI(pPFF->pPFT==gpPFTPublic,
|
|
"PFF not in public font table\n");
|
|
PUBLIC_PFTOBJ *p = (PUBLIC_PFTOBJ*) this;
|
|
PFF *pPFF_Found =
|
|
p->pPFFGet(pPFF->pwszPathname_, pPFF->cwc, pPFF->cFiles, &ppPFF);
|
|
ASSERTGDI(pPFF==pPFF_Found,
|
|
"Could not find remote PFF in the font table\n");
|
|
}
|
|
if (*ppPFF == pPFF)
|
|
{
|
|
*ppPFF = pPFF->pPFFNext;
|
|
}
|
|
if (pPFF->pPFFNext)
|
|
{
|
|
(pPFF->pPFFNext)->pPFFPrev = pPFF->pPFFPrev;
|
|
}
|
|
if (pPFF->pPFFPrev)
|
|
{
|
|
(pPFF->pPFFPrev)->pPFFNext = pPFF->pPFFNext;
|
|
}
|
|
pPFT->cFiles--;
|
|
prfntVictims = prfntKillList(pffo);
|
|
}
|
|
}
|
|
if ( pPFFVictim )
|
|
{
|
|
PFFOBJ pffoVictim(pPFFVictim);
|
|
if ( !pffoVictim.bValid() )
|
|
{
|
|
RIP("pffoVictim is not valid\n");
|
|
bFoundPFF = 0;
|
|
}
|
|
else
|
|
{
|
|
// bKillRFONTList() can handle NULL prfntVictims case.
|
|
|
|
if ( pSem )
|
|
{
|
|
// The victim has been removed from the table
|
|
// so the semaphore for the table may be safely
|
|
// released. It is necessary to do this because
|
|
// bKillRFONTList() calls RFONTOBJ::bDeleteRFONT()
|
|
// which in turn locks the display. If we do
|
|
// not release the font table semaphore before
|
|
// the device lock, we will have deadlock.
|
|
|
|
TRACE_FONT(("%ws\n", pszReleaseSem));
|
|
VRELEASESEM(pSem);
|
|
pSem = 0;
|
|
}
|
|
bFoundPFF = bKillRFONTList(pffoVictim, prfntVictims);
|
|
}
|
|
}
|
|
|
|
// We didn't delete anything, but we're ok as long as we found
|
|
// the right PFF. PFF still referenced (either load count or
|
|
// RFONT count) and will be deleted later.
|
|
}
|
|
|
|
// Make sure the semampore is released before the procedure ends
|
|
|
|
if ( pSem )
|
|
{
|
|
TRACE_FONT(("%ws\n", pszReleaseSem));
|
|
VRELEASESEM(pSem);
|
|
}
|
|
|
|
TRACE_FONT(("Exiting PFTOBJ::bUnloadWorkhorse\n"
|
|
"\treturn value = %d\n", bFoundPFF));
|
|
return( bFoundPFF );
|
|
}
|
|
|
|
/****************************************************************************
|
|
* INT PFTOBJ::QueryFonts( PUNIVERSAL_FONT_ID, ULONG, PLARGE_INTEGER )
|
|
*
|
|
* History:
|
|
* 5/24/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
// initialize to some value that's not equal to a Type1 Rasterizer ID
|
|
|
|
UNIVERSAL_FONT_ID gufiLocalType1Rasterizer = { A_VALID_ENGINE_CHECKSUM, 0 };
|
|
|
|
INT PUBLIC_PFTOBJ::QueryFonts(
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
ULONG nBufferSize,
|
|
PLARGE_INTEGER pTimeStamp
|
|
)
|
|
{
|
|
ULONG cFonts = 0;
|
|
*pTimeStamp = PFTOBJ::FontChangeTime;
|
|
|
|
// if we aren't supplied with a buffer just return the time stamp and number
|
|
// of fonts
|
|
|
|
if( ( pufi == NULL ) || ( nBufferSize == 0 ) )
|
|
{
|
|
return(pPFT->cFiles + (UFI_TYPE1_RASTERIZER(&gufiLocalType1Rasterizer) ? 1 : 0));
|
|
}
|
|
|
|
PFF *pPFF;
|
|
SEMOBJ so(gpsemPublicPFT);
|
|
|
|
// Fill the first position with the identifier for the local rasterizer if one
|
|
// exists. This must be the first UFI in the list if it exists.
|
|
|
|
if(UFI_TYPE1_RASTERIZER(&gufiLocalType1Rasterizer))
|
|
{
|
|
pufi[cFonts++] = gufiLocalType1Rasterizer;
|
|
}
|
|
|
|
for (
|
|
PFF **ppPFF = pPFT->apPFF
|
|
; (ppPFF < pPFT->apPFF + pPFT->cBuckets) && (cFonts < nBufferSize)
|
|
; ppPFF++
|
|
)
|
|
{
|
|
for (pPFF = *ppPFF; (pPFF) && (cFonts<nBufferSize); pPFF = pPFF->pPFFNext)
|
|
{
|
|
// Create a PFF user object. There shouldn't be any invalid
|
|
// handles in the PFT.
|
|
|
|
PFFOBJ pffo(pPFF);
|
|
ASSERTGDI(pffo.bValid(),
|
|
"gdisrv!bUnloadFontPFTOBJ(file): bad PPFF in public PFT\n");
|
|
|
|
// be sure not to include remote fonts in list
|
|
|
|
if (!pffo.bRemote())
|
|
{
|
|
// Set the Index to 1. This value can be anything since we will only
|
|
// be using the UFI's passed back to determine if font file match.
|
|
// We could just pass back checksums but we may need to expand the
|
|
// UFI structure to include more than checksum's which is why I'm
|
|
// using UFI's.
|
|
|
|
pufi[cFonts].Index = 1;
|
|
pufi[cFonts++].CheckSum = pffo.ulCheckSum();
|
|
}
|
|
}
|
|
}
|
|
|
|
return(cFonts);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* prfntKillList
|
|
*
|
|
* Scans the display PDEV list looking for inactive RFONTs that realized
|
|
* from the given PFF. These RFONTs are put into a linked list (using the
|
|
* PDEV RFONTLINKs) that is returned as the function return.
|
|
*
|
|
* The function is quite aggressinve in its definition of an inactive RFONT.
|
|
* In addition to looking for victims on the inactive list of each PDEV,
|
|
* the function also scans the DC list off each PDEV for RFONTs that are
|
|
* selected into currently unused DCs.
|
|
*
|
|
* We're not worried about being aggressive with non-display PDEVs. The
|
|
* PDEV cleanup code will destroy extraneous RFONTs directly using the PDEV's
|
|
* RFONT list(s).
|
|
*
|
|
* The reason we are building a list of RFONT victims rather than killing
|
|
* them immediately is because we are holding the gpsemPublicPFT semaphore
|
|
* when this function is called.
|
|
*
|
|
* Returns:
|
|
* Pointer to the kill list, NULL if the list is empty.
|
|
*
|
|
* History:
|
|
* 11-Mar-1993 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
RFONT *prfntKillList(PFFOBJ &pffoVictim)
|
|
{
|
|
TRACE_FONT((
|
|
"Entering prfntKillList\n\tpffoVictim.pPFF = %-#x\n",pffoVictim.pPFF));
|
|
RFONT *prfntDeadMeat = PRFNTNULL;
|
|
|
|
// Must hold this semaphore to be sure that the display
|
|
// PDEV list is stable.
|
|
|
|
SEMOBJ so1(gpsemDriverMgmt);
|
|
|
|
// Must hold this semaphore so we can manipulate the RFONT links and
|
|
// RFONT::cSelected.
|
|
|
|
SEMOBJ so2(gpsemRFONTList);
|
|
TRACE_FONT(("Acquiring gpsemRFONTList\n"));
|
|
|
|
// Must hold this mutex so that no one else tries to come in and lock
|
|
// a DC while we're scanning the DC lists off the PDEVs.
|
|
//
|
|
// Since we're holding this mutex, we must be extremely careful not
|
|
// to create any user objects that will try to regrab the mutex.
|
|
// That is bad bad bad bad.
|
|
|
|
MLOCKFAST mlf;
|
|
TRACE_FONT(("Acquiring handle management semaphore\n"));
|
|
|
|
PDEV *pPDEV = gppdevList;
|
|
|
|
// Scan through the list of display PDEVs.
|
|
|
|
while (pPDEV != NULL)
|
|
{
|
|
if (pPDEV->fs & PDEV_DISPLAY)
|
|
{
|
|
// Scan the RFONT active list for candidates made inactive by our
|
|
// scan of the DC list.
|
|
|
|
RFONT *prfntCandidate;
|
|
|
|
for ( prfntCandidate = pPDEV->prfntActive;
|
|
prfntCandidate != PRFNTNULL;
|
|
)
|
|
{
|
|
RFONTTMPOBJ rfo(prfntCandidate);
|
|
|
|
// We have to grab the next pointer before we (possibly)
|
|
// remove the current RFONT from the list.
|
|
|
|
prfntCandidate = prfntCandidate->rflPDEV.prfntNext;
|
|
|
|
// If this is an interesting RFONT (i.e., uses our PFF),
|
|
// then take it out of the list.
|
|
|
|
if ( (rfo.pPFF() == pffoVictim.pPFFGet()) && !rfo.bActive() )
|
|
{
|
|
RFONT *prfntHead = pffoVictim.prfntList();
|
|
rfo.vRemove(&prfntHead, PFF_LIST);
|
|
pffoVictim.prfntList(prfntHead);
|
|
|
|
rfo.vRemove(&pPDEV->prfntActive, PDEV_LIST);
|
|
rfo.vInsert(&prfntDeadMeat, PDEV_LIST);
|
|
}
|
|
}
|
|
|
|
// Scan the RFONT inactive list for candidates.
|
|
|
|
for (prfntCandidate = pPDEV->prfntInactive;
|
|
prfntCandidate != PRFNTNULL;
|
|
)
|
|
{
|
|
RFONTTMPOBJ rfo(prfntCandidate);
|
|
|
|
// We have to grab the next pointer before we (possibly)
|
|
// remove the current RFONT from the list.
|
|
|
|
prfntCandidate = prfntCandidate->rflPDEV.prfntNext;
|
|
|
|
// If this is an interesting RFONT (i.e., uses our PFF),
|
|
// then take it out of the list.
|
|
|
|
if ( rfo.pPFF() == pffoVictim.pPFFGet() )
|
|
{
|
|
RFONT *prfntHead = pffoVictim.prfntList();
|
|
rfo.vRemove(&prfntHead, PFF_LIST);
|
|
pffoVictim.prfntList(prfntHead);
|
|
|
|
rfo.vRemove(&pPDEV->prfntInactive, PDEV_LIST);
|
|
rfo.vInsert(&prfntDeadMeat, PDEV_LIST);
|
|
|
|
// Since we've removed a font from the inactive list, we
|
|
// need to update the count in the PDEV.
|
|
|
|
pPDEV->cInactive -= 1;
|
|
}
|
|
}
|
|
}
|
|
pPDEV = pPDEV->ppdevNext;
|
|
}
|
|
TRACE_FONT(("Releasing handle management semaphore\n"));
|
|
TRACE_FONT(("Releasing gpsemRFONTList\n"));
|
|
TRACE_FONT(("Releasing gpsemDriverMgmt\n"));
|
|
TRACE_FONT(("Exiting prfntKillList\n\treturn value=%-#x\n", prfntDeadMeat));
|
|
return(prfntDeadMeat);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bKillRFONTList
|
|
*
|
|
* Runs down a linked list (that is linked via the PDEV RFONTLINK's) and
|
|
* deletes each RFONT on it. Hold no global semaphores while calling this
|
|
* because we may call out to a driver.
|
|
*
|
|
* History:
|
|
* 11-Mar-1993 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bKillRFONTList(PFFOBJ &pffoVictim, RFONT *prfntVictims)
|
|
{
|
|
// If kill list is NULL, it is already OK to delete the PFF.
|
|
// However, we will have to do the work in here rather than let
|
|
// RFONTOBJ::bDeleteRFONTRef() do the work for us.
|
|
|
|
BOOL bRet;
|
|
TRACE_FONT((
|
|
"Entering bKillRFONTList\n"
|
|
"\t*pffoVictim.pPFF=%-#x\n"
|
|
"\tprfntVictims=%-#x\n"
|
|
, pffoVictim.pPFF, prfntVictims
|
|
));
|
|
if (prfntVictims == (PRFONT) NULL)
|
|
{
|
|
PFFCLEANUP *pPFFC = (PFFCLEANUP *) NULL;
|
|
|
|
{
|
|
// Need semaphore to access cRFONT.
|
|
|
|
SEMOBJ so(gpsemPublicPFT);
|
|
|
|
// If no more RFONTs for this PFF, OK to delete.
|
|
// Load count is implied to be zero
|
|
// (only time we call this function).
|
|
|
|
ASSERTGDI(pffoVictim.cLoaded() == 0,
|
|
"gdisrv!bKillRFONTList(): PFF load count not zero\n");
|
|
|
|
if ( pffoVictim.cRFONT() == 0 )
|
|
{
|
|
// It is now safe to delete the PFF.
|
|
|
|
pPFFC = pffoVictim.pPFFC_Delete();
|
|
}
|
|
}
|
|
|
|
// Call the driver outside of the semaphore.
|
|
|
|
if (pPFFC == (PFFCLEANUP *) -1)
|
|
{
|
|
WARNING("gdisrv!bDeleteRFONTRefPFFOBJ(): error deleting PFF\n");
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
vCleanupFontFile(pPFFC); // function can handle NULL case
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Otherwise, we will delete the RFONTs in the kill list. If and when
|
|
// the last RFONT dies, RFONTOBJ::bDeleteRFONTRef() will delete the PFF.
|
|
|
|
PRFONT prfnt;
|
|
|
|
while ( (prfnt = prfntVictims) != (PRFONT) NULL )
|
|
{
|
|
prfntVictims = prfntVictims->rflPDEV.prfntNext;
|
|
|
|
RFONTTMPOBJ rflo(prfnt);
|
|
|
|
ASSERTGDI(!rflo.bActive(),
|
|
"gdisrv!bKillRFONTList(): RFONT still active\n");
|
|
|
|
PDEVOBJ pdo(rflo.hdevConsumer());
|
|
ASSERTGDI(pdo.bValid(), "gdisrv!bKillRFONTList(): invalid HPDEV\n");
|
|
|
|
rflo.bDeleteRFONT((PDEVOBJ *) NULL, (PFFOBJ *) NULL);
|
|
bRet = pffoVictim.bDeleteRFONTRef();
|
|
}
|
|
}
|
|
TRACE_FONT(("Exiting bKillRFONTList\n\treturn value = %d\n", bRet));
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cCapString (pwcDst,pwcSrc,cMax) *
|
|
* *
|
|
* A useful routine to capitalize a string. This is adapted to our name *
|
|
* strings that show up in logical fonts. They may or may not have NULL *
|
|
* terminators, but they always fit in a given width. *
|
|
* *
|
|
* We assume that we may overwrite the last character in the buffer if *
|
|
* there is no terminator! (That's what the code was doing when I got *
|
|
* to it.) *
|
|
* *
|
|
* Returns: The length, in characters, of the resultant string. *
|
|
* *
|
|
* History: *
|
|
* Sun 13-Dec-1992 17:22:25 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
LONG cCapString(WCHAR *pwcDst,WCHAR *pwcSrc,INT cMax)
|
|
{
|
|
UNICODE_STRING csSrc,csDst;
|
|
WCHAR *pwc,*pwcEnd;
|
|
INT cLen;
|
|
|
|
// Count the length of the given string, but note that we can be given a
|
|
// string with cMax characters and no terminator!
|
|
// In that case, we truncate the last character and replace it with NULL.
|
|
|
|
pwc = pwcSrc;
|
|
pwcEnd = pwc + cMax - 1;
|
|
|
|
while (pwc<pwcEnd && *pwc)
|
|
pwc++;
|
|
cLen = pwc - pwcSrc; // cLen <= cMax-1, always.
|
|
|
|
if (cLen)
|
|
{
|
|
// Initialize the counted string structures.
|
|
|
|
csSrc.Length = cLen * sizeof(WCHAR); // Measured in bytes!
|
|
csSrc.Buffer = pwcSrc;
|
|
csSrc.MaximumLength = cMax * sizeof(WCHAR);
|
|
|
|
csDst.Buffer = pwcDst;
|
|
csDst.MaximumLength = cMax * sizeof(WCHAR);
|
|
|
|
// Convert the string.
|
|
|
|
RtlUpcaseUnicodeString(&csDst,&csSrc,FALSE);
|
|
}
|
|
|
|
// NULL terminate the result.
|
|
|
|
pwcDst[cLen] = 0;
|
|
return(cLen);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* UINT iHash *
|
|
* *
|
|
* A case dependent hashing routine for Unicode strings. *
|
|
* *
|
|
* Input: *
|
|
* *
|
|
* pwsz pointer to the string to be hashed *
|
|
* c number to be mod'ed against at the end *
|
|
* *
|
|
* Reutrns: *
|
|
* *
|
|
* a 'random' number in the range 0,1,...,c-1 *
|
|
* *
|
|
* Note: All strings must be capitalized! *
|
|
* *
|
|
* History: *
|
|
* Wed 07-Sep-1994 08:12:22 by Kirk Olynyk [kirko] *
|
|
* Since chuck is gone the mice are free to play. So I have replaced *
|
|
* it with my own variety. Tests show that this one is better. Of *
|
|
* course, once I have gone someone will replace mine. By the way, *
|
|
* just adding the letters and adding produces bad distributions. *
|
|
* Tue 15-Dec-1992 03:13:15 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. It looks crazy, but I claim there's a theory behind it. *
|
|
\**************************************************************************/
|
|
|
|
UINT iHash(PWSZ pwsz, UINT c)
|
|
{
|
|
unsigned i = 0;
|
|
while (*pwsz)
|
|
{
|
|
// use the lower byte since that is where most of the
|
|
// interesting stuff happens
|
|
|
|
i += 256*i + (UCHAR) *pwsz++;
|
|
}
|
|
return(i % c);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* FHOBJ::vInit *
|
|
* *
|
|
* History: *
|
|
* Mon 14-Dec-1992 18:38:35 -by- Charles Whitmer [chuckwh] *
|
|
* Compressed the table to contain only pointers to buckets. *
|
|
* *
|
|
* Tue 14-Apr-1992 13:48:53 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID FHOBJ::vInit(FONTHASHTYPE fht_,UINT c)
|
|
{
|
|
pfh->id = FONTHASH_ID;
|
|
pfh->fht = fht_;
|
|
pfh->cBuckets = c;
|
|
|
|
// Currently, none of the buckets are in use
|
|
|
|
pfh->cUsed = 0;
|
|
pfh->cCollisions = 0;
|
|
RtlZeroMemory(pfh->apbkt,sizeof(*(pfh->apbkt)) * pfh->cBuckets);
|
|
|
|
// Setup head and tail pointers to the doubly linked list of
|
|
// buckets. This list is maintained in load order. The ordinal
|
|
// of a bucket is the load time of the earliest loaded PFE in a
|
|
// bucket's list.
|
|
|
|
pfh->pbktFirst = (HASHBUCKET *) NULL;
|
|
pfh->pbktLast = (HASHBUCKET *) NULL;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* FHOBJ::vFree *
|
|
* *
|
|
* History: *
|
|
* Tue 15-Dec-1992 00:53:39 -by- Charles Whitmer [chuckwh] *
|
|
* Deletes remaining hash buckets. *
|
|
* *
|
|
* Tue 14-Apr-1992 13:48:56 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID FHOBJ::vFree()
|
|
{
|
|
HASHBUCKET *pbkt,*pbktNext;
|
|
|
|
if (pfh)
|
|
{
|
|
// Unfortunately, we get called here while a string of PFE's may be
|
|
// hanging on. One of the PFTOBJ::bUnloadFont calls kills the PFE's
|
|
// separately.
|
|
|
|
// Clean up any hash buckets.
|
|
|
|
for (UINT ii=0; ii<pfh->cBuckets; ii++)
|
|
{
|
|
for
|
|
(
|
|
pbkt = pfh->apbkt[ii];
|
|
pbkt != (HASHBUCKET *) NULL;
|
|
pbkt = pbktNext
|
|
)
|
|
{
|
|
pbktNext = pbkt->pbktCollision;
|
|
VFREEMEM(pbkt);
|
|
}
|
|
}
|
|
|
|
// Free the table itself.
|
|
|
|
VFREEMEM(pfh);
|
|
}
|
|
pfh = 0;
|
|
*ppfh = 0;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* FHOBJ::pbktSearch (pwsz,pi) *
|
|
* *
|
|
* Tries to locate a HASHBUCKET for the given string. If found, a pointer *
|
|
* is returned, else NULL. If pi is non-NULL, the hash index is returned *
|
|
* in either case. *
|
|
* *
|
|
* History: *
|
|
* Mon 14-Dec-1992 21:11:14 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. Differs from KirkO's old iSearch in that it assumes that all *
|
|
* strings are capitalized, and the hash table is full of pointers to *
|
|
* HASHBUCKETs instead of HASHBUCKETs. *
|
|
\**************************************************************************/
|
|
|
|
HASHBUCKET *FHOBJ::pbktSearch(PWSZ pwsz,UINT *pi,PUNIVERSAL_FONT_ID pufi)
|
|
{
|
|
UINT i;
|
|
WCHAR *pwcA,*pwcB;
|
|
HASHBUCKET *pbkt;
|
|
|
|
// Locate the hash entry.
|
|
|
|
if( pwsz == NULL )
|
|
{
|
|
i = UFI_HASH_VALUE(pufi) % pfh->cBuckets;
|
|
}
|
|
else
|
|
{
|
|
i = iHash(pwsz,pfh->cBuckets);
|
|
}
|
|
|
|
// Return the index for those who care.
|
|
|
|
if (pi != (UINT *) NULL)
|
|
*pi = i;
|
|
|
|
// Try to find an existing bucket that matches exactly.
|
|
|
|
for
|
|
(
|
|
pbkt = pfh->apbkt[i];
|
|
pbkt != (HASHBUCKET *) NULL;
|
|
pbkt = pbkt->pbktCollision
|
|
)
|
|
{
|
|
if( pufi != NULL )
|
|
{
|
|
if( UFI_SAME_FILE(&pbkt->u.ufi,pufi) )
|
|
{
|
|
return(pbkt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (pwcA=pwsz,pwcB=pbkt->u.wcCapName; *pwcA==*pwcB; pwcA++,pwcB++)
|
|
{
|
|
if (*pwcA == 0)
|
|
return(pbkt);
|
|
}
|
|
}
|
|
}
|
|
return(pbkt);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* FHOBJ::bInsert *
|
|
* *
|
|
* Insert a new PFE into the font hash table. *
|
|
* *
|
|
* History: *
|
|
* Mon 14-Dec-1992 22:51:22 -by- Charles Whitmer [chuckwh] *
|
|
* Moved HASHBUCKETs out of the hash table. We now create them as needed. *
|
|
* *
|
|
* 06-Aug-1992 00:43:37 by Gilman Wong [gilmanw] *
|
|
* Added support for font enumeration list. *
|
|
* *
|
|
* Tue 14-Apr-1992 13:49:24 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL FHOBJ::bInsert(PFEOBJ& pfeoNew)
|
|
{
|
|
// Capitalize the given string. We will always match on the capitalized
|
|
// string.
|
|
|
|
WCHAR wcCap[LF_FACESIZE];
|
|
|
|
HASHBUCKET *pbkt;
|
|
UINT iBucket;
|
|
|
|
if( fht() == FHT_UFI )
|
|
{
|
|
UNIVERSAL_FONT_ID ufi;
|
|
|
|
pfeoNew.vUFI( &ufi );
|
|
pbkt = pbktSearch(NULL,&iBucket,&ufi);
|
|
|
|
}
|
|
else
|
|
{
|
|
cCapString(wcCap,pwszName(pfeoNew),LF_FACESIZE);
|
|
|
|
// Locate the hashbucket.
|
|
|
|
pbkt = pbktSearch(wcCap,&iBucket);
|
|
}
|
|
|
|
// We need to deal with a potential conflict with device font family
|
|
// equivalence classes. A device can define a set of equivalent (or
|
|
// aliased) family names for the base (or physical) name of a font.
|
|
// For example, a device may define that for the "Helvetica" family,
|
|
// it may be aliased to be equivalent to the "Helv", and "Arial" names.
|
|
// We record this information by linking the "Helv" and "Arial"
|
|
// buckets to the "Helvetica" chain.
|
|
//
|
|
// However, if we later load a "Helv" device font, we want it to supplant
|
|
// or replace the "Helvetica" chain with the "Helv" chain. So we need to
|
|
// check to see if the bucket we found is in an equivalence class. If it
|
|
// is, we need to treat it as if it were a new bucket (because we are going
|
|
// to remove its link to the base name chain).
|
|
//
|
|
// So, we need to check to see if we need to create a new bucket or
|
|
// reuse an existing one.
|
|
|
|
if ( (pbkt == (HASHBUCKET *) NULL) || (pbkt->fl & HB_EQUIV_FAMILY) )
|
|
{
|
|
BOOL bNewBucket = FALSE;
|
|
|
|
// If a bucket already exists (i.e., we are reusing what used to be
|
|
// an family name equivalence class bucket), we will reuse it.
|
|
// Otherwise, we will create a new HASHBUCKET.
|
|
|
|
if (pbkt == (HASHBUCKET *) NULL)
|
|
{
|
|
pbkt = (HASHBUCKET *) PALLOCMEM(sizeof(HASHBUCKET), 'bahG');
|
|
if (pbkt == (HASHBUCKET *) NULL)
|
|
return(FALSE);
|
|
|
|
bNewBucket = TRUE;
|
|
}
|
|
|
|
// Link the PFE into the empty lists.
|
|
|
|
pbkt->ppfeEnumHead =
|
|
pbkt->ppfeEnumTail = pfeoNew.ppfeGet();
|
|
|
|
*pppfeEnumNext(pfeoNew) = PPFENULL;
|
|
|
|
// Set up the linked list pointers. We always add new buckets at the
|
|
// tail of the load order linked list.
|
|
|
|
if ( pfh->pbktFirst == (HASHBUCKET *) NULL )
|
|
{
|
|
// Special case: this is the first bucket to be put on the list.
|
|
|
|
pfh->pbktFirst = pbkt;
|
|
pfh->pbktLast = pbkt;
|
|
|
|
pbkt->pbktPrev = (HASHBUCKET *) NULL;
|
|
pbkt->pbktNext = (HASHBUCKET *) NULL;
|
|
}
|
|
else
|
|
{
|
|
pbkt->pbktPrev = pfh->pbktLast;
|
|
pbkt->pbktNext = (HASHBUCKET *) NULL;
|
|
|
|
pfh->pbktLast->pbktNext = pbkt;
|
|
pfh->pbktLast = pbkt;
|
|
}
|
|
|
|
// Record the time stamp of the bucket. Its time stamp is the
|
|
// time stamp of its oldest (or first) PFE. Since this is a new
|
|
// bucket, the time stamp is automatically that of pfeoNew.
|
|
|
|
pbkt->ulTime = pfeoNew.ulTimeStamp();
|
|
|
|
// Finish up.
|
|
|
|
pbkt->fl = 0;
|
|
pbkt->cTrueType = (pfeoNew.flFontType() & TRUETYPE_FONTTYPE) ? 1 : 0;
|
|
pbkt->cRaster = (pfeoNew.flFontType() & RASTER_FONTTYPE) ? 1 : 0;
|
|
|
|
// Copy in the string.
|
|
|
|
if( fht() == FHT_UFI )
|
|
{
|
|
pfeoNew.vUFI( &(pbkt->u.ufi) );
|
|
}
|
|
else
|
|
{
|
|
for (INT ii=0; ii<LF_FACESIZE; ii++)
|
|
pbkt->u.wcCapName[ii] = wcCap[ii];
|
|
}
|
|
|
|
// If this is a new bucket, link it into the hash table. If its a
|
|
// reused bucket its already linked in at the proper location (if
|
|
// we're reusing a bucket, it means we are replacing an aliased
|
|
// bucket with a base name bucket OF THE SAME FAMILY NAME).
|
|
|
|
if (bNewBucket)
|
|
{
|
|
pbkt->pbktCollision = pfh->apbkt[iBucket];
|
|
if (pbkt->pbktCollision != (HASHBUCKET *) NULL)
|
|
pfh->cCollisions++;
|
|
pfh->apbkt[iBucket] = pbkt;
|
|
pfh->cUsed++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// In the following we have found an existing HASHBUCKET.
|
|
// We can assume that its lists are non-empty.
|
|
|
|
// Insert into the font enumeration list. The new PFE is inserted at
|
|
// the tail because we want to preserve the order in which fonts are
|
|
// added to the system (Windows 3.1 compatibility).
|
|
|
|
// Append new PFE to old tail.
|
|
|
|
PFEOBJ pfeoTmp(pbkt->ppfeEnumTail); ASSERTPFEO(pfeoTmp);
|
|
*pppfeEnumNext(pfeoTmp) = pfeoNew.ppfeGet();
|
|
|
|
// Fixup tail pointer and terminate list with HPFE_INVALID.
|
|
|
|
*pppfeEnumNext(pfeoNew) = PPFENULL;
|
|
pbkt->ppfeEnumTail = pfeoNew.ppfeGet();
|
|
|
|
// Track the number of TrueType fonts.
|
|
|
|
if (pfeoNew.flFontType() & TRUETYPE_FONTTYPE)
|
|
pbkt->cTrueType++;
|
|
|
|
// Track the number of Raster fonts.
|
|
|
|
if (pfeoNew.flFontType() & RASTER_FONTTYPE)
|
|
pbkt->cRaster++;
|
|
}
|
|
|
|
// Do we need to add equivalence class family names to the hash table?
|
|
|
|
if ( pfeoNew.bEquivNames() && (fht() == FHT_FAMILY) )
|
|
{
|
|
HASHBUCKET *pbktEquiv;
|
|
PWSZ pwszEquivName = pwszName(pfeoNew);
|
|
|
|
// Skip to first equiv name.
|
|
|
|
while (*pwszEquivName++);
|
|
|
|
// Process each equiv. name until we hit the list terminator (NULL).
|
|
|
|
while (*pwszEquivName)
|
|
{
|
|
// Capitalize the name.
|
|
|
|
cCapString(wcCap,pwszEquivName,LF_FACESIZE);
|
|
|
|
// Locate the hashbucket.
|
|
|
|
pbktEquiv = pbktSearch(wcCap,&iBucket);
|
|
|
|
// If a base name HASHBUCKET exists, we certainly don't want to
|
|
// replace it with aliased font info. But if the existing bucket
|
|
// is already an alias bucket, there isn't anything wrong with
|
|
// saying that the last one has precedence. Therefore, only if
|
|
// the bucket doesn't exist OR it is already an alias bucket
|
|
// do we proceed.
|
|
|
|
if (
|
|
(pbktEquiv == (HASHBUCKET *) NULL)
|
|
|| (pbktEquiv->fl & HB_EQUIV_FAMILY)
|
|
)
|
|
{
|
|
BOOL bNewBucket = FALSE;
|
|
|
|
// Do we need a new bucket?
|
|
|
|
if (pbktEquiv == (HASHBUCKET *) NULL)
|
|
{
|
|
// Allocate a new HASHBUCKET.
|
|
|
|
pbktEquiv = (HASHBUCKET *) PALLOCMEM(sizeof(HASHBUCKET), 'bahG');
|
|
if (pbktEquiv == (HASHBUCKET *) NULL)
|
|
{
|
|
// We could fail the call because of the low memory.
|
|
// But we'll break out instead. The side effect is
|
|
// that we may get some mapping errors, but that is
|
|
// an acceptable degradation of performance in this
|
|
// situation.
|
|
|
|
WARNING(
|
|
"FHOBJ::bInsert(): memory allocation failed\n");
|
|
break;
|
|
}
|
|
|
|
bNewBucket = TRUE;
|
|
}
|
|
|
|
// The equiv. name HASHBUCKET does not have its own list.
|
|
// Rather, it points to the same list as the base name
|
|
// HASHBUCKET. So we don't need to insert anything onto a
|
|
// list. Rather, we will just copy the base name HASHBUCKE
|
|
// into the equiv. name bucket (modifying the cap name and
|
|
// flag that indicates equiv. name, of course).
|
|
|
|
HASHBUCKET *pbktCollisionSave = pbktEquiv->pbktCollision;
|
|
|
|
*pbktEquiv = *pbkt; // copy base name HB
|
|
|
|
pbktEquiv->fl = HB_EQUIV_FAMILY; // modify flag
|
|
|
|
for (INT ii=0; ii<LF_FACESIZE; ii++) // change cap name
|
|
pbktEquiv->u.wcCapName[ii] = wcCap[ii];
|
|
|
|
// If its a new bucket, link it into the hash table.
|
|
|
|
if (bNewBucket)
|
|
{
|
|
pbktEquiv->pbktCollision = pfh->apbkt[iBucket];
|
|
if (pbktEquiv->pbktCollision != (HASHBUCKET *) NULL)
|
|
pfh->cCollisions++;
|
|
pfh->apbkt[iBucket] = pbktEquiv;
|
|
pfh->cUsed++;
|
|
}
|
|
|
|
// On the other hand, if its a reused bucket, we've wiped out
|
|
// the collision list when we copied the base name bucket.
|
|
// The bucket must remain in the proper collision list, so we
|
|
// need to restore it now (the old collision link is the right
|
|
// one because the aliased name has not changed--just the
|
|
// base name it is associated with has changed).
|
|
|
|
else
|
|
pbktEquiv->pbktCollision = pbktCollisionSave;
|
|
|
|
}
|
|
|
|
// Skip to next name.
|
|
|
|
while (*pwszEquivName++);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* FHOBJ::vDelete *
|
|
* *
|
|
* Removes a PFE from all the lists hanging off the hash table. *
|
|
* *
|
|
* History: *
|
|
* Mon 14-Dec-1992 23:39:28 -by- Charles Whitmer [chuckwh] *
|
|
* Changed to search for buckets. Made it delete the bucket at the end, *
|
|
* instead of reconstructing the whole table. *
|
|
* *
|
|
* 06-Aug-1992 00:43:37 by Gilman Wong [gilmanw] *
|
|
* New deletion algorithm. Also, added support for font enumeration list. *
|
|
* *
|
|
* Tue 14-Apr-1992 13:49:05 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID FHOBJ::vDelete(PFEOBJ& pfeoV)
|
|
{
|
|
// Capitalize the search string.
|
|
|
|
WCHAR wcCapName[LF_FACESIZE];
|
|
UINT iBucket;
|
|
HASHBUCKET *phbkt;
|
|
|
|
if( fht() == FHT_UFI )
|
|
{
|
|
UNIVERSAL_FONT_ID ufi;
|
|
|
|
pfeoV.vUFI( &ufi );
|
|
phbkt = pbktSearch(NULL,&iBucket,&ufi);
|
|
|
|
}
|
|
else
|
|
{
|
|
cCapString(wcCapName,pwszName(pfeoV),LF_FACESIZE);
|
|
|
|
// Determine hash position in the table.
|
|
|
|
phbkt = pbktSearch(wcCapName,&iBucket);
|
|
}
|
|
|
|
#if DBG
|
|
BOOL bFoundVictim; // used only for debugging
|
|
#endif
|
|
|
|
// Does the list exist? It is possible that on the facename list this PFE
|
|
// may not exist. The set of PFEs in the facename list is a subset of the
|
|
// set of PFEs in the family name list.
|
|
|
|
// Return if there is no list.
|
|
|
|
if (phbkt == (HASHBUCKET *) NULL)
|
|
return;
|
|
|
|
// ----------------------------------
|
|
// Remove from font enumeration list.
|
|
// ----------------------------------
|
|
|
|
// Check for special case: victim is head of list.
|
|
|
|
if (phbkt->ppfeEnumHead == pfeoV.ppfeGet())
|
|
{
|
|
// Victim found, new head of list.
|
|
|
|
phbkt->ppfeEnumHead = *pppfeEnumNext(pfeoV);
|
|
|
|
// Tail check. List may now be empty, so we may need to adjust tail.
|
|
|
|
if (phbkt->ppfeEnumHead == PPFENULL)
|
|
phbkt->ppfeEnumTail = PPFENULL;
|
|
}
|
|
|
|
else
|
|
{
|
|
// If we're here, victim is either in the middle or end of the list.
|
|
|
|
PFEOBJ pfeoScan2(phbkt->ppfeEnumHead);
|
|
#if DBG
|
|
bFoundVictim = FALSE;
|
|
#endif
|
|
|
|
// Search loop; look for victim on the linked list.
|
|
do
|
|
{
|
|
if (*pppfeEnumNext(pfeoScan2) == pfeoV.ppfeGet())
|
|
{
|
|
//
|
|
// Victim found.
|
|
//
|
|
*pppfeEnumNext(pfeoScan2) = *pppfeEnumNext(pfeoV);
|
|
|
|
#if DBG
|
|
bFoundVictim = TRUE;
|
|
#endif
|
|
|
|
//
|
|
// Tail check. If victim is also the tail, we need a new tail.
|
|
//
|
|
if (*pppfeEnumNext(pfeoV) == PPFENULL)
|
|
phbkt->ppfeEnumTail = pfeoScan2.ppfeGet();
|
|
|
|
//
|
|
// Get out of search loop.
|
|
//
|
|
break;
|
|
}
|
|
} while ( bEnumNext(&pfeoScan2) );
|
|
|
|
// PFE must exist somewhere on the list.
|
|
|
|
ASSERTGDI (
|
|
bFoundVictim,
|
|
"gdisrv!vDeleteFHOBJ(): PFE not found in font enumeration list\n"
|
|
);
|
|
}
|
|
|
|
//
|
|
// Track the number of TrueType fonts.
|
|
//
|
|
if (pfeoV.flFontType() & TRUETYPE_FONTTYPE)
|
|
phbkt->cTrueType--;
|
|
|
|
//
|
|
// Track the number of Raster fonts.
|
|
//
|
|
if (pfeoV.flFontType() & RASTER_FONTTYPE)
|
|
phbkt->cRaster--;
|
|
|
|
|
|
// If the bucket has no PFE's attached, delete it.
|
|
|
|
if (phbkt->ppfeEnumHead == PPFENULL)
|
|
{
|
|
// We have to remove the HASHBUCKET from the load order linked list.
|
|
|
|
if (phbkt->pbktPrev != (HASHBUCKET *) NULL)
|
|
phbkt->pbktPrev->pbktNext = phbkt->pbktNext;
|
|
else
|
|
pfh->pbktFirst = phbkt->pbktNext; // new head of list
|
|
|
|
if (phbkt->pbktNext != (HASHBUCKET *) NULL)
|
|
phbkt->pbktNext->pbktPrev = phbkt->pbktPrev;
|
|
else
|
|
pfh->pbktLast = phbkt->pbktPrev; // new tail of list
|
|
|
|
// We also have to remove the HASHBUCKET from the collision list.
|
|
|
|
for
|
|
(
|
|
HASHBUCKET **ppbkt = &pfh->apbkt[iBucket];
|
|
*ppbkt != phbkt;
|
|
ppbkt = &((*ppbkt)->pbktCollision)
|
|
)
|
|
{}
|
|
*ppbkt = phbkt->pbktCollision;
|
|
|
|
// Reduce the counts in the hash table.
|
|
|
|
pfh->cUsed--;
|
|
if (pfh->apbkt[iBucket] != (HASHBUCKET *) NULL)
|
|
pfh->cCollisions--;
|
|
|
|
// Delete the HASHBUCKET.
|
|
|
|
VFREEMEM(phbkt);
|
|
}
|
|
|
|
// If we haven't deleted the bucket,
|
|
// check to see if its time stamp should be changed.
|
|
|
|
else
|
|
{
|
|
// The time stamp of a bucket is the time stamp of its oldest
|
|
// PFE. Since the font enumeration PFE list is also maintained
|
|
// in load order, the bucket time stamp is equivalent to the time
|
|
// stamp of the first bucket in its font enumeration list.
|
|
|
|
if ( phbkt->ulTime == phbkt->ppfeEnumHead->ulTimeStamp )
|
|
{
|
|
// If the time stamps are equal, the head of the list was not
|
|
// deleted. Therefore, the position of this bucket in the
|
|
// load order list has not changed and we are done.
|
|
|
|
return;
|
|
}
|
|
|
|
// Update the time stamp.
|
|
|
|
phbkt->ulTime = phbkt->ppfeEnumHead->ulTimeStamp;
|
|
|
|
// The bucket can only get younger if the head of the list is removed.
|
|
// Therefore we need only probe forward for the new position of the
|
|
// hash bucket.
|
|
|
|
// We will stop the scan when we are pointing at the bucket that
|
|
// precedes the new position.
|
|
|
|
for ( HASHBUCKET *pbktProbe = phbkt;
|
|
(pbktProbe->pbktNext != (HASHBUCKET *) NULL)
|
|
&& (pbktProbe->pbktNext->ulTime < phbkt->ulTime);
|
|
pbktProbe = pbktProbe->pbktNext
|
|
);
|
|
|
|
// If we found a new position and it isn't the one we already occupy,
|
|
// move the bucket.
|
|
|
|
if (pbktProbe != phbkt)
|
|
{
|
|
// Remove the bucket from its current position.
|
|
|
|
if (phbkt->pbktPrev != (HASHBUCKET *) NULL)
|
|
phbkt->pbktPrev->pbktNext = phbkt->pbktNext;
|
|
else
|
|
pfh->pbktFirst = phbkt->pbktNext; // new head of list
|
|
|
|
if (phbkt->pbktNext != (HASHBUCKET *) NULL)
|
|
phbkt->pbktNext->pbktPrev = phbkt->pbktPrev;
|
|
|
|
// It is not necessary to handle the case of a new tail
|
|
// because if this were the current tail, we would not be
|
|
// attempting to move it.
|
|
|
|
// Insert at its new position. Remember: pbktProbe is pointing to
|
|
// the bucket that should precede this one.
|
|
|
|
phbkt->pbktPrev = pbktProbe;
|
|
phbkt->pbktNext = pbktProbe->pbktNext;
|
|
|
|
pbktProbe->pbktNext = phbkt;
|
|
if (phbkt->pbktNext != (HASHBUCKET *) NULL)
|
|
phbkt->pbktNext->pbktPrev = phbkt;
|
|
else
|
|
pfh->pbktLast = phbkt; // new tail for the list
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ENUMFONTSTYLE efsCompute(BOOL *abFoundStyle, PFEOBJ &pfeo)
|
|
*
|
|
* Computes a font enumeration style category for the given pfeo.
|
|
*
|
|
* An array of flags, abFoundStyle, is passed in. There is a flag
|
|
* for each style classification returned by PFEOBJ::efsCompute().
|
|
*
|
|
* These flags are set as PFEs for each category are found.
|
|
* Once a category is filled, then all subsequent fonts of the
|
|
* same category are marked as either EFSTYLE_OTHER (if facename
|
|
* is different than family name, thereby allowing us to use it
|
|
* to distinguish from other fonts of this family) or EFSTYLE_SKIP
|
|
* (if facename is the same as the family name).
|
|
*
|
|
* This is to support Win 3.1 EnumFonts() behavior which can only
|
|
* discriminate 4 different styles for each family of fonts.
|
|
*
|
|
* History:
|
|
* 07-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ENUMFONTSTYLE efstyCompute(BOOL *abFoundStyle, PFEOBJ &pfeo)
|
|
{
|
|
ENUMFONTSTYLE efsty = pfeo.efstyCompute();
|
|
|
|
if ( !abFoundStyle[efsty] )
|
|
{
|
|
abFoundStyle[efsty] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if ( _wcsicmp(pfeo.pwszFamilyName(), pfeo.pwszFaceName()) )
|
|
{
|
|
efsty = EFSTYLE_OTHER;
|
|
}
|
|
else
|
|
{
|
|
efsty = EFSTYLE_SKIP;
|
|
}
|
|
}
|
|
|
|
return efsty;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* BOOL FHOBJ::bScanLists *
|
|
* *
|
|
* This implements the behavior of EnumFonts() and EnumFontFamilies() when *
|
|
* a NULL name is passed in. If the bComputeStyles flag is TRUE, the *
|
|
* EnumFonts() behavior of enumerating some fonts by their facename (rather *
|
|
* than family name) is used. *
|
|
* *
|
|
* This function puts HPFEs from the hash table and lists into the EFSOBJ. *
|
|
* If bComputeStyles is FALSE, only the font enumeration list heads from *
|
|
* each bucket are added to the EFSOBJ. *
|
|
* *
|
|
* If bComputeStyles is TRUE, then each list is scanned and a style *
|
|
* classification (EFSTYLE) is computed. Fonts classified as EFSTYLE_OTHER *
|
|
* are also added to the EFSOBJ. *
|
|
* *
|
|
* Return: *
|
|
* Returns FALSE if an error occurs; TRUE otherwise. *
|
|
* *
|
|
* History: *
|
|
* 15-Jan-1993 -by- Gilman Wong [gilmanw] *
|
|
* Changed to use the linked list that preserves PFE load order for outer *
|
|
* loop. *
|
|
* *
|
|
* Mon 14-Dec-1992 23:50:10 -by- Charles Whitmer [chuckwh] *
|
|
* Changed outer loop logic for new hashing. *
|
|
* *
|
|
* 07-Aug-1992 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL FHOBJ::bScanLists (
|
|
EFSOBJ *pefso, // fill this EFSOBJ
|
|
ULONG iEnumType, // Enum Fonts, Families or FamiliesEx
|
|
EFFILTER_INFO *peffi // filtering information
|
|
)
|
|
{
|
|
HASHBUCKET *phbkt;
|
|
// better C++ code generation if you always return a variable
|
|
BOOL bRet = FALSE;
|
|
FLONG flAdd = 0;
|
|
|
|
if (iEnumType == TYPE_ENUMFONTFAMILIES)
|
|
flAdd |= FL_ENUMFAMILIES;
|
|
if (iEnumType == TYPE_ENUMFONTFAMILIESEX)
|
|
flAdd |= FL_ENUMFAMILIESEX;
|
|
|
|
// Scan through the hash table using the load ordered linked list.
|
|
|
|
for (phbkt = pfh->pbktFirst;
|
|
phbkt != (HASHBUCKET *) NULL;
|
|
phbkt = phbkt->pbktNext
|
|
)
|
|
{
|
|
// If the list exists, need to scan it. We skip over equiv. name
|
|
// HASHBUCKETs. These are here only to allow the mapper to alias
|
|
// printer font names to other "equivlaent" names. We do not
|
|
// enumerate them.
|
|
|
|
if (
|
|
(phbkt->ppfeEnumHead != PPFENULL)
|
|
&& !(phbkt->fl & HB_EQUIV_FAMILY)
|
|
)
|
|
{
|
|
PFEOBJ pfeo(phbkt->ppfeEnumHead);
|
|
|
|
ASSERTGDI (
|
|
pfeo.bValid(),
|
|
"gdisrv!bScanListsFHOBJ(NULL): bad HPFE handle\n"
|
|
);
|
|
|
|
// This flag is used only if bComputeStyles is TRUE (i.e.,
|
|
// processing an EnumFonts() request). We use this to track
|
|
// whether or not the first suitable font in the list is found
|
|
// yet. The first font PLUS fonts that are EFSTYLE_OTHER
|
|
// are put in the enumeration.
|
|
|
|
BOOL bFoundFirst = FALSE;
|
|
|
|
// These flags are set as PFEs for each category are found.
|
|
// Once a category is filled, then all subsequent fonts of the
|
|
// same category are marked as either EFSTYLE_OTHER (if facename
|
|
// is different than family name, thereby allowing us to use it
|
|
// to distinguish from other fonts of this family) or EFSTYLE_SKIP
|
|
// (if facename is the same as the family name).
|
|
//
|
|
// This is to support Win 3.1 EnumFonts() behavior which can only
|
|
// discriminate 4 different styles for each family of fonts.
|
|
|
|
BOOL abFoundStyle[EFSTYLE_MAX];
|
|
RtlZeroMemory((PVOID) abFoundStyle, EFSTYLE_MAX * sizeof(BOOL));
|
|
|
|
// Windows 3.1 compatibility
|
|
//
|
|
// When NULL is passed into EnumFonts or EnumFontFamilies,
|
|
// raster fonts are not enumerated if a TrueType font of the same
|
|
// name exists. We can emulate this behavior by turning on
|
|
// the "TrueType duplicate" filter (the same one used by the
|
|
// (GACF_TTIGNORERASTERDUPE app compatibility flag) for the NULL case.
|
|
|
|
peffi->bTrueTypeDupeFilter = TRUE;
|
|
|
|
// Win3.1 App compatibility flag GACF_TTIGNORERASTERDUPE. Need
|
|
// to copy count of TrueType from bucket into EFFILTER_INFO, peffi.
|
|
|
|
peffi->cTrueType = phbkt->cTrueType;
|
|
|
|
// Scan the list for candidates.
|
|
|
|
do
|
|
{
|
|
// Skip this PFE if it needs to be filtered out.
|
|
|
|
if ( pfeo.bFilteredOut(peffi) )
|
|
continue;
|
|
|
|
// EnumFonts() or EnumFontFamilies() processing (bComputeStyles
|
|
// is TRUE for EnumFonts()).
|
|
|
|
if (iEnumType != TYPE_ENUMFONTS)
|
|
{
|
|
// EnumFontFamilies --
|
|
// Need only the first one on the list.
|
|
|
|
if (!pefso->bAdd(pfeo.ppfeGet(),EFSTYLE_REGULAR,flAdd,peffi->lfCharSetFilter))
|
|
{
|
|
// Error return. bAdd() will set error code.
|
|
|
|
WARNING(
|
|
"gdisrv!bScanListsFHOBJ(NULL): "
|
|
"abandon enum, cannot grow list\n"
|
|
);
|
|
return bRet;
|
|
}
|
|
|
|
// Break out of the do..while loop.
|
|
//
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Compute the style category for this PFE.
|
|
|
|
ENUMFONTSTYLE efsty = efstyCompute(abFoundStyle, pfeo);
|
|
|
|
// EnumFonts --
|
|
// If style is EFSTYLE_OTHER, this font falls into an already
|
|
// occupied category but it has a facename that allow it to be
|
|
// distinguished from other fonts of this family. So it
|
|
// should be added.
|
|
//
|
|
if ( !bFoundFirst || (efsty == EFSTYLE_OTHER) )
|
|
{
|
|
if (!pefso->bAdd(pfeo.ppfeGet(),efsty))
|
|
{
|
|
// Error return. bAdd() will set error code.
|
|
|
|
WARNING(
|
|
"gdisrv!bScanListsFHOBJ(NULL): "
|
|
"abandon enum, cannot grow list\n");
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// First one has been found. From now on, we will only
|
|
// take EFSTYLE_OTHER fonts.
|
|
//
|
|
bFoundFirst = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
} while ( bEnumNext(&pfeo) );
|
|
}
|
|
}
|
|
|
|
// Success.
|
|
bRet = TRUE;
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* BOOL FHOBJ::bScanLists *
|
|
* *
|
|
* This implements the behavior of EnumFonts() and EnumFontFamilies() when *
|
|
* a non-NULL name is passed in. If the bComputeStyles flag is TRUE, the *
|
|
* EnumFonts() behavior of enumerating some fonts by their facename (rather *
|
|
* than family name) is used. *
|
|
* *
|
|
* This function puts HPFEs from the hash table and lists into the EFSOBJ. *
|
|
* If bComputeStyles is FALSE, the entire font enumeration list is added *
|
|
* to the EFSOBJ. *
|
|
* *
|
|
* If bComputeStyles is TRUE, then each list is scanned and a style *
|
|
* classification (EFSTYLE) is computed. Fonts classified as EFSTYLE_OTHER *
|
|
* are excluded from the EFSOBJ. (These fonts are enumerated by their *
|
|
* facename rather than their family name). *
|
|
* *
|
|
* Return: *
|
|
* Returns FALSE if an error occurs; TRUE otherwise. *
|
|
* *
|
|
* History: *
|
|
* Mon 14-Dec-1992 23:54:37 -by- Charles Whitmer [chuckwh] *
|
|
* Modified hash lookup. *
|
|
* *
|
|
* 07-Aug-1992 -by- Gilman Wong [gilmanw] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL FHOBJ::bScanLists
|
|
(
|
|
EFSOBJ *pefso, // fill this EFSOBJ
|
|
PWSZ pwszName, // search on this name
|
|
ULONG iEnumType, // Enum Fonts, Families or FamiliesEx
|
|
EFFILTER_INFO *peffi // filtering information
|
|
)
|
|
{
|
|
|
|
WCHAR wcCapName[LF_FACESIZE];
|
|
|
|
BOOL bRet = FALSE; // for better code generation
|
|
FLONG flAdd = 0;
|
|
|
|
if (iEnumType == TYPE_ENUMFONTFAMILIESEX)
|
|
flAdd |= FL_ENUMFAMILIESEX;
|
|
|
|
// Capitalize the search name.
|
|
|
|
cCapString(wcCapName,pwszName,LF_FACESIZE);
|
|
|
|
// Search for head of the list.
|
|
|
|
HASHBUCKET *pbkt = pbktSearch(wcCapName,(UINT *) NULL);
|
|
|
|
// If the list exists, need to scan it. Unless this is an equiv. name
|
|
// HASHBUCKET. These are here only to allow the mapper to alias
|
|
// printer font names to other "equivlaent" names. We do not
|
|
// enumerate them.
|
|
|
|
if ((pbkt != (HASHBUCKET *) NULL) && !(pbkt->fl & HB_EQUIV_FAMILY))
|
|
{
|
|
PFEOBJ pfeo(pbkt->ppfeEnumHead);
|
|
|
|
ASSERTGDI (
|
|
pfeo.bValid(),
|
|
"gdisrv!bScanListsFHOBJ(): bad HPFE handle\n"
|
|
);
|
|
|
|
// These flags are set as PFEs for each category are found.
|
|
// Once a category is filled, then all subsequent fonts of the
|
|
// same category are marked as either EFSTYLE_OTHER (if facename
|
|
// is different than family name, thereby allowing us to use it
|
|
// to distinguish from other fonts of this family) or EFSTYLE_SKIP
|
|
// (if facename is the same as the family name).
|
|
//
|
|
// This is to support Win 3.1 EnumFonts() behavior which can only
|
|
// discriminate 4 different styles for each family of fonts.
|
|
|
|
BOOL abFoundStyle[EFSTYLE_MAX];
|
|
RtlZeroMemory((PVOID) abFoundStyle, EFSTYLE_MAX * sizeof(BOOL));
|
|
ENUMFONTSTYLE efsty = EFSTYLE_REGULAR;
|
|
|
|
//
|
|
// Win3.1 App compatibility flag GACF_TTIGNORERASTERDUPE. Need
|
|
// to copy count of TrueType from bucket into EFFILTER_INFO, peffi.
|
|
//
|
|
peffi->cTrueType = pbkt->cTrueType;
|
|
|
|
//
|
|
// Scan the list for candidates.
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Skip this PFE if it needs to be filtered out.
|
|
//
|
|
if ( pfeo.bFilteredOut(peffi) )
|
|
continue;
|
|
|
|
// If servicing an EnumFonts() call (bComputeStyles is TRUE),
|
|
// then some fonts may be excluded. EnumFontFamilies, however,
|
|
// wants the entire list.
|
|
|
|
if (iEnumType == TYPE_ENUMFONTS)
|
|
{
|
|
//
|
|
// Compute the style category for this PFE.
|
|
//
|
|
efsty = efstyCompute(abFoundStyle, pfeo);
|
|
|
|
// EnumFonts --
|
|
// If style is EFSTYLE_OTHER, this font falls into an
|
|
// already occupied category but it has a facename that allows
|
|
// it to be distinguished from other fonts of this family.
|
|
// So it will be excluded from this enumeration. (It will
|
|
// be enumerated by its facename).
|
|
|
|
if ( efsty == EFSTYLE_OTHER )
|
|
continue;
|
|
|
|
}
|
|
|
|
// Add the font to the enumeration.
|
|
|
|
if (!pefso->bAdd(pfeo.ppfeGet(),efsty,flAdd, peffi->lfCharSetFilter))
|
|
{
|
|
// Error return. bAdd() will set error code.
|
|
|
|
WARNING(
|
|
"gdisrv!bScanListsFHOBJ(): "
|
|
"abandon enum, cannot grow list\n");
|
|
return bRet;
|
|
}
|
|
|
|
} while ( bEnumNext(&pfeo) );
|
|
}
|
|
|
|
// Success.
|
|
bRet = TRUE;
|
|
return bRet;
|
|
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* FHMEMOBJ::FHMEMOBJ *
|
|
* *
|
|
* Allocates memory for a font hash table. *
|
|
* *
|
|
* History: *
|
|
* Tue 14-Apr-1992 14:44:35 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
FHMEMOBJ::FHMEMOBJ(FONTHASH **ppfhNew, FONTHASHTYPE fht_, UINT c)
|
|
{
|
|
ppfh = ppfhNew;
|
|
*ppfh = (FONTHASH*)
|
|
PALLOCMEM (offsetof(FONTHASH,apbkt) + sizeof(*(pfh->apbkt)) * c, 'sahG');
|
|
|
|
pfh = *ppfh;
|
|
|
|
if (pfh != (FONTHASH*) NULL)
|
|
{
|
|
vInit(fht_,c);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if DBG
|
|
/******************************Public*Routine******************************\
|
|
* VOID PFTOBJ::vDump ()
|
|
*
|
|
* Debugging code.
|
|
*
|
|
* History:
|
|
* 25-Feb-1991 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID PFTOBJ::vPrint()
|
|
{
|
|
PFF *pPFF, **ppPFF;
|
|
int i;
|
|
|
|
DbgPrint("\nContents of PFT, PPFT = 0x%lx\n", pPFT);
|
|
DbgPrint("pfhFamily = %-#x\n", pPFT->pfhFamily);
|
|
DbgPrint("pfhFace = %-#x\n", pPFT->pfhFace);
|
|
DbgPrint("pfhUFI = %-#x\n", pPFT->pfhUFI);
|
|
DbgPrint("cBuckets = %ld\n", pPFT->cBuckets);
|
|
DbgPrint("cFiles = %ld\n", pPFT->cFiles);
|
|
DbgPrint("PPFF table\n");
|
|
for (
|
|
ppPFF = pPFT->apPFF,i=0
|
|
; ppPFF < pPFT->apPFF + pPFT->cBuckets
|
|
; ppPFF++,i++)
|
|
{
|
|
if (pPFF = *ppPFF)
|
|
{
|
|
DbgPrint("\tPFT->apPFF[%d]\n",i);
|
|
while (pPFF)
|
|
{
|
|
if (!pPFF->hdev)
|
|
{
|
|
DbgPrint("%-#x\t\"%ws\" %u\n"
|
|
, pPFF
|
|
, pPFF->pwszPathname_
|
|
, pPFF->sizeofThis
|
|
);
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("%-#x\t%-#x %u\n"
|
|
, pPFF
|
|
, pPFF->hdev
|
|
, pPFF->sizeofThis
|
|
);
|
|
}
|
|
pPFF = pPFF->pPFFNext;
|
|
}
|
|
}
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
/******************************Member*Function*****************************\
|
|
* FHOBJ::vPrint
|
|
*
|
|
* History:
|
|
* Tue 14-Apr-1992 13:49:51 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID FHOBJ::vPrint(VPRINT print)
|
|
{
|
|
UINT i;
|
|
HASHBUCKET *pbkt;
|
|
|
|
print(" FHOBJ::vPrint()\n\n");
|
|
print(" ppfh = %-#8lx\n",ppfh);
|
|
print(" pfh = %-#8lx\n",pfh);
|
|
print(
|
|
" pfh->id = %c%c%c%c\n",
|
|
((char*) (&pfh->id))[0],
|
|
((char*) (&pfh->id))[1],
|
|
((char*) (&pfh->id))[2],
|
|
((char*) (&pfh->id))[3]
|
|
);
|
|
print(
|
|
" fht = %s\n",
|
|
pfh->fht == FHT_FAMILY ? "FHT_FAMILY" :
|
|
(pfh->fht == FHT_FACE ? "FHT_FACE" :
|
|
(pfh->fht == FHT_UFI ? "FHT_UFI" : "BOGUS VALUE" ))
|
|
);
|
|
print(" cBuckets = %d\n",pfh->cBuckets);
|
|
print(" cUsed = %d\n",pfh->cUsed);
|
|
print(" cCollisions = %d\n",pfh->cCollisions);
|
|
|
|
for (i = 0; i < pfh->cBuckets; i++)
|
|
{
|
|
for
|
|
(
|
|
pbkt = pfh->apbkt[i];
|
|
pbkt != (HASHBUCKET *) NULL;
|
|
pbkt = pbkt->pbktCollision
|
|
)
|
|
{
|
|
print(" ahbkt[%04d] \"%ws\"\n",i,pbkt->u.wcCapName);
|
|
}
|
|
}
|
|
|
|
print(
|
|
"\n\n hpfe %s\n\n",
|
|
pfh->fht ? "FamilyName" : "FaceName"
|
|
);
|
|
|
|
for (i = 0; i < pfh->cBuckets; i++)
|
|
{
|
|
PFE *ppfe;
|
|
BOOL bFirst;
|
|
|
|
for
|
|
(
|
|
pbkt = pfh->apbkt[i];
|
|
pbkt != (HASHBUCKET *) NULL;
|
|
pbkt = pbkt->pbktCollision
|
|
)
|
|
{
|
|
ppfe = pbkt->ppfeEnumHead;
|
|
bFirst = TRUE;
|
|
while (ppfe)
|
|
{
|
|
PFEOBJ pfeo(ppfe);
|
|
|
|
if (bFirst)
|
|
{
|
|
print(" %-#8x \"%ws\"\n",ppfe,pwszName(pfeo));
|
|
bFirst = FALSE;
|
|
}
|
|
else
|
|
{
|
|
print(" %-#8x\n",ppfe);
|
|
}
|
|
ppfe = *pppfeEnumNext(pfeo);
|
|
}
|
|
}
|
|
}
|
|
print("\n\n");
|
|
}
|
|
#endif
|
|
|
|
#define NLS_TABLE_KEY \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Nls\\Language"
|
|
|
|
USHORT GetLanguageID()
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routines returns the default language ID. Normally, we would call
|
|
GetLocaleInfoW to get this information but that API is not available in
|
|
kernel mode. Since GetLocaleInfoW gets it from the registry we'll do the
|
|
same.
|
|
|
|
Return Value:
|
|
|
|
The default language ID. If the call fails it will just return 409
|
|
for English.
|
|
|
|
Gerrit van Wingerden [gerritv] 2/6/96
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
USHORT Result = 0x409;
|
|
HANDLE RegistryKeyHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, NLS_TABLE_KEY);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
NtStatus = ZwOpenKey(&RegistryKeyHandle, GENERIC_READ, &ObjectAttributes);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
|
|
ULONG BufferSize = sizeof(WCHAR) * MAX_PATH +
|
|
sizeof(KEY_VALUE_FULL_INFORMATION);
|
|
|
|
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) PALLOCMEM(BufferSize,'dilG');
|
|
|
|
if(KeyValueInformation)
|
|
{
|
|
ULONG ValueReturnedLength;
|
|
|
|
RtlInitUnicodeString(&UnicodeString,L"Default");
|
|
|
|
NtStatus = ZwQueryValueKey(RegistryKeyHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
BufferSize,
|
|
&BufferSize);
|
|
|
|
if(NT_SUCCESS(NtStatus))
|
|
{
|
|
ULONG Temp;
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
(USHORT*) &(KeyValueInformation->Data[0]));
|
|
RtlUnicodeStringToInteger(&UnicodeString, 16, &Temp);
|
|
Result = (USHORT) Temp;
|
|
}
|
|
else
|
|
{
|
|
WARNING("GetLanguageID failed to read registry\n");
|
|
}
|
|
VFREEMEM(KeyValueInformation);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GetLanguageID out of memory\n");
|
|
}
|
|
|
|
ZwClose(RegistryKeyHandle);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GetLanguageID failed to open NLS key\n");
|
|
}
|
|
|
|
return(Result);
|
|
}
|
|
|
|
#ifdef FE_SB
|
|
BOOL PFTOBJ::bUnloadEUDCFont(PWSZ pwszPathname)
|
|
{
|
|
PFF *pPFF, **ppPFF;
|
|
WCHAR szUcPathName[MAX_PATH + 1];
|
|
BOOL bRet = FALSE;
|
|
|
|
cCapString(szUcPathName,
|
|
pwszPathname,
|
|
wcslen(pwszPathname)+1);
|
|
|
|
|
|
PUBLIC_PFTOBJ pfto; // access the public font table
|
|
VACQUIRESEM(gpsemPublicPFT); // This is a very high granularity
|
|
// and will prevent text output
|
|
|
|
|
|
pPFF = pfto.pPFFGet(szUcPathName, wcslen(szUcPathName) + 1, 1, &ppPFF,TRUE);
|
|
|
|
if (pPFF)
|
|
{
|
|
// bUnloadWorkhorse() guarantees that the public font table
|
|
// semaphore will be released before it returns
|
|
|
|
bRet = pfto.bUnloadWorkhorse(pPFF, ppPFF, gpsemPublicPFT);
|
|
}
|
|
else
|
|
{
|
|
VRELEASESEM(gpsemDriverMgmt);
|
|
}
|
|
|
|
return( bRet );
|
|
}
|
|
#endif
|