windows-nt/Source/XPSP1/NT/shell/themes/uxtheme/textdraw.cpp
2020-09-26 16:20:57 +08:00

395 lines
12 KiB
C++

//---------------------------------------------------------------------------
// TextDraw.cpp - implements the drawing API for text
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "Render.h"
#include "Utils.h"
#include "TextDraw.h"
#include "info.h"
#include "DrawHelp.h"
//---------------------------------------------------------------------------
HRESULT CTextDraw::PackProperties(CRenderObj *pRender, int iPartId, int iStateId)
{
memset(this, 0, sizeof(CTextDraw)); // allowed because we have no vtable
//---- save off partid, stateid for debugging ----
_iSourcePartId = iPartId;
_iSourceStateId = iStateId;
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TEXTCOLOR, &_crText)))
_crText = 0; // default value
//---- shadow ----
if (SUCCEEDED(pRender->GetPosition(iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &_ptShadowOffset)))
{
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &_crShadow)))
_crShadow = RGB(0, 0, 0); // default value = black
if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_TEXTSHADOWTYPE, (int *)&_eShadowType)))
_eShadowType = TST_NONE; // default value
}
//---- border ----
if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_TEXTBORDERSIZE, &_iBorderSize)))
{
_iBorderSize = 0;
}
else
{
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TEXTBORDERCOLOR, &_crBorder)))
_crBorder = RGB(0, 0, 0); // default value
}
//---- font ----
if (SUCCEEDED(pRender->GetFont(NULL, iPartId, iStateId, TMT_FONT, FALSE, &_lfFont)))
_fHaveFont = TRUE;
//---- edge colors ----
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGELIGHTCOLOR, &_crEdgeLight)))
_crEdgeLight = RGB(192, 192, 192);
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGEHIGHLIGHTCOLOR, &_crEdgeHighlight)))
_crEdgeHighlight = RGB(255, 255, 255);
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGESHADOWCOLOR, &_crEdgeShadow)))
_crEdgeShadow = RGB(128, 128, 128);
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGEDKSHADOWCOLOR, &_crEdgeDkShadow)))
_crEdgeDkShadow = RGB(0, 0, 0);
if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGEFILLCOLOR, &_crEdgeFill)))
_crEdgeFill = _crEdgeLight;
return S_OK;
}
//---------------------------------------------------------------------------
BOOL CTextDraw::KeyProperty(int iPropId)
{
BOOL fKey = FALSE;
switch (iPropId)
{
case TMT_TEXTCOLOR:
case TMT_TEXTSHADOWOFFSET:
case TMT_TEXTSHADOWCOLOR:
case TMT_TEXTSHADOWTYPE:
case TMT_TEXTBORDERSIZE:
case TMT_TEXTBORDERCOLOR:
case TMT_FONT:
case TMT_EDGELIGHTCOLOR:
case TMT_EDGEHIGHLIGHTCOLOR:
case TMT_EDGESHADOWCOLOR:
case TMT_EDGEDKSHADOWCOLOR:
case TMT_EDGEFILLCOLOR:
fKey = TRUE;
break;
}
return fKey;
}
//---------------------------------------------------------------------------
void CTextDraw::DumpProperties(CSimpleFile *pFile, BYTE *pbThemeData, BOOL fFullInfo)
{
if (fFullInfo)
pFile->OutLine(L"Dump of CTextDraw at offset=0x%x", (BYTE *)this - pbThemeData);
else
pFile->OutLine(L"Dump of CTextDraw");
pFile->OutLine(L" _crText=0x%08x", _crText);
pFile->OutLine(L" _ptShadowOffset=(%d, %d)", _ptShadowOffset.x, _ptShadowOffset.y);
pFile->OutLine(L" _crEdgeLight=0x%08x, _crEdgeHighlight=0x%08x, _crEdgeShadow=0x%08x",
_crEdgeLight, _crEdgeHighlight, _crEdgeShadow);
pFile->OutLine(L" _crEdgeDkShadow=0x%08x, _crEdgeFill=0x%08x, _crShadow=0x%08x",
_crEdgeDkShadow, _crEdgeFill, _crShadow);
pFile->OutLine(L" _eShadowType, _iBorderSize=%d, _crBorder=0x%08x",
_eShadowType, _iBorderSize, _crBorder);
//---- dump resolution-independent font points ----
int iFontPoints = FontPointSize(_lfFont.lfHeight);
pFile->OutLine(L" _fHaveFont=%d, font: %s, size=%d points, bold=%d, italic=%d",
_fHaveFont, _lfFont.lfFaceName, iFontPoints, _lfFont.lfWeight > 400, _lfFont.lfItalic);
}
//---------------------------------------------------------------------------
HRESULT CTextDraw::DrawText(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, LPCWSTR _pszText,
DWORD dwCharCount, DWORD dwTextFlags, const RECT *pRect, const DTTOPTS *pOptions)
{
Log(LOG_TM, L"DrawText(): iPartId=%d, pszText=%s", iPartId, _pszText);
int iRetVal;
HFONT hFont = NULL;
COLORREF oldcolor = 0;
HRESULT hr = S_OK;
BOOL fOldColor = FALSE;
RESOURCE HFONT oldfont = NULL;
LPWSTR pszText = (LPWSTR)_pszText; // so DrawText() calls are happy
dwTextFlags &= ~(DT_MODIFYSTRING); // we don't want to change the constant ptr
int oldmode = SetBkMode(hdc, TRANSPARENT);
RECT rect;
COLORREF crText = _crText;
COLORREF crBorder = _crBorder;
COLORREF crShadow = _crShadow;
TEXTSHADOWTYPE eShadowType = _eShadowType;
POINT ptShadowOffset = _ptShadowOffset;
int iBorderSize = _iBorderSize;
if (pOptions)
{
DWORD dwFlags = pOptions->dwFlags;
if (dwFlags & DTT_TEXTCOLOR)
crText = pOptions->crText;
if (dwFlags & DTT_BORDERCOLOR)
crBorder = pOptions->crBorder;
if (dwFlags & DTT_SHADOWCOLOR)
crShadow = pOptions->crShadow;
if (dwFlags & DTT_SHADOWTYPE)
eShadowType = (TEXTSHADOWTYPE)pOptions->eTextShadowType;
if (dwFlags & DTT_SHADOWOFFSET)
ptShadowOffset = pOptions->ptShadowOffset;
if (dwFlags & DTT_BORDERSIZE)
iBorderSize = pOptions->iBorderSize;
}
BOOL fShadow = (eShadowType != TST_NONE);
if (_fHaveFont)
{
hr = pRender->GetScaledFontHandle(hdc, &_lfFont, &hFont);
if (FAILED(hr))
goto exit;
oldfont = (HFONT)SelectObject(hdc, hFont);
}
//---- BLURRED shadow approach ----
if ((fShadow) && (eShadowType == TST_CONTINUOUS))
{
SetRect(&rect, pRect->left, pRect->top, pRect->right, pRect->bottom);
hr = EnsureUxCtrlLoaded();
if (FAILED(hr))
goto exit;
//---- this will draw shadow & text (no outline support yet) ----
iRetVal = CCDrawShadowText(hdc, pszText, dwCharCount, &rect, dwTextFlags, crText, crShadow,
ptShadowOffset.x, ptShadowOffset.y);
}
else //---- normal approach ----
{
//---- draw SINGLE shadow first ----
if (fShadow)
{
oldcolor = SetTextColor(hdc, crShadow);
fOldColor = TRUE;
//---- adjust rect for drawing shadow ----
rect.left = pRect->left + ptShadowOffset.x;
rect.top = pRect->top + ptShadowOffset.y;
rect.right = pRect->right + ptShadowOffset.x;
rect.bottom = pRect->bottom, ptShadowOffset.y;
iRetVal = DrawTextEx(hdc, pszText, dwCharCount, &rect, dwTextFlags, NULL);
if (! iRetVal)
{
hr = MakeErrorLast();
goto exit;
}
}
SetRect(&rect, pRect->left, pRect->top, pRect->right, pRect->bottom);
//---- draw outline, if wanted ----
if (iBorderSize) // draw outline around text
{
iRetVal = BeginPath(hdc);
if (! iRetVal)
{
hr = MakeErrorLast();
goto exit;
}
iRetVal = DrawTextEx(hdc, pszText, dwCharCount, &rect, dwTextFlags, NULL);
if (! iRetVal)
{
AbortPath(hdc);
hr = MakeErrorLast();
goto exit;
}
EndPath(hdc);
HPEN pen, oldpen;
HBRUSH brush, oldbrush;
pen = CreatePen(PS_SOLID, iBorderSize, crBorder);
brush = CreateSolidBrush(crText);
if ((pen) && (brush))
{
oldpen = (HPEN)SelectObject(hdc, pen);
oldbrush = (HBRUSH)SelectObject(hdc, brush);
//---- this draws both outline & normal text ---
StrokeAndFillPath(hdc);
SelectObject(hdc, oldpen);
SelectObject(hdc, oldbrush);
}
}
else // draw normal text
{
if (fOldColor)
SetTextColor(hdc, crText);
else
{
oldcolor = SetTextColor(hdc, crText);
fOldColor = TRUE;
}
iRetVal = DrawTextEx(hdc, pszText, dwCharCount, &rect, dwTextFlags, NULL);
if (! iRetVal)
{
hr = MakeErrorLast();
goto exit;
}
}
}
hr = S_OK;
exit:
//---- restore hdc objects ----
SetBkMode(hdc, oldmode);
if (fOldColor)
SetTextColor(hdc, oldcolor);
if (oldfont)
SelectObject(hdc, oldfont);
if (hFont)
pRender->ReturnFontHandle(hFont);
return hr;
}
//---------------------------------------------------------------------------
HRESULT CTextDraw::GetTextExtent(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, LPCWSTR _pszText,
int iCharCount, DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtentRect)
{
LPWSTR pszText = (LPWSTR)_pszText; // so DrawText() calls are happy
dwTextFlags &= ~(DT_MODIFYSTRING); // we don't want to change the constant ptr
Log(LOG_TM, L"GetTextExtent(): iPartId=%d, pszText=%s", iPartId, pszText);
RESOURCE HFONT oldfont = NULL;
HFONT hFont = NULL;
HRESULT hr = S_OK;
if (_fHaveFont)
{
hr = pRender->GetScaledFontHandle(hdc, &_lfFont, &hFont);
if (FAILED(hr))
goto exit;
oldfont = (HFONT)SelectObject(hdc, hFont);
}
RECT rect;
int iRetVal;
if (pBoundingRect)
rect = *pBoundingRect;
else
SetRect(&rect, 0, 0, 0, 0);
iRetVal = DrawTextEx(hdc, pszText, iCharCount, &rect, dwTextFlags | DT_CALCRECT, NULL);
if (! iRetVal)
{
hr = MakeErrorLast();
goto exit;
}
//----do NOT adjust for text shadow (ok if shadows overlap...) ----
*pExtentRect = rect;
exit:
//---- restore hdc objects ----
if (oldfont)
SelectObject(hdc, oldfont);
Log(LOG_TM, L"END Of GetTextExtent()");
if (hFont)
pRender->ReturnFontHandle(hFont);
return hr;
}
//---------------------------------------------------------------------------
HRESULT CTextDraw::GetTextMetrics(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, TEXTMETRIC* ptm)
{
Log(LOG_TM, L"GetTextMetrics(): iPartId=%d, ", iPartId);
HRESULT hr = S_OK;
RESOURCE HFONT hFont = NULL;
RESOURCE HFONT oldfont = NULL;
if (! ptm)
{
hr = MakeError32(E_INVALIDARG);
goto exit;
}
if (_fHaveFont)
{
hr = pRender->GetScaledFontHandle(hdc, &_lfFont, &hFont);
if (FAILED(hr))
goto exit;
oldfont = (HFONT)SelectObject(hdc, hFont);
}
if (! ::GetTextMetrics(hdc, ptm))
{
hr = MakeErrorLast();
goto exit;
}
exit:
//---- restore hdc objects ----
if (oldfont)
SelectObject(hdc, oldfont);
if (hFont)
pRender->ReturnFontHandle(hFont);
Log(LOG_TM, L"END Of GetTextMetrics()");
return hr;
}
//---------------------------------------------------------------------------
HRESULT CTextDraw::DrawEdge(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, const RECT *pDestRect,
UINT uEdge, UINT uFlags, OUT RECT *pContentRect)
{
Log(LOG_TM, L"DrawEdge(): iPartId=%d, iStateId=%d, uEdge=0x%08x, uFlags=0x%08x", iPartId, iStateId, uEdge, uFlags);
HRESULT hr = _DrawEdge(hdc, pDestRect, uEdge, uFlags,
_crEdgeLight, _crEdgeHighlight, _crEdgeShadow, _crEdgeDkShadow, _crEdgeFill, pContentRect);
Log(LOG_TM, L"END Of DrawEdge()");
return hr;
}
//---------------------------------------------------------------------------