// FontCache.cpp : Implementation of cFontCache #include "stdafx.h" #include "Inject.h" #include "FontCache.h" #include "Manager.h" ///////////////////////////////////////////////////////////////////////////// // cFontCache cFontCache::~cFontCache() { cManager::_p->removeFont( this ); } #define BUFFER_WIDTHCHARS 32 #define BUFFER_HEIGHTCHARS 8 #define BUFFER_CHARCOUNT (BUFFER_WIDTHCHARS * BUFFER_HEIGHTCHARS) bool cFontCache::checkBuffer() { if( m_pBuffer.p ) { VARIANT_BOOL bWasLost; m_pBuffer->get_WasLost( &bWasLost ); if( bWasLost ) m_pBuffer.Release(); } if( m_pBuffer.p ) // The character buff is intact return true; // Get a dummy DC from the primary surface CComPtr< ICanvas > pSurf; if( FAILED(cManager::_p->GetPrimarySurface( &pSurf )) ) return false; // Madar: This can happen if you set an edit-text during plugin initialization. if (!pSurf) { return false; } HDC hdc; pSurf->GetDC( &hdc ); // Drakier: reset error, try to create font, then check for error. SetLastError(ERROR_SUCCESS); HFONT hfnt = ::CreateFontIndirect( &m_lf ); if (GetLastError() != ERROR_SUCCESS) { _ASSERTE(GetLastError()); // Drakier: try arial instead strcpy(m_lf.lfFaceName, "Arial"); SetLastError(ERROR_SUCCESS); HFONT hfnt = ::CreateFontIndirect( &m_lf ); if (GetLastError() != ERROR_SUCCESS) return false; } HFONT hfntOld = reinterpret_cast< HFONT >( ::SelectObject( hdc, hfnt ) ); TEXTMETRIC tm; ::GetTextMetrics( hdc, &tm ); m_szCharCell.cy = tm.tmHeight; m_szCharCell.cx = tm.tmMaxCharWidth; // Create the buffer SIZE szBuffer = { m_szCharCell.cx * BUFFER_WIDTHCHARS, m_szCharCell.cy * BUFFER_HEIGHTCHARS }; cManager::_p->CreateCanvas( &szBuffer, &m_pBuffer ); INT widths[ BUFFER_CHARCOUNT ]; BOOL b = ::GetCharWidth( hdc, 0, ( BUFFER_CHARCOUNT - 1 ), widths ); _ASSERTE( b ); DWORD dwError = ::GetLastError(); for( short nChar = 0; nChar < BUFFER_CHARCOUNT; ++ nChar ) { // TODO: Render the chars // Figure out the character cell size m_nWidths[ nChar ].m_nWidth = widths[ nChar ]; } // TODO: Render all the chars into the buffer ::SelectObject( hdc, hfntOld ); ::DeleteObject( hfnt ); pSurf->ReleaseDC(); return true; } STDMETHODIMP cFontCache::DrawText( LPPOINT ppt, BSTR strText, long clr, ICanvas *pCanvas ) { /* _ASSERTE( ppt != NULL ); _ASSERTE( strText != NULL ); _ASSERTE( pCanvas != NULL ); if( !checkBuffer() ) return E_FAIL; USES_CONVERSION; LPCTSTR szText = OLE2T( strText ); // TODO: Draw this a lot faster from a cached bitmap value HDC hdc; pCanvas->GetDC( &hdc ); // Draw the text HFONT hfnt = ::CreateFontIndirect( &m_lf ), hfntOld = reinterpret_cast< HFONT >( ::SelectObject( hdc, hfnt ) ); ::SetBkMode( hdc, TRANSPARENT ); ::SetTextColor( hdc, clr ); ::SetTextAlign( hdc, TA_TOP | TA_LEFT ); LPCSTR szAnsi = OLE2A( strText ); int cbLength = ::strlen( szAnsi ); INT *pDeltas = new INT[ cbLength ]; // Fill in the character deltas const char *i_src = szAnsi; INT *i_end_deltas = pDeltas + cbLength; for( INT *i_delta = pDeltas; i_delta != i_end_deltas; ++ i_delta, ++ i_src ) *i_delta = m_nWidths[ *i_src ].m_nWidth; if( m_bFontSmoothing ) SystemParametersInfo( SPI_SETFONTSMOOTHING, FALSE, NULL, 0 ); ::ExtTextOut( hdc, ppt->x, ppt->y, 0, NULL, szAnsi, cbLength, pDeltas ); if( m_bFontSmoothing ) SystemParametersInfo( SPI_SETFONTSMOOTHING, TRUE, NULL, 0 ); delete[] pDeltas; ::SelectObject( hdc, hfntOld ); ::DeleteObject( hfnt ); pCanvas->ReleaseDC(); return S_OK;*/ return DrawTextEx( ppt, strText, clr, 0, 0, pCanvas ); } STDMETHODIMP cFontCache::DrawTextEx( LPPOINT ppt, BSTR strText, long clr1, long clr2, long lFlags, ICanvas *pCanvas ) { _ASSERTE( ppt != NULL ); _ASSERTE( strText != NULL ); _ASSERTE( pCanvas != NULL ); if( !checkBuffer() ) return E_FAIL; USES_CONVERSION; LPCTSTR szText = OLE2T( strText ); // TODO: Draw this a lot faster from a cached bitmap value HDC hdc; pCanvas->GetDC( &hdc ); // Draw the text // Drakier: reset error, try to create font, then check for error. SetLastError(ERROR_SUCCESS); HFONT hfnt = ::CreateFontIndirect( &m_lf ); if (GetLastError() != ERROR_SUCCESS) { _ASSERTE(GetLastError()); // Drakier: try arial instead strcpy(m_lf.lfFaceName, "Arial"); SetLastError(ERROR_SUCCESS); HFONT hfnt = ::CreateFontIndirect( &m_lf ); if (GetLastError() != ERROR_SUCCESS) return E_FAIL; } HFONT hfntOld = reinterpret_cast< HFONT >( ::SelectObject( hdc, hfnt ) ); ::SetBkMode( hdc, TRANSPARENT ); ::SetTextAlign( hdc, TA_TOP | TA_LEFT ); LPCSTR szAnsi = OLE2A( strText ); int cbLength = ::strlen( szAnsi ); INT *pDeltas = new INT[ cbLength ]; // Fill in the character deltas const char *i_src = szAnsi; INT *i_end_deltas = pDeltas + cbLength; for( INT *i_delta = pDeltas; i_delta != i_end_deltas; ++ i_delta, ++ i_src ) *i_delta = m_nWidths[ *i_src ].m_nWidth; if( !(lFlags & eAA) ) if( m_bFontSmoothing ) SystemParametersInfo( SPI_SETFONTSMOOTHING, FALSE, NULL, 0 ); if( lFlags & eOutlined ) { ::SetTextColor( hdc, clr2 ); ::ExtTextOut( hdc, ppt->x - 1, ppt->y - 1, 0, NULL, szAnsi, cbLength, pDeltas ); ::ExtTextOut( hdc, ppt->x - 1, ppt->y + 1, 0, NULL, szAnsi, cbLength, pDeltas ); ::ExtTextOut( hdc, ppt->x + 1, ppt->y - 1, 0, NULL, szAnsi, cbLength, pDeltas ); ::ExtTextOut( hdc, ppt->x + 1, ppt->y + 1, 0, NULL, szAnsi, cbLength, pDeltas ); } ::SetTextColor( hdc, clr1 ); ::ExtTextOut( hdc, ppt->x, ppt->y, 0, NULL, szAnsi, cbLength, pDeltas ); if( !(lFlags & eAA) ) if( m_bFontSmoothing ) SystemParametersInfo( SPI_SETFONTSMOOTHING, TRUE, NULL, 0 ); delete[] pDeltas; ::SelectObject( hdc, hfntOld ); ::DeleteObject( hfnt ); pCanvas->ReleaseDC(); return S_OK; } STDMETHODIMP cFontCache::MeasureText( BSTR strText, LPSIZE pszExt ) { _ASSERTE( strText != NULL ); _ASSERTE( pszExt != NULL ); if( !checkBuffer() ) return E_FAIL; USES_CONVERSION; LPCSTR szText = OLE2T( strText ), i_end_text = szText + strlen( szText ); pszExt->cy = m_szCharCell.cy; pszExt->cx = 0; for( LPCSTR i_text = szText; i_text != i_end_text; ++ i_text ) pszExt->cx += m_nWidths[ *i_text ].m_nWidth; return S_OK; } STDMETHODIMP cFontCache::HitTest(BSTR szText, long nPos, long *nIndex) { _ASSERTE( szText != NULL ); _ASSERTE( nIndex != NULL ); if( !checkBuffer() ) return E_FAIL; USES_CONVERSION; LPCSTR szAText = OLE2T( szText ), i_end_text = szAText + strlen( szAText ); for( LPCSTR i_text = szAText; i_text != i_end_text; ++ i_text ) { short nWidth = m_nWidths[ *i_text ].m_nWidth; if( nPos < nWidth ) { *nIndex = ( i_text - szAText ); return S_OK; } nPos -= nWidth; } *nIndex = -1; return S_OK; }