All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
284 lines
6.6 KiB
C++
284 lines
6.6 KiB
C++
// 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;
|
|
}
|