#include "stdafx.h" #include #include #include #include "FontEngine.h" #include "FontFile.h" #include "Font.h" #include "FT_FontEngine.h" #include "List.h" //------------------------------------------------------------------------------------------------------------------------------- // CFontEngine //------------------------------------------------------------------------------------------------------------------------------- CFontEngine::CFontEngine(BOOL bAntiAliasing, BOOL bUseKerning, BOOL bLoadWinFonts, CString sWinFontsXml, CString wsFontDir) { for ( int nIndex = 0; nIndex < MAX_FONT_CACHE_SIZE; ++nIndex ) { m_pFontCache[nIndex] = NULL; } // Инициализируем библиотеку FreeType m_pFreeTypeEngine = CFreeTypeFontEngine::Initialize( bAntiAliasing, bUseKerning ); // Составляем список установленных шрифтов m_pWinFontList = NULL; if ( _T("") != sWinFontsXml ) m_pWinFontList = new CWinFontList( sWinFontsXml ); else if ( bLoadWinFonts ) { if ( _T("") != wsFontDir ) m_pWinFontList = new CWinFontList( m_pFreeTypeEngine->m_pLibrary, wsFontDir ); else m_pWinFontList = new CWinFontList( m_pFreeTypeEngine->m_pLibrary ); } m_pDefaultFont[0] = NULL; m_pDefaultFont[1] = NULL; m_pDefaultFont[2] = NULL; m_pDefaultFont[3] = NULL; for ( int nIndex = 0; nIndex < INSTALLED_FONTS_CACHE_SIZE; nIndex++ ) { m_arrInstalledFontsCache[nIndex].wsFamilyName = _T(""); m_arrInstalledFontsCache[nIndex].lStyle = 0; m_arrInstalledFontsCache[nIndex].pWinFontInfo = NULL; } } CFontEngine::CFontEngine(BOOL bAntiAliasing, BOOL bUseKerning, BOOL bLoadWinFonts, BYTE* pBuffer, CString wsFontDir) { for ( int nIndex = 0; nIndex < MAX_FONT_CACHE_SIZE; ++nIndex ) { m_pFontCache[nIndex] = NULL; } // Инициализируем библиотеку FreeType m_pFreeTypeEngine = CFreeTypeFontEngine::Initialize( bAntiAliasing, bUseKerning ); // Составляем список установленных шрифтов m_pWinFontList = NULL; if ( NULL != pBuffer ) m_pWinFontList = new CWinFontList( pBuffer, wsFontDir ); else if ( bLoadWinFonts ) { if ( _T("") != wsFontDir ) m_pWinFontList = new CWinFontList( m_pFreeTypeEngine->m_pLibrary, wsFontDir ); else m_pWinFontList = new CWinFontList( m_pFreeTypeEngine->m_pLibrary ); } m_pDefaultFont[0] = NULL; m_pDefaultFont[1] = NULL; m_pDefaultFont[2] = NULL; m_pDefaultFont[3] = NULL; for ( int nIndex = 0; nIndex < INSTALLED_FONTS_CACHE_SIZE; nIndex++ ) { m_arrInstalledFontsCache[nIndex].wsFamilyName = _T(""); m_arrInstalledFontsCache[nIndex].lStyle = 0; m_arrInstalledFontsCache[nIndex].pWinFontInfo = NULL; } } CFontEngine::~CFontEngine() { for ( int nIndex = 0; nIndex < MAX_FONT_CACHE_SIZE; ++nIndex ) { if ( m_pFontCache[nIndex] ) { delete m_pFontCache[nIndex]; } } for ( int nIndex = 0; nIndex < 4; nIndex++ ) { if ( m_pDefaultFont[nIndex] ) delete m_pDefaultFont[nIndex]; } if ( m_pFreeTypeEngine ) { delete m_pFreeTypeEngine; } if ( m_pWinFontList ) delete m_pWinFontList; } CFontFile *CFontEngine::GetFontFile(wchar_t *wsFamilyName, BOOL bBold, BOOL bItalic) { long lIndex = 0; long lStyle = ( bBold ? 1 : 0 ) + ( bItalic ? 2 : 0 ); CWinFontInfo *pFontInfo = GetInstalledFont(wsFamilyName, lStyle, &lIndex ); if ( !pFontInfo ) return NULL; for ( int nIndex = 0; nIndex < MAX_FONT_CACHE_SIZE; ++nIndex ) { if ( m_pFontCache[nIndex] ) { CFontFile *pFontFile = m_pFontCache[nIndex]->GetFontFile(); CStringW oTemp1 = pFontFile->m_wsFileName; CStringW oTemp2 = pFontInfo->m_wsFontPath; oTemp1.MakeLower(); oTemp2.MakeLower(); if ( pFontFile && oTemp1 == oTemp2 && pFontFile->m_lIndex == pFontInfo->m_lIndex ) { return pFontFile; } } } return NULL; } CFontFile *CFontEngine::GetFontFile(wchar_t *wsFilePath, long lIndex) { for ( int nIndex = 0; nIndex < MAX_FONT_CACHE_SIZE; ++nIndex ) { if ( m_pFontCache[nIndex] ) { CFontFile *pFontFile = m_pFontCache[nIndex]->GetFontFile(); CStringW oTemp1 = pFontFile->m_wsFileName; CStringW oTemp2 = CStringW( wsFilePath ); oTemp1.MakeLower(); oTemp2.MakeLower(); if ( pFontFile && oTemp1 == oTemp2 && pFontFile->m_lIndex == lIndex ) { return pFontFile; } } } return NULL; } CFontFile *CFontEngine::LoadFont(wchar_t *wsFamilyName, BOOL bBold, BOOL bItalic) { long lIndex = 0; long lStyle = ( bBold ? 1 : 0 ) + ( bItalic ? 2 : 0 ); CWinFontInfo *pFontInfo = GetInstalledFont(wsFamilyName, lStyle, &lIndex ); if ( !pFontInfo ) return NULL; CFontFile *pFontFile = NULL; if ( !pFontFile && m_pFreeTypeEngine ) { pFontFile = m_pFreeTypeEngine->LoadFont( pFontInfo->m_wsFontPath.GetBuffer(), pFontInfo->m_lIndex ); } return pFontFile; } CFontFile *CFontEngine::LoadFont(wchar_t *wsFilePath, long lIndex) { CFontFile *pFontFile = NULL; if ( !pFontFile && m_pFreeTypeEngine ) { pFontFile = m_pFreeTypeEngine->LoadFont( wsFilePath, lIndex ); } return pFontFile; } CWinFontInfo *CFontEngine::GetInstalledFont(long lIndex) { if ( !m_pWinFontList ) return NULL; int nCount = m_pWinFontList->GetFonts()->GetLength(); if ( lIndex < 0 ) lIndex = 0; else if ( lIndex >= nCount ) lIndex = nCount - 1; CWinFontInfo *pFontInfo = m_pWinFontList->GetByIndex( lIndex ); return pFontInfo; } CWinFontInfo *CFontEngine::GetInstalledFont(wchar_t *wsFamilyName, long lStyle, long *plIndex) { int nCacheIndex = FindInCache( wsFamilyName, lStyle ); if ( -1 != nCacheIndex ) return m_arrInstalledFontsCache[nCacheIndex].pWinFontInfo; if ( !m_pWinFontList ) return NULL; // Ищем все шрифты с данным именем FamilyName CList *pFoundList = new CList(); CSimpleArray arrIndexList; if ( !pFoundList ) return NULL; for ( int nIndex = 0; nIndex < m_pWinFontList->GetFonts()->GetLength(); nIndex++ ) { CWinFontInfo *pFontInfo = m_pWinFontList->GetByIndex( nIndex ); if ( CStringW( wsFamilyName ) == pFontInfo->m_wsFontName ) { // Мы добавляем только ссылки в список, поэтому при удалении не надо делать DeleteCList() pFoundList->Append( pFontInfo ); arrIndexList.Add( nIndex ); } } if ( pFoundList->GetLength() <= 0 ) { delete pFoundList; return NULL; } BOOL bBold = FALSE; BOOL bItalic = FALSE; switch (lStyle) { case FontConstants::FontStyleRegular: bBold = FALSE; bItalic = FALSE; break; case FontConstants::FontStyleItalic: bBold = FALSE; bItalic = TRUE; break; case FontConstants::FontStyleBold: bBold = TRUE; bItalic = FALSE; break; case FontConstants::FontStyleBoldItalic: bBold = TRUE; bItalic = TRUE; break; } // Ищем шрифт с данным стилем int arrStyles[4] = { -1, -1, -1, -1 }; // { Regular, Bold, Italic, Bold Italic } for ( int nIndex = 0; nIndex < pFoundList->GetLength(); nIndex++ ) { CWinFontInfo *pCurFont = (CWinFontInfo *)pFoundList->GetByIndex( nIndex ); if ( arrStyles[3] < 0 && TRUE == pCurFont->m_bBold && TRUE == pCurFont->m_bItalic ) arrStyles[3] = nIndex; if ( arrStyles[2] < 0 && FALSE == pCurFont->m_bBold && TRUE == pCurFont->m_bItalic ) arrStyles[2] = nIndex; if ( arrStyles[1] < 0 && TRUE == pCurFont->m_bBold && FALSE == pCurFont->m_bItalic ) arrStyles[1] = nIndex; if ( arrStyles[0] < 0 && FALSE == pCurFont->m_bBold && FALSE == pCurFont->m_bItalic ) arrStyles[0] = nIndex; } CWinFontInfo *pFontInfo = NULL; BOOL bNeedBold = bBold, bNeedItalic = bItalic; if ( bBold && bItalic && arrStyles[3] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[3] ); bNeedBold = FALSE; bNeedItalic = FALSE; *plIndex = arrIndexList.GetData()[arrStyles[3]]; } else if ( bBold && bItalic && arrStyles[3] < 0 && arrStyles[1] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[1] ); bNeedBold = FALSE; *plIndex = arrIndexList.GetData()[arrStyles[1]]; } else if ( bBold && bItalic && arrStyles[3] < 0 && arrStyles[2] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[2] ); bNeedItalic = FALSE; *plIndex = arrIndexList.GetData()[arrStyles[2]]; } else if ( bBold && bItalic && arrStyles[3] < 0 && arrStyles[0] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[0] ); *plIndex = arrIndexList.GetData()[arrStyles[0]]; } else if ( bBold && !bItalic && arrStyles[1] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[1] ); bNeedBold = FALSE; *plIndex = arrIndexList.GetData()[arrStyles[1]]; } else if ( bBold && !bItalic && arrStyles[1] < 0 && arrStyles[0] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[0] ); *plIndex = arrIndexList.GetData()[arrStyles[0]]; } else if ( !bBold && bItalic && arrStyles[2] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[2] ); bNeedItalic = FALSE; *plIndex = arrIndexList.GetData()[arrStyles[2]]; } else if ( !bBold && bItalic && arrStyles[2] < 0 && arrStyles[0] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[0] ); *plIndex = arrIndexList.GetData()[arrStyles[0]]; } else if ( !bBold && !bItalic && arrStyles[0] >= 0 ) { pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[0] ); *plIndex = arrIndexList.GetData()[arrStyles[0]]; } else { // если не один из предыдущих вариантов не прошел, тогда берем первый попавшийся фонт // запоминая, нужно ли в будущем делать Bold и Italic int nIndex = 0; for ( ; nIndex < 4; nIndex++ ) if ( arrStyles[nIndex] >= 0 ) break; if ( nIndex < 4 ) { switch ( nIndex ) { case 0: break; case 1: bNeedBold = FALSE; break; case 2: bNeedItalic = FALSE; break; case 3: bNeedItalic = FALSE; bNeedBold = FALSE; break; } pFontInfo = (CWinFontInfo *)pFoundList->GetByIndex( arrStyles[nIndex] ); *plIndex = arrIndexList.GetData()[arrStyles[nIndex]]; } } delete pFoundList; TInstalledFontCacheEntry oEntry; oEntry.lStyle = lStyle; oEntry.pWinFontInfo = pFontInfo; oEntry.wsFamilyName = CStringW( wsFamilyName ); AddToCache( oEntry ); return pFontInfo; } CWinFontInfo *CFontEngine::GetInstalledFont(CString sParamsXml) { if ( !m_pWinFontList ) return NULL; return m_pWinFontList->GetByParams( sParamsXml ); } CWinFontInfo *CFontEngine::GetInstalledFont(wchar_t* wsAltFontName, long lCharset, wchar_t* wsFamilyClass, long lStyle, BOOL bFixed, wchar_t *wsPanose, long lUnicodeRange1, long lUnicodeRange2, long lUnicodeRange3, long lUnicodeRange4, long lCodePageRange1, long lCodePageRange2, long lAvgWidth) { if ( !m_pWinFontList ) return NULL; return m_pWinFontList->GetByParams( wsAltFontName, lCharset, wsFamilyClass, lStyle, bFixed, wsPanose, lUnicodeRange1, lUnicodeRange2, lUnicodeRange3, lUnicodeRange4, lCodePageRange1, lCodePageRange2, lAvgWidth ); } long CFontEngine::GetInstalledFontsCount() { if ( !m_pWinFontList ) return 0; return m_pWinFontList->GetFonts()->GetLength(); } BOOL CFontEngine::IsStyleAvailable(wchar_t *wsFamilyName, long lStyle) { if ( !m_pWinFontList ) return FALSE; BOOL bResult = FALSE; BOOL bBold = FALSE; BOOL bItalic = FALSE; switch (lStyle) { case FontConstants::FontStyleRegular: bBold = FALSE; bItalic = FALSE; break; case FontConstants::FontStyleItalic: bBold = FALSE; bItalic = TRUE; break; case FontConstants::FontStyleBold: bBold = TRUE; bItalic = FALSE; break; case FontConstants::FontStyleBoldItalic: bBold = TRUE; bItalic = TRUE; break; } // Ищем все шрифты с данным именем FamilyName CList *pFoundList = new CList(); if ( !pFoundList ) return FALSE; for ( int nIndex = 0; nIndex < m_pWinFontList->GetFonts()->GetLength(); nIndex++ ) { CWinFontInfo *pFontInfo = m_pWinFontList->GetByIndex( nIndex ); if ( CStringW( wsFamilyName ) == pFontInfo->m_wsFontName ) { // Мы добавляем только ссылки в список, поэтому при удалении не надо делать DeleteCList() pFoundList->Append( pFontInfo ); } } // Ищем шрифт с данным стилем int arrStyles[4] = { -1, -1, -1, -1 }; // { Regular, Bold, Italic, Bold Italic } for ( int nIndex = 0; nIndex < pFoundList->GetLength(); nIndex++ ) { CWinFontInfo *pCurFont = (CWinFontInfo *)pFoundList->GetByIndex( nIndex ); if ( arrStyles[3] < 0 && TRUE == pCurFont->m_bBold && TRUE == pCurFont->m_bItalic ) arrStyles[3] = nIndex; if ( arrStyles[2] < 0 && FALSE == pCurFont->m_bBold && TRUE == pCurFont->m_bItalic ) arrStyles[2] = nIndex; if ( arrStyles[1] < 0 && TRUE == pCurFont->m_bBold && FALSE == pCurFont->m_bItalic ) arrStyles[1] = nIndex; if ( arrStyles[0] < 0 && FALSE == pCurFont->m_bBold && FALSE == pCurFont->m_bItalic ) arrStyles[0] = nIndex; } if ( arrStyles[0] >= 0 ) // Если есть Regular, то в крайнем случае остальные из него можем получить с помощью преобразований bResult = TRUE; else if ( FALSE == bBold && FALSE == bItalic ) // Regular нельзя получить из других стилей bResult = FALSE; else if ( TRUE == bBold && FALSE == bItalic ) { if ( arrStyles[1] >= 0 ) bResult = TRUE; else bResult = FALSE; } else if ( FALSE == bBold && TRUE == bItalic ) { if ( arrStyles[2] >= 0 ) bResult = TRUE; else bResult = FALSE; } else if ( TRUE == bBold && TRUE == bItalic ) { if ( arrStyles[1] >= 0 || arrStyles[2] >= 0 || arrStyles[3] >= 0 ) bResult = TRUE; else bResult = FALSE; } return bResult; } CFont *CFontEngine::GetFont(CFontFile *pFontFile) { // Если шрифт совпадает с первым в кэше, тогда отдаем указатель на первый шрифт CFont *pFont = m_pFontCache[0]; if ( pFont && pFont->Matches( pFontFile ) ) { return pFont; } // Если шрифт совпадает с не первым шрифтом из кэша, тогда указатель на данный шрифт двигаем в начало кэша и отдаем его for ( int nFontIndex = 1; nFontIndex < MAX_FONT_CACHE_SIZE; ++nFontIndex ) { pFont = m_pFontCache[nFontIndex]; if ( pFont && pFont->Matches( pFontFile ) ) { for ( int nJ = nFontIndex; nJ > 0; --nJ ) { m_pFontCache[nJ] = m_pFontCache[nJ - 1]; } m_pFontCache[0] = pFont; return pFont; } } // Если данного шрифта в кэше нет, создаем шрифт и записываем его в начало кэша, а последний шрифт из кэша удаляем(если он там есть) pFont = pFontFile->MakeFont(); if ( m_pFontCache[MAX_FONT_CACHE_SIZE - 1] ) { delete m_pFontCache[MAX_FONT_CACHE_SIZE - 1]; } for ( int nJ = MAX_FONT_CACHE_SIZE - 1; nJ > 0; --nJ ) { m_pFontCache[nJ] = m_pFontCache[nJ - 1]; } m_pFontCache[0] = pFont; return pFont; } void CFontEngine::SetAA(BOOL bAA) { m_pFreeTypeEngine->m_bAntiAliasing = bAA; } void CFontEngine::SetDefaultFont(wchar_t *wsFamilyName) { for ( int nIndex = 0; nIndex < 4; nIndex++ ) { BOOL bBold, bItalic; switch( nIndex ) { case 0: bBold = FALSE; bItalic = FALSE; break; case 1: bBold = TRUE; bItalic = FALSE; break; case 2: bBold = FALSE; bItalic = TRUE; break; case 3: bBold = TRUE; bItalic = TRUE; break; } long lIndex = 0; long lStyle = ( bBold ? 1 : 0 ) + ( bItalic ? 2 : 0 ); CWinFontInfo *pFontInfo = GetInstalledFont(wsFamilyName, lStyle, &lIndex ); if ( !pFontInfo ) return; CFontFile *pFontFile = NULL; if ( !pFontFile && m_pFreeTypeEngine ) { pFontFile = m_pFreeTypeEngine->LoadFont( pFontInfo->m_wsFontPath.GetBuffer(), pFontInfo->m_lIndex ); } if ( !pFontFile ) return; if ( m_pDefaultFont[nIndex] ) delete m_pDefaultFont[nIndex]; if ( 0 == nIndex && m_pWinFontList ) m_pWinFontList->SetDefaultFont( lIndex ); m_pDefaultFont[nIndex] = pFontFile->MakeFont(); UpdateStyles( m_pDefaultFont[nIndex], bBold, bItalic ); } } void CFontEngine::SetDefaultFont(wchar_t *wsFilePath, long lIndex) { for ( int nIndex = 0; nIndex < 4; nIndex++ ) { BOOL bBold, bItalic; switch( nIndex ) { case 0: bBold = FALSE; bItalic = FALSE; break; case 1: bBold = TRUE; bItalic = FALSE; break; case 2: bBold = FALSE; bItalic = TRUE; break; case 3: bBold = TRUE; bItalic = TRUE; break; } CFontFile *pFontFile = NULL; if ( !pFontFile && m_pFreeTypeEngine ) { pFontFile = m_pFreeTypeEngine->LoadFont( wsFilePath, lIndex ); } if ( !pFontFile ) return; if ( m_pDefaultFont[nIndex] ) delete m_pDefaultFont[nIndex]; m_pDefaultFont[nIndex] = pFontFile->MakeFont(); UpdateStyles( m_pDefaultFont[nIndex], bBold, bItalic ); } } CFont *CFontEngine::GetDefaultFont(BOOL bBold, BOOL bItalic) { int nIndex = ( bBold ? 1 : 0 ) + ( bItalic ? 2 : 0 ); return m_pDefaultFont[nIndex]; } void CFontEngine::AddToCache(TInstalledFontCacheEntry oEntry) { int nLastIndex = 0; while ( nLastIndex < INSTALLED_FONTS_CACHE_SIZE && m_arrInstalledFontsCache[nLastIndex].wsFamilyName != _T("") ) nLastIndex++; if ( INSTALLED_FONTS_CACHE_SIZE == nLastIndex ) { for ( int nIndex = INSTALLED_FONTS_CACHE_SIZE - 1; nIndex > 0; nIndex-- ) { m_arrInstalledFontsCache[nIndex] = m_arrInstalledFontsCache[nIndex - 1]; } m_arrInstalledFontsCache[0] = oEntry; } else { m_arrInstalledFontsCache[nLastIndex] = oEntry; } } int CFontEngine::FindInCache(wchar_t *wsFamilyName, long lStyle) { int nResult = -1; for ( int nIndex = 0; nIndex < INSTALLED_FONTS_CACHE_SIZE; nIndex++ ) { if ( _T("") == m_arrInstalledFontsCache[nIndex].wsFamilyName ) break; if ( CStringW( wsFamilyName) == m_arrInstalledFontsCache[nIndex].wsFamilyName && lStyle == m_arrInstalledFontsCache[nIndex].lStyle ) { nResult = nIndex; break; } } return nResult; }