/**************************************************************************\ * * Copyright (c) 1999 Microsoft Corporation * * Abstract: * * Implementation of GpFontFamily and GpFontFamilyList * * Revision History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ #include "precomp.hpp" #if DBG #include #endif #define QWORD_ALIGN(x) (((x) + 7L) & ~7L) #define SWAP_LANGID(pj) \ ( \ ((USHORT)(((PBYTE)(pj))[0]) << 8) | \ (USHORT)(((PBYTE)(pj))[1]) \ ) // VOID CopyFamilyName(WCHAR * dest, const WCHAR * src, BOOL bCap) { GpMemset(dest, 0, FamilyNameMax * sizeof(WCHAR)); if (src != NULL) { for (int c = 0; src[c] && c < FamilyNameMax - 1; c++) dest[c] = src[c]; } if (bCap) UnicodeStringToUpper(dest, dest); } ////////////////////////////////////////////////////////////////////////////// GpFontFamily::GpFontFamily(const WCHAR *name, GpFontFile * fontfile, INT index, FAMILYCACHEENTRY * pCacheEntry, GpFontCollection *fontCollection) { SetValid(TRUE); // set initial valid state to TRUE (valid) // InitializeCriticalSection(&FontFamilyCritSection); cacheEntry = pCacheEntry; CopyFamilyName(cacheEntry->Name, name, TRUE); for (INT ff = 0; ff < NumFontFaces; ff++) { Face[ff] = NULL; FontFile[ff] = NULL; cacheEntry->cFilePathName[ff] = 0; cacheEntry->LastWriteTime[ff].LowPart = 0; cacheEntry->LastWriteTime[ff].HighPart = 0; } cFontFamilyRef = 0; cacheEntry->iFont = index; // Get font entry for the font file GpFontFace * fontface = fontfile->GetFontFace(cacheEntry->iFont); // Get LandID for Family Name cacheEntry->LangID = SWAP_LANGID((LANGID *) &fontface->pifi->familyNameLangID); cacheEntry->AliasLnagID = SWAP_LANGID((LANGID *) &fontface->pifi->familyAliasNameLangID); // Process Alias name cacheEntry->bAlias = fontface->IsAliasName(); if (cacheEntry->bAlias) { CopyFamilyName(cacheEntry->FamilyAliasName, fontface->GetAliasName(), TRUE); CopyFamilyName(cacheEntry->NormalFamilyAliasName, fontface->GetAliasName(), FALSE); } CopyFamilyName(cacheEntry->NormalName, fontfile->GetFamilyName(cacheEntry->iFont), FALSE); // Determine face type(s) of font FontStyle style = FontStyleRegular; // ... // SetFont(face, font); cacheEntry->lfCharset = DEFAULT_CHARSET; if (fontCollection == NULL) { associatedFontCollection = GpInstalledFontCollection::GetGpInstalledFontCollection(); } else { associatedFontCollection = fontCollection; } FamilyFallbackInitialized = FALSE; bLoadFromCache = FALSE; bFontFileLoaded = TRUE; } GpFontFamily::GpFontFamily(FAMILYCACHEENTRY * pCacheEntry) { SetValid(TRUE); // set initial valid state to TRUE (valid) // InitializeCriticalSection(&FontFamilyCritSection); cacheEntry = pCacheEntry; for (INT ff = 0; ff < NumFontFaces; ff++) { Face[ff] = NULL; FontFile[ff] = NULL; } cFontFamilyRef = 0; // It will be from Cache entry. bFontFileLoaded = FALSE; // Determine face type(s) of font FontStyle style = FontStyleRegular; associatedFontCollection = GpInstalledFontCollection::GetGpInstalledFontCollection(); FamilyFallbackInitialized = FALSE; bLoadFromCache = TRUE; } GpFontFamily::~GpFontFamily() { if (FamilyFallbackInitialized) { FamilyFallbackInitialized = FALSE; fallback.Destroy(); } ReleaseCacheEntry(); // DeleteCriticalSection(&FontFamilyCritSection); SetValid(FALSE); // so we don't use a deleted object } BOOL GpFontFamily::IsPrivate() const { return associatedFontCollection != GpInstalledFontCollection::GetGpInstalledFontCollection(); } void GpFontFamily::SetFaceAndFile(INT style, GpFontFace *face, GpFontFile * fontfile) { // EnterCriticalSection(&FontFamilyCritSection); Face[style & 3] = face; FontFile[style & 3] = fontfile; cacheEntry->LastWriteTime[style & 3].QuadPart = (fontfile->GetFileView())->LastWriteTime.QuadPart; // LeaveCriticalSection(&FontFamilyCritSection); } GpStatus GpFontFamily::GetFamilyName(WCHAR name[LF_FACESIZE], LANGID language) const { ASSERT(FamilyNameMax == LF_FACESIZE); if (cacheEntry->bAlias && language == cacheEntry->AliasLnagID) { CopyFamilyName(name, cacheEntry->NormalFamilyAliasName, FALSE); } else { CopyFamilyName(name, cacheEntry->NormalName, FALSE); } return Ok; } BOOL GpFontFamily::IsFileLoaded(BOOL loadFontFile) const { // If file is not loaed yet then load it. if (!bFontFileLoaded) { if (loadFontFile) { if (bLoadFromCache) { GpFontTable *fontTable; GpFontFile * fontFile; WCHAR * fontfilepath; fontTable = (GpInstalledFontCollection::GetGpInstalledFontCollection())->GetFontTable(); fontfilepath = (WCHAR *) ((BYTE *) cacheEntry + QWORD_ALIGN(sizeof(FAMILYCACHEENTRY))); for (UINT i = 0; i < NumFontFaces; i++) { if (cacheEntry->cFilePathName[i]) { fontFile = fontTable->AddFontFile(fontfilepath); if (!fontFile) { return FALSE; } else { GpFontFace* face = fontFile->GetFontFace(cacheEntry->iFont); FontStyle style = face->GetFaceStyle(); Face[style & 3] = face; face->cGpFontFamilyRef = cFontFamilyRef; FontFile[style & 3] = fontFile; cacheEntry->LastWriteTime[style & 3].QuadPart = (fontFile->GetFileView())->LastWriteTime.QuadPart; } fontfilepath = (WCHAR *) ((BYTE *) fontfilepath + cacheEntry->cFilePathName[i]); } } bFontFileLoaded = TRUE; } else { ASSERT(!bLoadFromCache); } } else { return FALSE; } } return bFontFileLoaded; } GpFontFace *GpFontFamily::GetFace(INT style) const { // Return face for the given style - either the direct face // or one which can support this style through simulation. GpFontFace *fontFace = NULL; // EnterCriticalSection(&FontFamilyCritSection); if (IsFileLoaded()) { if (Face[style&3]) { // Distinct font exists fontFace = Face[style&3]; } else { // Will need simulation switch (style & 3) { case FontStyleBold: case FontStyleItalic: fontFace = Face[0]; break; case FontStyleBold|FontStyleItalic: if (Face[FontStyleBold]) { fontFace = Face[FontStyleBold]; } else if (Face[FontStyleItalic]) { fontFace = Face[FontStyleItalic]; } else { fontFace = Face[0]; } break; default: case 0: ; } } } // LeaveCriticalSection(&FontFamilyCritSection); return fontFace; } GpFontFace *GpFontFamily::GetFaceAbsolute(INT style) const { // Return face for the given style, where the style is one of // the four basic types. If it does not exist, return NULL. GpFontFace *fontFace = NULL; // EnterCriticalSection(&FontFamilyCritSection); if (IsFileLoaded()) fontFace = Face[style & 3]; // LeaveCriticalSection(&FontFamilyCritSection); return (fontFace); } UINT16 GpFontFamily::GetDesignEmHeight (INT style) const { UINT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignEmHeight() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } UINT16 GpFontFamily::GetDesignCellAscent (INT style) const { UINT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignCellAscent() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } UINT16 GpFontFamily::GetDesignCellDescent (INT style) const { UINT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignCellDescent() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } UINT16 GpFontFamily::GetDesignLineSpacing (INT style) const { UINT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignLineSpacing() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } UINT16 GpFontFamily::GetDesignUnderscoreSize (INT style) const { UINT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignUnderscoreSize() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } INT16 GpFontFamily::GetDesignUnderscorePosition (INT style) const { INT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignUnderscorePosition() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } UINT16 GpFontFamily::GetDesignStrikeoutSize (INT style) const { UINT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignStrikeoutSize() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } INT16 GpFontFamily::GetDesignStrikeoutPosition (INT style) const { INT16 result; GpFontFace *fontface; // EnterCriticalSection(&FontFamilyCritSection); fontface = GetFace(style); result = ((fontface != NULL) ? fontface->GetDesignStrikeoutPosition() : 0); // LeaveCriticalSection(&FontFamilyCritSection); return result; } /**************************************************************************\ * * Function Description: * * Determines available (non-NULL) faces for this family * * Arguments: * * None * * Returns: * * Bitset of available face flags * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ INT GpFontFamily::AvailableFaces(void) const { INT faces = 0; if (bFontFileLoaded) { for (int ff = 0; ff < NumFontFaces; ff++) { if (Face[ff] != NULL) { // Map index to FontFace flag faces |= (0x01 << ff); } } } else { // At least one face exists. faces = 1; } return faces; } /**************************************************************************\ * * Function Description: * * Determines whether the specified face supports a given string * * Arguments: * * style: font face to test for support * lang: language id * * Returns: * * Boolean result * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ BOOL GpFontFamily::SupportsLanguage(INT style, LANGID lang) const { BOOL result = TRUE; // ... return result; } /**************************************************************************\ * * Function Description: * * Determines whether the specified face supports a given string * * Arguments: * * style: font face to test for support * str: target string * len: string length * * Returns: * * Boolean result * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ BOOL GpFontFamily::SupportsCharacters(INT style, WCHAR* str, INT len) const { BOOL result = TRUE; // ... return result; } /**************************************************************************\ * * Function Description: * * Internal, access the tables from the font, return a pointer * * Arguments: * * style: font style * tag: 4 bytes tag for the table, a null tag means return the whole file * * Returns: * * table size and pointer to the table * * History: * * 09/10/1999 caudebe * Created it. * \**************************************************************************/ GpStatus GpFontFamily::GetFontData(FontStyle style, UINT32 tag, INT* tableSize, BYTE** pjTable) { GpFontFace *face; GpStatus status; // EnterCriticalSection(&FontFamilyCritSection); face = GetFace(style); if (face == NULL) { return GenericError; } status = face->GetFontData (tag, tableSize, pjTable); // LeaveCriticalSection(&FontFamilyCritSection); return status; } void GpFontFamily::ReleaseFontData(FontStyle style) { GpFontFace *face; // EnterCriticalSection(&FontFamilyCritSection); face = GetFace(style); if (face != NULL) { face->ReleaseFontData(); } // LeaveCriticalSection(&FontFamilyCritSection); } /**************************************************************************\ * * Function Description: * * Determines whether a font family is deletable. Returns TRUE * if its ref count is 0 and all of its Face pointers are NULL. * * Arguments: * none * * Returns: * * Boolean result * * History: * * 2/21/2000 dchinn * Created it. * \**************************************************************************/ /**************************************************************************\ * * Function Description: * * Returns TRUE exactly when all faces of the font family have had * RemoveFontFile() called on their corresponding font files. * * Arguments: * none * * Returns: * boolean * * History: * * 03/08/2000 dchinn * Created it. * \**************************************************************************/ BOOL GpFontFamily::AreAllFacesRemoved() { /* no need for critical section, called only internally */ if (!bFontFileLoaded) { ASSERT (bLoadFromCache); return FALSE; } else { for (UINT iFace = 0; iFace < NumFontFaces; iFace++) { if (Face[iFace] != NULL) { ASSERT (Face[iFace]->pff); if (!Face[iFace]->pff->bRemoved) { // if the GpFontFile corresponding to the GpFontFace // has not been removed, then the face is still "active" // and so the font family is still "active". return FALSE; } } } } return TRUE; } BOOL GpFontFamily::Deletable() { BOOL bAllFacesNull = TRUE; if (cFontFamilyRef != 0) { return FALSE; } for (UINT iFace = 0; iFace < NumFontFaces; iFace++) { if (Face[iFace] != NULL) { bAllFacesNull= FALSE; } } return bAllFacesNull; } /**************************************************************************\ * * Function Description: * * Increments/decrements the reference count for the fontFamily and each GpFontFace (PFE) * pointed to by the Face pointers of the GpFontFamily object. * * Arguments: * none * * Returns: * nothing * * History: * * 2/21/2000 dchinn * Created it. * \**************************************************************************/ BOOL GpFontFamily::IncFontFamilyRef() { // EnterCriticalSection(&FontFamilyCritSection); if (AreAllFacesRemoved()) { // LeaveCriticalSection(&FontFamilyCritSection); return FALSE; } else { cFontFamilyRef++; if (bFontFileLoaded) { for (UINT iFace = 0; iFace < NumFontFaces; iFace++) { if (Face[iFace]) { Face[iFace]->IncGpFontFamilyRef(); } } } // LeaveCriticalSection(&FontFamilyCritSection); return TRUE; } } void GpFontFamily::DecFontFamilyRef() { // EnterCriticalSection(&FontFamilyCritSection); cFontFamilyRef--; if (bFontFileLoaded) { for (UINT iFace = 0; iFace < NumFontFaces; iFace++) { if (Face[iFace]) { Face[iFace]->DecGpFontFamilyRef(); } } } // LeaveCriticalSection(&FontFamilyCritSection); } GpStatus GpFontFamily::CreateFontFamilyFromName( const WCHAR *name, GpFontCollection *fontCollection, GpFontFamily **fontFamily) { GpFontTable *fontTable; GpFontCollection *gpFontCollection; if (!name || !fontFamily) { return InvalidParameter; } GpStatus status = Ok; // ASSERT: if fontCollection is NULL, then the caller wants to // act on the GpInstalledFontCollection object. Otherwise, the // caller has passed in a GpPrivateFontCollection. if (fontCollection == NULL) { gpFontCollection = GpInstalledFontCollection::GetGpInstalledFontCollection(); } else { gpFontCollection = fontCollection; } if (gpFontCollection == NULL) return WrongState; fontTable = gpFontCollection->GetFontTable(); if (!fontTable->IsValid()) return OutOfMemory; if (!fontTable->IsPrivate() && !fontTable->IsFontLoaded()) fontTable->LoadAllFonts(); *fontFamily = fontTable->GetFontFamily(name); if (*fontFamily == NULL) { GetFamilySubstitution(name, fontFamily); } if (!*fontFamily) status = FontFamilyNotFound; // NOTE: We assume here that GdipCreateFontFamilyFromName gets // called externally (e.g., the FontFamily constructor). if (*fontFamily && (!(*fontFamily)->IncFontFamilyRef())) { // all the faces of the found fontFamily have been removed. // we do not want to return the fontFamily. *fontFamily = NULL; status = FontFamilyNotFound; } return status; } GpStatus GpFontFamily::GetGenericFontFamilySansSerif( GpFontFamily **nativeFamily) { GpStatus status; if (!nativeFamily) { return InvalidParameter; } // return FontFamily::GetGenericSansSerif(nativeFamily); status = CreateFontFamilyFromName(L"Microsoft Sans Serif", NULL, nativeFamily); if (status == FontFamilyNotFound) { // Not found Arial in system so we got to find another font status = CreateFontFamilyFromName(L"Arial", NULL, nativeFamily); if (status == FontFamilyNotFound) status = CreateFontFamilyFromName(L"Tahoma", NULL, nativeFamily); // We are in the worst case so trying to find any font we can. if (status == FontFamilyNotFound) { GpFontTable *fontTable; GpFontCollection *gpFontCollection; gpFontCollection = GpInstalledFontCollection::GetGpInstalledFontCollection(); fontTable = gpFontCollection->GetFontTable(); if (!fontTable->IsValid()) return OutOfMemory; *nativeFamily = fontTable->GetAnyFamily(); if (!*nativeFamily) status = FontFamilyNotFound; else status = Ok; } } return status; } GpStatus GpFontFamily::GetGenericFontFamilySerif( GpFontFamily **nativeFamily) { GpStatus status; if (!nativeFamily) { return InvalidParameter; } // return FontFamily::GetGenericSerif(nativeFamily); status = CreateFontFamilyFromName(L"Times New Roman", NULL, nativeFamily); // Get the font family from SansSerif if (status == FontFamilyNotFound) status = GetGenericFontFamilySansSerif(nativeFamily); return status; } GpStatus GpFontFamily::GetGenericFontFamilyMonospace( GpFontFamily **nativeFamily) { GpStatus status; if (!nativeFamily) { return InvalidParameter; } // return FontFamily::GetGenericMonospace(nativeFamily); status = CreateFontFamilyFromName(L"Courier New", NULL, nativeFamily); if (status == FontFamilyNotFound) status = CreateFontFamilyFromName(L"Lucida Console", NULL, nativeFamily); // We are in the worst case so trying to find any font we can. if (status == FontFamilyNotFound) status = GetGenericFontFamilySansSerif(nativeFamily); return status; } ////////////////////////////////////////////////////////////////////////////// // GpFontFamilyList GpFontFamilyList::GpFontFamilyList() : Head(NULL), FamilyCacheEntry(NULL) {} GpFontFamilyList::~GpFontFamilyList() { DeleteList(); } void GpFontFamilyList::DeleteList(void) { for (FamilyNode* node = Head; node != NULL; ) { FamilyNode * next = node->Next; delete node->Item; delete node; node = next; } if (FamilyCacheEntry) { GpFree(FamilyCacheEntry); FamilyCacheEntry = NULL; } Head = NULL; } /**************************************************************************\ * * Function Description: * * Counts number of enumerable families * * Arguments: * * filter: filter describing the desired font styles * * Returns: * * Number of available families * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ INT GpFontFamilyList::Enumerable(GpGraphics* graphics) const { INT result = 0; for (FamilyNode* node = Head; node != NULL; node = node->Next) { if (node->Item == NULL) { ASSERT(node->Item); } else if ( node->Item->AvailableFaces() != 0) { result++; } } return result; } /**************************************************************************\ * * Function Description: * * Enumerates the available font families. * * If numExpected == 0 then Enumerate() counts the number of available families * and returns the result in numExpected. * * If numExpected != 0 then Enumerate() sets pointers to as many available * families as possible. * * The total number of emurated families is return in numEnumerated. * * Arguments: * * numExpected: number of families expected and allocated in families array * families: array to hold pointers to enumerated families (preallocated) * numEnumerated: the actual number of fonts enumerated in this pass * filter: filter describing the desired font styles * * Returns: * * Status of the operation, which may include: * - success * - too few available fonts * - too many available fonts * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ Status GpFontFamilyList::Enumerate( INT numSought, GpFontFamily* gpfamilies[], INT& numFound, GpGraphics* graphics ) const { Status status = Ok; numFound = 0; for ( FamilyNode* node = Head; node != NULL && numFound < numSought; node = node->Next ) { if (node->Item == NULL) { ASSERT(node->Item); } else if ( node->Item->AvailableFaces() != 0) { gpfamilies[numFound++] = node->Item; } } return status; } /**************************************************************************\ * * Function Description: * * Finds the any font (except Marlett) in the family list * * Arguments: * * Returns: * * Pointer to family if found any, else NULL * * History: * * 07/14/2000 YungT * Created it. * \**************************************************************************/ GpFontFamily* GpFontFamilyList::GetAnyFamily() const { for (FamilyNode* node = Head; node != NULL; node = node->Next) { if (node->Item == NULL) { //ASSERT } else { if (!UnicodeStringCompare(L"MARLETT", node->Item->GetCaptializedName()) == 0) { return node->Item; } } } return NULL; } /**************************************************************************\ * * Function Description: * * Finds the named font in the family list * * Arguments: * * name: name of the font family to be found * * Returns: * * Pointer to family if found, else NULL * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ GpFontFamily* GpFontFamilyList::GetFamily(const WCHAR *familyName) const { WCHAR nameCap[FamilyNameMax]; // Family name GpMemset(nameCap, 0, sizeof(nameCap)); for (int c = 0; familyName[c] && c < FamilyNameMax - 1; c++) nameCap[c] = familyName[c]; UnicodeStringToUpper(nameCap, nameCap); for (FamilyNode* node = Head; node != NULL; node = node->Next) { if (node->Item == NULL) { //ASSERT } else { if (UnicodeStringCompare(nameCap, node->Item->GetCaptializedName()) == 0) { return node->Item; } if (node->Item->IsAliasName()) { if (UnicodeStringCompare(nameCap, node->Item->GetAliasName()) == 0) { return node->Item; } } } } return NULL; } /**************************************************************************\ * * Function Description: * * Adds a font family to the enumeration list ordered alphabetically * by family name. * * Arguments: * * fontFile: the font to be added. * * Returns: * * Boolean indicating success * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ BOOL GpFontFamilyList::AddFont(GpFontFile* fontFile, GpFontCollection *fontCollection) { BOOL newFamily = FALSE; BOOL newNodeInserted = FALSE; // Loop over each entry per font file for (ULONG e = 0; e < fontFile->GetNumEntries(); e++) { VERBOSE(("Adding \"%ws\" to family list...", fontFile->GetFamilyName(e))) // Check if the family already exists, if not create a new entry GpFontFamily* family = GetFamily(fontFile->GetFamilyName(e)); if (family == NULL) { FAMILYCACHEENTRY * pCacheEntry; UINT cjSize = sizeof(FAMILYCACHEENTRY); // This family is not in the list, create a new GpFontFamily object if (!(pCacheEntry = (FAMILYCACHEENTRY *) GpMalloc(cjSize))) { return FALSE; } pCacheEntry->cjThis = cjSize; family = new GpFontFamily(fontFile->GetFamilyName(e), fontFile, e, pCacheEntry, fontCollection); if (family == NULL) { GpFree(pCacheEntry); WARNING(("Error constructing family.")) return FALSE; } newFamily = TRUE; } // Insert entry into the enumeration list, ordered alphabetically GpFontFace* face = fontFile->GetFontFace(e); FontStyle style = face->GetFaceStyle(); if (InsertOrdered(family, style, fontFile, face, TRUE)) newNodeInserted = TRUE; if (newFamily && !newNodeInserted) { // New GpFontFamily object not used, delete it delete family; return FALSE; } } return TRUE; } /**************************************************************************\ * * Function Description: * * Inserts font family into the enumeration list ordered alphabetically * by family name, and links up the face pointer to the font entry. * * Arguments: * * family: the font family * face: the font face * entry: the font entry * * Returns: * * Boolean indicating whether family was added (a new node was created) * * History: * * 29/07/1999 cameronb * Created it. * \**************************************************************************/ BOOL GpFontFamilyList::InsertOrdered( GpFontFamily* family, FontStyle style, GpFontFile * fontfile, GpFontFace * face, BOOL bSetFace ) { BOOL result = FALSE; if (Head == NULL) { // First entry FamilyNode *new_node = new FamilyNode(family); if (!new_node) return FALSE; if(bSetFace) new_node->Item->SetFaceAndFile(style, face, fontfile); Head = new_node; return TRUE; } else { // Search the enumeration list for (FamilyNode* node = Head; node != NULL; node = node->Next) { int comp = UnicodeStringCompare(node->Item->GetCaptializedName(), family->GetCaptializedName()); if (comp == 0) { // FontFamily found in list if (bSetFace && node->Item->FaceExist(style & 3)) { // This face already exists for this family, do nothing VERBOSE(("Face collision: face %d exists for family \"%ws\".", style, family->GetCaptializedName())) } else { if (bSetFace) { // Update face pointer node->Item->SetFaceAndFile(style, face, fontfile); } } return FALSE; } else if (comp > 0) { // Add new family node FamilyNode *new_node = new FamilyNode(family); if (!new_node) return FALSE; if (bSetFace) { // Update face pointer new_node->Item->SetFaceAndFile(style, face, fontfile); } // Insert before node if (node->Prev == NULL) { // Insert at head new_node->Next = node; node->Prev = new_node; Head = new_node; } else { // Insert between node and prev new_node->Next = node; new_node->Prev = node->Prev; node->Prev->Next = new_node; node->Prev = new_node; } return TRUE; } else if (node->Next == NULL) { // Add new family node FamilyNode *new_node = new FamilyNode(family); if (!new_node) return FALSE; if (bSetFace) { // Update face pointer new_node->Item->SetFaceAndFile(style, face, fontfile); } // Insert at tail new_node->Prev = node; node->Next = new_node; return TRUE; } } } return result; } /**************************************************************************\ * * Function Description: * * Given a pointer to a font family, remove that font family from the list, * but only if its ref count is 0 and its Face pointers are all NULL. * The parameter bDeleted is set to TRUE if a GpFontFamily was deleted from * the list. * * Arguments: * * fontFamily: the font family to be removed * * Returns: * * Boolean indicating success * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ BOOL GpFontFamilyList::RemoveFontFamily(GpFontFamily* fontFamily) { FamilyNode *node; node = Head; while(node) { if (node->Item == fontFamily) { if (node->Item->Deletable()) { if (node->Prev) node->Prev->Next = node->Next; if (node->Next) node->Next->Prev = node->Prev; if (node == Head) Head = node->Next; delete node->Item; delete node; node = NULL; } else { // We found the font family, but it's not deletable, so // we can quit trying to delete the font family from the list. break; } } else { node = node->Next; } } return TRUE; } /**************************************************************************\ * * Function Description: * Create a cache list from GpFontFamily.cacheEntry * We will load it when the Family list is touched * * Arguments: * * None * * Returns: * * None * * History: * * 27/06/1999 cameronb * Created it. * \**************************************************************************/ VOID GpFontFamilyList::UpdateFamilyListToCache(BOOL bLoadFromRegistry, HKEY hkey, ULONG registrySize, ULONG numExpected) { FamilyNode *node; UINT cachedSize = 0; UINT entrySize = 0; GpFontFile * fontfile; GpFontFamily * family; FAMILYCACHEENTRY * pEntry; node = Head; if (bLoadFromRegistry) cachedSize = QWORD_ALIGN(registrySize + 8); while(node) { entrySize = 0; // Get the current GpFontFamily from family list family = node->Item; pEntry = family->GetCacheEntry(); // Here we need to calcuatle the size for each cache entry // it include FAMILYCACHEENTRY + fontfilepathname1 + fontfilepathname2 // A fmaily could have 1 more font file included entrySize += QWORD_ALIGN(pEntry->cjThis); for (UINT i = 0; i < NumFontFaces; i++) { if (fontfile = family->GetFontFile(i)) { pEntry->cFilePathName[i] = QWORD_ALIGN(fontfile->GetPathNameSize() * 2); entrySize += pEntry->cFilePathName[i]; } } cachedSize += entrySize; node = node->Next; } BYTE * pCacheEntry = (BYTE *)FontFileCacheAlloc(cachedSize); if (!pCacheEntry) { FontFileCacheFault(); return; } if (bLoadFromRegistry) { DWORD allDataSize = 0; ULONG index = 0; LONG error = ERROR_SUCCESS; PBYTE pRegistryData; *((ULONG *) pCacheEntry) = 0xBFBFBFBF; *((ULONG *) (pCacheEntry + 4)) = registrySize; pRegistryData = pCacheEntry + 8; while (index < numExpected && error != ERROR_NO_MORE_ITEMS && allDataSize < registrySize) { DWORD regType = 0; DWORD labelSize = MAX_PATH; DWORD dataSize = MAX_PATH; CHAR label[MAX_PATH]; BYTE data[MAX_PATH]; error = RegEnumValueA(hkey, index, label, &labelSize, NULL, ®Type, data, &dataSize); if (error == ERROR_NO_MORE_ITEMS) break; memcpy(pRegistryData, data, dataSize); pRegistryData += dataSize; allDataSize += dataSize; index ++; } pCacheEntry += QWORD_ALIGN(registrySize + 8); } node = Head; while(node) { entrySize = 0; family = node->Item; pEntry = family->GetCacheEntry(); ASSERT(pEntry->cjThis == sizeof(FAMILYCACHEENTRY)); entrySize = QWORD_ALIGN(pEntry->cjThis); memcpy((VOID *) pCacheEntry, (VOID *) pEntry, pEntry->cjThis); for (UINT i = 0; i < NumFontFaces; i++) { // cache the font file path name if (fontfile = family->GetFontFile(i)) { memcpy((VOID *) (pCacheEntry + entrySize), (VOID *) fontfile->GetPathName(), fontfile->GetPathNameSize() * 2); entrySize += pEntry->cFilePathName[i]; } } ((FAMILYCACHEENTRY *)pCacheEntry)->cjThis = entrySize; pCacheEntry += entrySize; node = node->Next; } return; } /**************************************************************************\ * * Function Description: * * Create a family list form the cache file * * * Arguments: * * NONE * * Returns: * * Boolean indicating the list is created successfully or not * * History: * * 06/28/20000 YungT [Yung-Jen Tony Tsai] * Created it. * \**************************************************************************/ BOOL GpFontFamilyList::BuildFamilyListFromCache(BOOL bLoadFromRegistry) { ULONG cachedSize = 0; ULONG calcSize = 0; FAMILYCACHEENTRY * pCacheEntry; BYTE * pCached= (BYTE *)FontFileCacheLookUp(&cachedSize); // We can not get data from cached file if (!cachedSize) return FALSE; if (bLoadFromRegistry) { ASSERT(!Globals::IsNt); ULONG registrySize = 0; if (*((ULONG *) pCached) != 0xBFBFBFBF) return FALSE; registrySize = *((ULONG *) (pCached + 4)) ; cachedSize -= QWORD_ALIGN(registrySize + 8); pCached += QWORD_ALIGN(registrySize + 8); } else { if (*((ULONG *) pCached) == 0xBFBFBFBF) return FALSE; } FamilyCacheEntry = (BYTE *) GpMalloc(cachedSize); if (!FamilyCacheEntry) return FALSE; memcpy(FamilyCacheEntry, pCached, cachedSize); while (calcSize < cachedSize) { pCacheEntry = (FAMILYCACHEENTRY *) (FamilyCacheEntry + calcSize); GpFontFamily * family = new GpFontFamily(pCacheEntry); if (family == NULL) { // Clean up we have created. DeleteList(); WARNING(("Error constructing family from cache.")) return FALSE; } if (!InsertOrdered(family, FontStyleRegular, (GpFontFile *) NULL, (GpFontFace *) NULL, FALSE)) { WARNING(("Error constructing family from cache.")) // New GpFontFamily object not used, delete it // Something wrong with this case so we need to delete it. delete family; DeleteList(); return FALSE; } calcSize += QWORD_ALIGN(pCacheEntry->cjThis); } ASSERT(calcSize == cachedSize); return TRUE; }