/*++ Copyright (c) 2000 Microsoft Corporation Module Name: glfcach.h Abstract: PCL XL glyph cache Environment: Windows Whistler Revision History: 11/09/00 Created it. --*/ #include "xlpdev.h" #include "xldebug.h" #include "glyfcach.h" XLGlyphCache:: XLGlyphCache(VOID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::Ctor entry.\n")); m_ulNumberOfFonts = NULL; m_ulNumberOfArray = NULL; m_paulFontID = NULL; m_ppGlyphTable = NULL; #if DBG m_dbglevel = GLYPHCACHE; #endif } XLGlyphCache:: ~XLGlyphCache(VOID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::Dtor entry.\n")); FreeAll(); } VOID XLGlyphCache:: FreeAll(VOID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::FreeAll entry.\n")); MemFree(m_paulFontID); ULONG ulI; PGLYPHTABLE *ppGlyphTable = m_ppGlyphTable; PGLYPHTABLE pGlyphTable; for (ulI = 0; ulI < m_ulNumberOfFonts; ulI++, ppGlyphTable++) { if (pGlyphTable = *ppGlyphTable) { if (pGlyphTable->pGlyphID) { MemFree(pGlyphTable->pGlyphID); } MemFree(pGlyphTable); } } if (m_ppGlyphTable) { MemFree(m_ppGlyphTable); } } HRESULT XLGlyphCache:: XLCreateFont( ULONG ulFontID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::CreateFont(ulFontiD=%d) entry.\n", ulFontID)); HRESULT hResult; ULONG ulI; // // Search font ID // ULONG ulArrayID = UlSearchFontID(ulFontID); // // New font ID // if (ulArrayID == 0xFFFF || ulArrayID == m_ulNumberOfFonts) { // // Out of buffer. Increase array // if (m_ulNumberOfArray == m_ulNumberOfFonts) { if (S_OK != (hResult = IncreaseArray())) { XL_ERR(("XLGlyphCache::CreateFont IncreaseArray failed.\n")); return hResult; } } *(m_paulFontID + m_ulNumberOfFonts) = ulFontID; PGLYPHTABLE pGlyphTable; if (!(pGlyphTable = (PGLYPHTABLE)MemAllocZ(sizeof(GLYPHTABLE)))) { XL_ERR(("XLGlyphCache::CreateFont MemAllocZ failed.\n")); return E_UNEXPECTED; } pGlyphTable->wFontID = (WORD)ulFontID; pGlyphTable->wGlyphNum = 0; pGlyphTable->pFirstGID = NULL; pGlyphTable->pGlyphID = NULL; pGlyphTable->dwAvailableEntries = 0; PGLYPHID pGlyphID; if (!(pGlyphID = (PGLYPHID)MemAllocZ(INIT_GLYPH_ARRAY * sizeof(GLYPHID)))) { XL_ERR(("XLGlyphCache::CreateFont MemAllocZ failed.\n")); MemFree(pGlyphTable); return E_UNEXPECTED; } pGlyphTable->pGlyphID = pGlyphID; pGlyphTable->dwAvailableEntries = INIT_GLYPH_ARRAY; *(m_ppGlyphTable + m_ulNumberOfFonts) = pGlyphTable; m_ulNumberOfFonts ++; XL_VERBOSE(("XLGlyphCache::CreateFont New font ID.\n")); } return S_OK; } HRESULT XLGlyphCache:: IncreaseArray( VOID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::IncreaseArray entry.\n")); if (NULL == m_paulFontID || NULL == m_ppGlyphTable) { if (NULL == m_paulFontID) { if (!(m_paulFontID = (PULONG)MemAllocZ(INIT_ARRAY * sizeof(ULONG)))) { FreeAll(); XL_ERR(("XLGlyphCache::IncreaseArray MemAllocZ failed.\n")); return E_UNEXPECTED; } } if (NULL == m_ppGlyphTable) { if (!(m_ppGlyphTable = (GLYPHTABLE**)MemAllocZ(INIT_ARRAY * sizeof(GLYPHTABLE)))) { FreeAll(); XL_ERR(("XLGlyphCache::IncreaseArray MemAllocZ failed.\n")); return E_UNEXPECTED; } } m_ulNumberOfArray = INIT_ARRAY; m_ulNumberOfFonts = 0; } else if (m_ulNumberOfArray == m_ulNumberOfFonts) { ULONG ulArraySize = m_ulNumberOfArray + ADD_ARRAY; PULONG paulTmpFontID; PGLYPHTABLE *ppTmpGlyphTable; // // Allocate new buffer // if (!(paulTmpFontID = (PULONG)MemAllocZ(ulArraySize))) { XL_ERR(("XLGlyphCache::IncreaseArray MemAllocZ failed.\n")); return E_UNEXPECTED; } if (!(ppTmpGlyphTable = (GLYPHTABLE**)MemAllocZ(ulArraySize * sizeof(GLYPHTABLE)))) { MemFree(paulTmpFontID); XL_ERR(("XLGlyphCache::IncreaseArray MemAllocZ failed.\n")); return E_UNEXPECTED; } // // Copy old one to new one // CopyMemory(paulTmpFontID, m_paulFontID, m_ulNumberOfArray * sizeof(ULONG)); CopyMemory(ppTmpGlyphTable, m_ppGlyphTable, m_ulNumberOfArray * sizeof(GLYPHTABLE)); // // Free old buffer // MemFree(m_paulFontID); MemFree(m_ppGlyphTable); // // Set new buffer // m_paulFontID = paulTmpFontID; m_ppGlyphTable = ppTmpGlyphTable; m_ulNumberOfArray = ulArraySize; } return S_OK; } ULONG XLGlyphCache:: UlSearchFontID( ULONG ulFontID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::UlSearchFontID entry.\n")); ULONG ulReturn, ulI; BOOL bFound; if (NULL == m_paulFontID) { // // Error case. Returns 0xFFFF. // Here is an assumption. The number of fonts in one document doesn't // become larger than 65535. // XL_ERR(("XLGlyphCache::UlSearchFontID failed.\n")); return 0xFFFF; } bFound = TRUE; // // Search font ID // ulI = m_ulNumberOfFonts / 2; PULONG paulFontID = m_paulFontID + ulI; while ( *paulFontID != ulFontID) { if (ulI == 0) { bFound = FALSE; break; } ulI = ulI / 2; if (ulI == 0) { ulI = 1; } if (*paulFontID < ulFontID) { paulFontID += ulI; } else { paulFontID -= ulI; } if (ulI == 1) { ulI = 0; } } if (!bFound) { ulReturn = m_ulNumberOfFonts; } else { ulReturn = (ULONG)(paulFontID - m_paulFontID); } XL_VERBOSE(("XLGlyphCache::UlSearchFontID(ulFontID=%d, ulArrayID=%d).\n", ulFontID, ulReturn)); return ulReturn; } HRESULT XLGlyphCache:: AddGlyphID( ULONG ulFontID, ULONG ulGlyphID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::AddGlyphID entry (ulFontiD=%d, ulGlyphID=%d).\n", ulFontID, ulGlyphID)); ULONG ulArrayID; // // Get the pointer to GLYPYTABLE of this font. // if (0xFFFF == (ulArrayID = UlSearchFontID(ulFontID))) { XL_ERR(("XLGlyphCache::AddGlyphID UlSearchFontID failed.\n")); return E_UNEXPECTED; } PGLYPHTABLE pGlyphTable = *(m_ppGlyphTable+ulArrayID); PGLYPHID pGlyphID = pGlyphTable->pFirstGID; BOOL bFound; WORD wI, wSearchRange; wSearchRange = pGlyphTable->wGlyphNum / 2; pGlyphID = PSearchGlyph(wSearchRange, TRUE, pGlyphID); bFound = TRUE; if (pGlyphID) { while (pGlyphID->ulGlyphID != ulGlyphID) { if (wSearchRange == 0) { bFound = FALSE; break; } wSearchRange = wSearchRange / 2; if (wSearchRange == 0) { wSearchRange = 1; } if (pGlyphID->ulGlyphID > ulGlyphID) { pGlyphID = PSearchGlyph(wSearchRange, TRUE, pGlyphID); } else { pGlyphID = PSearchGlyph(wSearchRange, FALSE, pGlyphID); } if (wSearchRange == 1) { wSearchRange = 0; } if (NULL == pGlyphID) { bFound = FALSE; break; } } } else { // // PSearchGlyph failed. There is not glyph available in the cache. // bFound = FALSE; } if (bFound) { XL_VERBOSE(("XLGlyphCache::AddGlyphID FOUND glyph in the cache.\n")); return S_FALSE; } else if (pGlyphID) { PGLYPHID pPrevGID = pGlyphID->pPrevGID; PGLYPHID pNextGID = pGlyphID->pNextGID; PGLYPHID pNewGID; IncreaseGlyphArray(ulFontID); pNewGID = pGlyphTable->pGlyphID + pGlyphTable->wGlyphNum; if (pGlyphID->ulGlyphID < ulGlyphID && ulGlyphID < pNextGID->ulGlyphID) { pGlyphID->pNextGID = pNewGID; pNewGID->pPrevGID = pGlyphID; pNewGID->pNextGID = pNextGID; pNextGID->pPrevGID = pNewGID; } else if (pPrevGID->ulGlyphID < ulGlyphID && ulGlyphID < pGlyphID->ulGlyphID) { pPrevGID->pNextGID = pNewGID; pNewGID->pPrevGID = pPrevGID; pNewGID->pNextGID = pGlyphID; pGlyphID->pPrevGID = pNewGID; } pNewGID->ulGlyphID = ulGlyphID; pGlyphTable->wGlyphNum++; XL_VERBOSE(("XLGlyphCache::AddGlyphID ADDED glyph in the cache.\n")); return S_OK; } else { PGLYPHID pNewGID; IncreaseGlyphArray(ulFontID); pNewGID = pGlyphTable->pGlyphID + pGlyphTable->wGlyphNum; pNewGID->ulGlyphID = ulGlyphID; pNewGID->pPrevGID = NULL; pNewGID->pNextGID = NULL; pGlyphTable->wGlyphNum++; XL_VERBOSE(("XLGlyphCache::AddGlyphID ADDED glyph in the cache.\n")); return S_OK; } } PGLYPHID XLGlyphCache:: PSearchGlyph( WORD wSearchRange, BOOL bForward, PGLYPHID pGlyphID) /*++ Routine Description: Arguments: Return Value: Note: --*/ { XL_VERBOSE(("XLGlyphCache::PSearchGlyph entry (wSearchRange=%d,bForward=%d).\n",wSearchRange, bForward)); WORD wI; if (pGlyphID) { if (bForward) { for (wI = 0; wI < wSearchRange; wI++) { if (pGlyphID->pNextGID) { pGlyphID = pGlyphID->pNextGID; } else { pGlyphID = NULL; break; } } } else { for (wI = 0; wI < wSearchRange; wI++) { if (pGlyphID->pNextGID) { pGlyphID = pGlyphID->pNextGID; } else { pGlyphID = NULL; break; } } } } XL_VERBOSE(("XLGlyphCache::PSearchGlyph pGlyphID = %0x.\n", pGlyphID)); return pGlyphID; } HRESULT XLGlyphCache:: IncreaseGlyphArray( ULONG ulFontID) { ULONG ulArrayID; // // Get the pointer to GLYPYTABLE of this font. // if (0xFFFF == (ulArrayID = UlSearchFontID(ulFontID))) { XL_ERR(("XLGlyphCache::AddGlyphID UlSearchFontID failed.\n")); return E_UNEXPECTED; } PGLYPHTABLE pGlyphTable = *(m_ppGlyphTable+ulArrayID); // // Get the pointer to GLYPYTABLE of this font. // if (0xFFFF == (ulArrayID = UlSearchFontID(ulFontID))) { XL_ERR(("XLGlyphCache::AddGlyphID UlSearchFontID failed.\n")); return E_UNEXPECTED; } if (pGlyphTable->wGlyphNum == pGlyphTable->dwAvailableEntries) { PGLYPHID pGlyphID; if (!(pGlyphID = (PGLYPHID)MemAllocZ((pGlyphTable->dwAvailableEntries + ADD_GLYPH_ARRAY) * sizeof(GLYPHID)))) { XL_ERR(("XLGlyphCache::AddGlyphID MemAllocZ failed.\n")); return E_UNEXPECTED; } CopyMemory(pGlyphID, pGlyphTable->pGlyphID, pGlyphTable->dwAvailableEntries * sizeof(GLYPHID)); pGlyphTable->pFirstGID = pGlyphID + (pGlyphTable->pFirstGID - pGlyphTable->pGlyphID); MemFree(pGlyphTable->pGlyphID); pGlyphTable->pGlyphID = pGlyphID; pGlyphTable->dwAvailableEntries += ADD_GLYPH_ARRAY; } return S_OK; } #if DBG VOID XLGlyphCache:: SetDbgLevel( DWORD dwLevel) /*++ Routine Description: Arguments: Return Value: Note: --*/ { m_dbglevel = dwLevel; } #endif