|
|
/**************************************************************************\
* * Copyright (c) 1999 Microsoft Corporation * * Abstract: * * Font table operations * * Revision History: * * 23/06/1999 cameronb * Created it. * \**************************************************************************/
#include "precomp.hpp"
/**************************************************************************\
Windows 9x compatibility:
const WCHAR* strW;
if (Globals::IsNT) { FunctionW(strW); } else { AnsiStrFromUnicode strA(strW); FunctionA(strA); }
\**************************************************************************/
/**************************************************************************\
* * Function Description: * * Constructs a GpFontTable object * * Arguments: * * none * * Returns: * * nothing * * History: * * 23/06/1999 cameronb * Created it. * \**************************************************************************/
GpFontTable::GpFontTable() : NumFilesLoaded(0), NumHashEntries(61), Table(NULL), EnumList(NULL) { Table = new GpFontFile *[NumHashEntries];
if (Table != NULL) { GpMemset(Table, 0, sizeof(GpFontFile *) * NumHashEntries);
EnumList = new GpFontFamilyList(); }
bPrivate = FALSE; bFontFilesLoaded = FALSE; }
/**************************************************************************\
* * Function Description: * * Destroys a GpFontTable object * * Arguments: * * none * * Returns: * * nothing * * History: * * 23/06/1999 cameronb * Created it. * \**************************************************************************/
GpFontTable::~GpFontTable() { if (EnumList) { delete EnumList; }
if (Table) { for (UINT h = 0; h < NumHashEntries; h++) { if (Table[h] != NULL) { UnloadFontFiles(Table[h]); } }
delete [] Table; } }
BOOL GpFontTable::UnloadFontFiles(GpFontFile* fontFile) { if (fontFile->GetNext() != NULL) { UnloadFontFiles(fontFile->GetNext()); }
CacheFaceRealization *prface = fontFile->prfaceList;
while(prface) { GpFaceRealizationTMP rface(prface);
// specially for the case of font added and removed from a private font collection, we need to remove it from the
// last recently used list
Globals::FontCacheLastRecentlyUsedList->RemoveFace(prface);
prface = (prface->NextCacheFaceRealization == fontFile->prfaceList) ? NULL : prface->NextCacheFaceRealization;
rface.DeleteRealizedFace(); }
ttfdSemUnloadFontFile(fontFile->hff);
// Free objects allocated by text support
for (UINT i=0; i<fontFile->GetNumEntries(); i++) { fontFile->GetFontFace(i)->FreeImagerTables(); }
if (fontFile->pfv != NULL) { if (fontFile->pfv->pwszPath == NULL) // memory image
GpFree(fontFile->pfv->pvView);
GpFree(fontFile->pfv); }
GpFree(fontFile);
return TRUE; }
/**************************************************************************\
* * Function Description: * * Load all the fonts from cache or the registry to the font table * * * History: * * 11/12/1999 yungt created it. * \**************************************************************************/
void GpFontTable::LoadAllFonts(const WCHAR *familyName) { InitFontFileCache(); if (GetFontFileCacheState() & FONT_CACHE_LOOKUP_MODE) { // Do the fast way to load all the fonts, we will be no need to touch any registry
// and font file.
LoadAllFontsFromCache(FontFileCacheReadRegistry()); } else { // We do need to load the fonts from registry also we need to
if (GetFontFileCacheState() & FONT_CACHE_CREATE_MODE) { LoadAllFontsFromRegistry(TRUE); } else { LoadAllFontsFromRegistry(FALSE); } } vCloseFontFileCache(); }
/**************************************************************************\
* * Function Description: * * Adds a font from the font table * * Arguments: * * str: name of font to be added * * Returns: * * GpFontFile *: It will not be NULL if succeeded * * History: * * 28/06/YungT cameronb * Created it. * \**************************************************************************/
GpFontFile * GpFontTable::AddFontFile(WCHAR* fileName) { // This rountine is called from GpFontFamily which we have load the family from cache
// We need to load the font file now if it is being used.
GpFontFile* fontFile = NULL; UINT hash = HashIt(fileName); { fontFile = GetFontFile(fileName, hash); if (fontFile != NULL) { // font exists in the table
fontFile->cLoaded++; } else { if ((fontFile = LoadFontFile(fileName)) == NULL) { return NULL; } // Add to the head of the appropriate hash list (hash bucket)
fontFile->SetPrev(NULL); fontFile->SetNext(Table[hash]); if (Table[hash] != NULL) Table[hash]->SetPrev(fontFile); Table[hash] = fontFile; // loop over pfe's, init the data:
GpFontFace * face = (GpFontFace *)fontFile->aulData;
for (ULONG iFont = 0; iFont < fontFile->cFonts; iFont++) { face[iFont].SetPrivate(bPrivate); }
// Add to the emuneration list
NumFilesLoaded++; } } return fontFile; }
/**************************************************************************\
* * Function Description: * * Adds a font from the font table * * Arguments: * * str: name of font to be added * * Returns: * * BOOL: indicating success * * History: * * 23/06/1999 cameronb * Created it. * \**************************************************************************/
GpStatus GpFontTable::AddFontFile(const WCHAR* fileName, GpFontCollection *fontCollection) { WCHAR awcPath[MAX_PATH];
GpStatus status = Ok; if (!MakePathName(awcPath, const_cast<WCHAR *>(fileName))) return FileNotFound;
// Determine whether font is already in the table
UnicodeStringToUpper (awcPath, awcPath); UINT hash = HashIt(awcPath); { GpFontFile* fontFile = GetFontFile(awcPath, hash); if (fontFile != NULL) { // font exists in the table
fontFile->cLoaded++; } else { if ((fontFile = LoadFontFile(awcPath)) == NULL) { return FileNotFound; } // Add to the head of the appropriate hash list (hash bucket)
fontFile->SetPrev(NULL); fontFile->SetNext(Table[hash]); if (Table[hash] != NULL) Table[hash]->SetPrev(fontFile); Table[hash] = fontFile; // loop over pfe's, init the data:
GpFontFace * face = (GpFontFace *)fontFile->aulData;
for (ULONG iFont = 0; iFont < fontFile->cFonts; iFont++) { face[iFont].SetPrivate(bPrivate); }
// Add to the emuneration list
if (!EnumList->AddFont(fontFile, fontCollection)) return OutOfMemory; NumFilesLoaded++; } } return Ok; }
/************************************************************\
* * Function Description: * * Adds a font from the memory image * * * History: * * Nov/09/1999 Xudong Wu [tessiew] * Created it. * \************************************************************/ ULONG GpFontTable::MemImageUnique = 0;
GpStatus GpFontTable::AddFontMemImage( const BYTE* fontMemoryImage, INT fontImageSize, GpFontCollection *fontCollection ) { WCHAR awcPath[MAX_PATH]; UINT hash; GpFontFile *fontFile;
// generate a "MEMORY xxx" style file name
wsprintfW(awcPath, L"MEMORY-%u", GetNewMemImageUniqueness(GpFontTable::MemImageUnique));
UnicodeStringToUpper (awcPath, awcPath); hash = HashIt(awcPath); fontFile = LoadFontMemImage(awcPath, const_cast<BYTE *>(fontMemoryImage), fontImageSize); if (fontFile == NULL) // unable to load font
{ return FileNotFound; } // Add to the head of the appropriate hash list (hash bucket)
fontFile->SetNext(Table[hash]); if (Table[hash] != NULL) Table[hash]->SetPrev(fontFile); Table[hash] = fontFile;
// Add to the emuneration list
if (!EnumList->AddFont(fontFile, fontCollection)) return OutOfMemory; NumFilesLoaded++; return Ok; }
/**************************************************************************\
* * Function Description: * * Searched the font table for the any font * * Arguments: * * * Returns: * * GpFontFamily *: pointer to font file if found, else NULL * * History: * * 7/15/2000 YungT * Created it. * \**************************************************************************/
GpFontFamily* GpFontTable::GetAnyFamily() { return EnumList->GetAnyFamily(); }
/**************************************************************************\
* * Function Description: * * Searched the font table for the specified font * * Arguments: * * fileName: name of font to be removed * hash: its hash value * * Returns: * * GpFontFile*: pointer to font file if found, else NULL * * History: * * 23/06/1999 cameronb * Created it. * \**************************************************************************/
GpFontFamily* GpFontTable::GetFontFamily(const WCHAR* familyName) { return EnumList->GetFamily(familyName); }
/**************************************************************************\
* * Function Description: * * Removes a font from the font table. * * Note: If the ref count of any of the PFEs in the font file is greater * than zero, then we do not delete the font file entry in the font table. * However, the bRemoved flag is set in this function. So, in the case when * a ref count decrement could cause a font file to be removed, the caller * should first test bRemoved before calling this function. * * History: * * Nov/28/1999 Xudong Wu [tessiew] * Created it. * \**************************************************************************/
GpStatus GpFontTable::RemoveFontFile(const WCHAR* fontFileName) { WCHAR awcPath[MAX_PATH]; GpFontFile *fontFile = NULL;
if (!MakePathName(awcPath, const_cast<WCHAR *>(fontFileName))) return GenericError;
UnicodeStringToUpper (awcPath, awcPath); UINT hash = HashIt(awcPath);
GpFontFile *ff = Table[hash];
while(ff && !fontFile) { if ( UnicodeStringCompare(awcPath, ff->pwszPathname_) == 0 ) { fontFile = ff; } ff = ff->GetNext(); }
if (fontFile) { fontFile->bRemoved = TRUE;
if (fontFile->cLoaded) { fontFile->cLoaded--; }
// see if any of the PFEs have a ref count on them
BOOL bFontFamilyRef = TRUE; for (UINT iFont = 0; iFont < fontFile->cFonts; iFont++) { GpFontFace *pfe = &(((GpFontFace *) &(fontFile->aulData))[iFont]); if (pfe->cGpFontFamilyRef > 0) { bFontFamilyRef = FALSE; } } // ASSERT: if there are no references by any FontFamily to
// any of the PFEs in this object (via GpFontFamily objects),
// then bFontFamilyRef is TRUE. bFontFamilyRef is FALSE otherwise.
if (fontFile->cLoaded == 0 && bFontFamilyRef && fontFile->prfaceList == NULL) { // set the Face pointers of the corresponding FontFamily objects
// to NULL and attempt to remove each font family in the file
for (UINT iFont = 0; iFont < fontFile->cFonts; iFont++) { GpFontFamily *gpFontFamily = GetFontFamily(fontFile->GetFamilyName(iFont)); if (gpFontFamily) { for (UINT iFace = 0; iFace < NumFontFaces; iFace++) { if (gpFontFamily->GetFaceAbsolute(iFace) == (&(((GpFontFace *) (&(fontFile->aulData))) [iFont]))) { gpFontFamily->SetFaceAndFile(iFace, NULL, NULL); } } EnumList->RemoveFontFamily(gpFontFamily); } }
// remove GpFontFile from the FontTable
NumFilesLoaded--;
if (fontFile->GetPrev()) fontFile->GetPrev()->SetNext(fontFile->GetNext()); if (fontFile->GetNext()) fontFile->GetNext()->SetPrev(fontFile->GetPrev()); if (fontFile == Table[hash]) Table[hash] = fontFile->GetNext(); ttfdSemUnloadFontFile(fontFile->hff);
// Free objects allocated by text support
for (ULONG i=0; i<fontFile->GetNumEntries(); i++) { fontFile->GetFontFace(i)->FreeImagerTables(); }
if (fontFile->pfv != NULL) { if (fontFile->pfv->pwszPath == NULL) // memory image
GpFree(fontFile->pfv->pvView);
GpFree(fontFile->pfv); } GpFree(fontFile);
return Ok; } } else { // couldn't find the font file in the hash table
return GenericError; } return Ok; }
/**************************************************************************\
* * Function Description: * * Counts the number of enumerable fonts in the table * * Arguments: * * * * Returns: * * Number of enumerable fonts * * History: * * 12/07/1999 cameronb * Created it. * \**************************************************************************/
INT GpFontTable::EnumerableFonts(GpGraphics* graphics) { return EnumList->Enumerable(graphics); }
/**************************************************************************\
* * Function Description: * * Enumerates fonts. * * First call EnumerableFonts() to determine the number to expect. * * Arguments: * * * * Returns: * * Status of the enumeration operation * * History: * * 12/07/1999 cameronb * Created it. * \**************************************************************************/
GpStatus GpFontTable::EnumerateFonts( INT numSought, GpFontFamily* gpfamilies[], INT& numFound, GpGraphics* graphics ) { GpStatus status = EnumList->Enumerate(numSought, gpfamilies, numFound, graphics);
#if FONTTABLE_DBG
TERSE(("Enumerated font list:")); EnumList->Dump(); TERSE(("Done.")); #endif
return status; }
/**************************************************************************\
* * Function Description: * * Returns a pseudorandom hash value for a given string * * Arguments: * * str: string to be hashed * * Returns: * * UINT: hash value for str * * Note: All strings must be capitalized! * * * * History: * * 23/06/1999 cameronb * Created it. * 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 GpFontTable::HashIt(const WCHAR* str) const { UINT result = 0;
//ASSERT(NumHashEntries != 0);
while (*str) { // use the lower byte since that is where most of the
// interesting stuff happens
//result += 256 * result + (UCHAR)towupper(*str++);
result += 256 * result + (UCHAR)*str++; }
return result % NumHashEntries; }
GpFontFile* GpFontTable::GetFontFile(const WCHAR* fileName) const { WCHAR fileNameCopy[MAX_PATH]; UnicodeStringToUpper (fileNameCopy, const_cast<WCHAR *>(fileName)); UINT hash = HashIt(fileNameCopy); return GetFontFile(fileNameCopy, hash); }
GpFontFile* GpFontTable::GetFontFile(const WCHAR* fileName, UINT hash) const { for (GpFontFile* ff = Table[hash]; ff != NULL; ff = ff->GetNext()) if (UnicodeStringCompareCI(fileName, ff->GetPathName()) == 0) { return ff; }
return NULL; }
/**************************************************************************\
* * Function Description: * * Adds fonts from the cache file to the font table * * Arguments: * * Returns: * * nothing * * History: * * 6/21/2000 YungT * Created it. * \**************************************************************************/
void GpFontTable::LoadAllFontsFromCache(BOOL bLoadFromRegistry) { if (!EnumList->BuildFamilyListFromCache(bLoadFromRegistry)) { LoadAllFontsFromRegistry(FALSE); } else { bFontFilesLoaded = TRUE; }
return ; }
/**************************************************************************\
* * Function Description: * * Adds fonts from the registry to the font table * * Arguments: * * numExpected: number of fonts expected in the registry. This includes * *.FON files which the TT font driver will not load. * * Returns: * * nothing * * History: * * 23/06/1999 cameronb * Created it. * \**************************************************************************/
void GpFontTable::LoadAllFontsFromRegistry(BOOL bUpdateCache) { ULONG numExpected; // Open the key
HKEY hkey;
LONG error = (Globals::IsNt) ? RegOpenKeyExW(HKEY_LOCAL_MACHINE, Globals::FontsKeyW, 0, KEY_QUERY_VALUE, &hkey) : RegOpenKeyExA(HKEY_LOCAL_MACHINE, Globals::FontsKeyA, 0, KEY_QUERY_VALUE, &hkey);
if (error == ERROR_SUCCESS) { // Must read from the registry in Ascii format for some unfathomable reason
CHAR label[MAX_PATH]; BYTE data[MAX_PATH]; WCHAR labelW[MAX_PATH]; WCHAR fileNameW[MAX_PATH];
// Loop through fonts in registry
// Note:
// Don't make (error != ERROR_NO_MORE_ITEMS) the sole
// terminating condition for this loop. The last entry
// may produce a different type of error.
ULONG index = 0; ULONG registrySize = 0;
error = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &numExpected, NULL, NULL, NULL, NULL);
if (error != ERROR_SUCCESS) { numExpected = NumHashEntries << 3; error = ERROR_SUCCESS; }
/* we need to add the font Marlett separately since it's hidden and not listed in the registry */ if (AddFontFile(L"Marlett.ttf", NULL) != Ok) { VERBOSE(("Error loading font Marlett.ttf.\n")) }
while (index < numExpected && error != ERROR_NO_MORE_ITEMS) { DWORD regType = 0; DWORD labelSize = MAX_PATH; DWORD dataSize = MAX_PATH; DWORD dataSizeW = MAX_PATH * sizeof(WCHAR);
if (Globals::IsNt) error = RegEnumValueW(hkey, index, labelW, &labelSize, NULL, ®Type, (PBYTE) fileNameW, &dataSizeW ); else error = RegEnumValueA(hkey, index, label, &labelSize, NULL, ®Type, data, &dataSize);
if (error == ERROR_NO_MORE_ITEMS) break; else if (error != ERROR_SUCCESS) { index ++; //ASSERT
VERBOSE(("Bad RegEnumValueA %d for %s.", error, data)) continue; }
if (!Globals::IsNt) { memset(fileNameW, 0, MAX_PATH * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, (CHAR*)data, -1, fileNameW, MAX_PATH);
registrySize += dataSize; }
if (AddFontFile(fileNameW, NULL) != Ok) { VERBOSE(("Error loading font %ws.\n", fileNameW)) } index ++; }
if (NumFilesLoaded) { // loaded all the fonts from reg
if (bUpdateCache) EnumList->UpdateFamilyListToCache(FontFileCacheReadRegistry(), hkey, registrySize, numExpected);
bFontFilesLoaded = TRUE; }
RegCloseKey(hkey); } }
|