Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
12 KiB

  1. //---------------------------------------------------------------------------
  2. // TextDraw.cpp - implements the drawing API for text
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "Render.h"
  6. #include "Utils.h"
  7. #include "TextDraw.h"
  8. #include "info.h"
  9. #include "DrawHelp.h"
  10. //---------------------------------------------------------------------------
  11. HRESULT CTextDraw::PackProperties(CRenderObj *pRender, int iPartId, int iStateId)
  12. {
  13. memset(this, 0, sizeof(CTextDraw)); // allowed because we have no vtable
  14. //---- save off partid, stateid for debugging ----
  15. _iSourcePartId = iPartId;
  16. _iSourceStateId = iStateId;
  17. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TEXTCOLOR, &_crText)))
  18. _crText = 0; // default value
  19. //---- shadow ----
  20. if (SUCCEEDED(pRender->GetPosition(iPartId, iStateId, TMT_TEXTSHADOWOFFSET, &_ptShadowOffset)))
  21. {
  22. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TEXTSHADOWCOLOR, &_crShadow)))
  23. _crShadow = RGB(0, 0, 0); // default value = black
  24. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_TEXTSHADOWTYPE, (int *)&_eShadowType)))
  25. _eShadowType = TST_NONE; // default value
  26. }
  27. //---- border ----
  28. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_TEXTBORDERSIZE, &_iBorderSize)))
  29. {
  30. _iBorderSize = 0;
  31. }
  32. else
  33. {
  34. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TEXTBORDERCOLOR, &_crBorder)))
  35. _crBorder = RGB(0, 0, 0); // default value
  36. }
  37. //---- font ----
  38. if (SUCCEEDED(pRender->GetFont(NULL, iPartId, iStateId, TMT_FONT, FALSE, &_lfFont)))
  39. _fHaveFont = TRUE;
  40. //---- edge colors ----
  41. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGELIGHTCOLOR, &_crEdgeLight)))
  42. _crEdgeLight = RGB(192, 192, 192);
  43. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGEHIGHLIGHTCOLOR, &_crEdgeHighlight)))
  44. _crEdgeHighlight = RGB(255, 255, 255);
  45. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGESHADOWCOLOR, &_crEdgeShadow)))
  46. _crEdgeShadow = RGB(128, 128, 128);
  47. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGEDKSHADOWCOLOR, &_crEdgeDkShadow)))
  48. _crEdgeDkShadow = RGB(0, 0, 0);
  49. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_EDGEFILLCOLOR, &_crEdgeFill)))
  50. _crEdgeFill = _crEdgeLight;
  51. return S_OK;
  52. }
  53. //---------------------------------------------------------------------------
  54. BOOL CTextDraw::KeyProperty(int iPropId)
  55. {
  56. BOOL fKey = FALSE;
  57. switch (iPropId)
  58. {
  59. case TMT_TEXTCOLOR:
  60. case TMT_TEXTSHADOWOFFSET:
  61. case TMT_TEXTSHADOWCOLOR:
  62. case TMT_TEXTSHADOWTYPE:
  63. case TMT_TEXTBORDERSIZE:
  64. case TMT_TEXTBORDERCOLOR:
  65. case TMT_FONT:
  66. case TMT_EDGELIGHTCOLOR:
  67. case TMT_EDGEHIGHLIGHTCOLOR:
  68. case TMT_EDGESHADOWCOLOR:
  69. case TMT_EDGEDKSHADOWCOLOR:
  70. case TMT_EDGEFILLCOLOR:
  71. fKey = TRUE;
  72. break;
  73. }
  74. return fKey;
  75. }
  76. //---------------------------------------------------------------------------
  77. void CTextDraw::DumpProperties(CSimpleFile *pFile, BYTE *pbThemeData, BOOL fFullInfo)
  78. {
  79. if (fFullInfo)
  80. pFile->OutLine(L"Dump of CTextDraw at offset=0x%x", (BYTE *)this - pbThemeData);
  81. else
  82. pFile->OutLine(L"Dump of CTextDraw");
  83. pFile->OutLine(L" _crText=0x%08x", _crText);
  84. pFile->OutLine(L" _ptShadowOffset=(%d, %d)", _ptShadowOffset.x, _ptShadowOffset.y);
  85. pFile->OutLine(L" _crEdgeLight=0x%08x, _crEdgeHighlight=0x%08x, _crEdgeShadow=0x%08x",
  86. _crEdgeLight, _crEdgeHighlight, _crEdgeShadow);
  87. pFile->OutLine(L" _crEdgeDkShadow=0x%08x, _crEdgeFill=0x%08x, _crShadow=0x%08x",
  88. _crEdgeDkShadow, _crEdgeFill, _crShadow);
  89. pFile->OutLine(L" _eShadowType, _iBorderSize=%d, _crBorder=0x%08x",
  90. _eShadowType, _iBorderSize, _crBorder);
  91. //---- dump resolution-independent font points ----
  92. int iFontPoints = FontPointSize(_lfFont.lfHeight);
  93. pFile->OutLine(L" _fHaveFont=%d, font: %s, size=%d points, bold=%d, italic=%d",
  94. _fHaveFont, _lfFont.lfFaceName, iFontPoints, _lfFont.lfWeight > 400, _lfFont.lfItalic);
  95. }
  96. //---------------------------------------------------------------------------
  97. HRESULT CTextDraw::DrawText(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, LPCWSTR _pszText,
  98. DWORD dwCharCount, DWORD dwTextFlags, const RECT *pRect, const DTTOPTS *pOptions)
  99. {
  100. Log(LOG_TM, L"DrawText(): iPartId=%d, pszText=%s", iPartId, _pszText);
  101. int iRetVal;
  102. HFONT hFont = NULL;
  103. COLORREF oldcolor = 0;
  104. HRESULT hr = S_OK;
  105. BOOL fOldColor = FALSE;
  106. RESOURCE HFONT oldfont = NULL;
  107. LPWSTR pszText = (LPWSTR)_pszText; // so DrawText() calls are happy
  108. dwTextFlags &= ~(DT_MODIFYSTRING); // we don't want to change the constant ptr
  109. int oldmode = SetBkMode(hdc, TRANSPARENT);
  110. RECT rect;
  111. COLORREF crText = _crText;
  112. COLORREF crBorder = _crBorder;
  113. COLORREF crShadow = _crShadow;
  114. TEXTSHADOWTYPE eShadowType = _eShadowType;
  115. POINT ptShadowOffset = _ptShadowOffset;
  116. int iBorderSize = _iBorderSize;
  117. if (pOptions)
  118. {
  119. DWORD dwFlags = pOptions->dwFlags;
  120. if (dwFlags & DTT_TEXTCOLOR)
  121. crText = pOptions->crText;
  122. if (dwFlags & DTT_BORDERCOLOR)
  123. crBorder = pOptions->crBorder;
  124. if (dwFlags & DTT_SHADOWCOLOR)
  125. crShadow = pOptions->crShadow;
  126. if (dwFlags & DTT_SHADOWTYPE)
  127. eShadowType = (TEXTSHADOWTYPE)pOptions->eTextShadowType;
  128. if (dwFlags & DTT_SHADOWOFFSET)
  129. ptShadowOffset = pOptions->ptShadowOffset;
  130. if (dwFlags & DTT_BORDERSIZE)
  131. iBorderSize = pOptions->iBorderSize;
  132. }
  133. BOOL fShadow = (eShadowType != TST_NONE);
  134. if (_fHaveFont)
  135. {
  136. hr = pRender->GetScaledFontHandle(hdc, &_lfFont, &hFont);
  137. if (FAILED(hr))
  138. goto exit;
  139. oldfont = (HFONT)SelectObject(hdc, hFont);
  140. }
  141. //---- BLURRED shadow approach ----
  142. if ((fShadow) && (eShadowType == TST_CONTINUOUS))
  143. {
  144. SetRect(&rect, pRect->left, pRect->top, pRect->right, pRect->bottom);
  145. hr = EnsureUxCtrlLoaded();
  146. if (FAILED(hr))
  147. goto exit;
  148. //---- this will draw shadow & text (no outline support yet) ----
  149. iRetVal = CCDrawShadowText(hdc, pszText, dwCharCount, &rect, dwTextFlags, crText, crShadow,
  150. ptShadowOffset.x, ptShadowOffset.y);
  151. }
  152. else //---- normal approach ----
  153. {
  154. //---- draw SINGLE shadow first ----
  155. if (fShadow)
  156. {
  157. oldcolor = SetTextColor(hdc, crShadow);
  158. fOldColor = TRUE;
  159. //---- adjust rect for drawing shadow ----
  160. rect.left = pRect->left + ptShadowOffset.x;
  161. rect.top = pRect->top + ptShadowOffset.y;
  162. rect.right = pRect->right + ptShadowOffset.x;
  163. rect.bottom = pRect->bottom, ptShadowOffset.y;
  164. iRetVal = DrawTextEx(hdc, pszText, dwCharCount, &rect, dwTextFlags, NULL);
  165. if (! iRetVal)
  166. {
  167. hr = MakeErrorLast();
  168. goto exit;
  169. }
  170. }
  171. SetRect(&rect, pRect->left, pRect->top, pRect->right, pRect->bottom);
  172. //---- draw outline, if wanted ----
  173. if (iBorderSize) // draw outline around text
  174. {
  175. iRetVal = BeginPath(hdc);
  176. if (! iRetVal)
  177. {
  178. hr = MakeErrorLast();
  179. goto exit;
  180. }
  181. iRetVal = DrawTextEx(hdc, pszText, dwCharCount, &rect, dwTextFlags, NULL);
  182. if (! iRetVal)
  183. {
  184. AbortPath(hdc);
  185. hr = MakeErrorLast();
  186. goto exit;
  187. }
  188. EndPath(hdc);
  189. HPEN pen, oldpen;
  190. HBRUSH brush, oldbrush;
  191. pen = CreatePen(PS_SOLID, iBorderSize, crBorder);
  192. brush = CreateSolidBrush(crText);
  193. if ((pen) && (brush))
  194. {
  195. oldpen = (HPEN)SelectObject(hdc, pen);
  196. oldbrush = (HBRUSH)SelectObject(hdc, brush);
  197. //---- this draws both outline & normal text ---
  198. StrokeAndFillPath(hdc);
  199. SelectObject(hdc, oldpen);
  200. SelectObject(hdc, oldbrush);
  201. }
  202. }
  203. else // draw normal text
  204. {
  205. if (fOldColor)
  206. SetTextColor(hdc, crText);
  207. else
  208. {
  209. oldcolor = SetTextColor(hdc, crText);
  210. fOldColor = TRUE;
  211. }
  212. iRetVal = DrawTextEx(hdc, pszText, dwCharCount, &rect, dwTextFlags, NULL);
  213. if (! iRetVal)
  214. {
  215. hr = MakeErrorLast();
  216. goto exit;
  217. }
  218. }
  219. }
  220. hr = S_OK;
  221. exit:
  222. //---- restore hdc objects ----
  223. SetBkMode(hdc, oldmode);
  224. if (fOldColor)
  225. SetTextColor(hdc, oldcolor);
  226. if (oldfont)
  227. SelectObject(hdc, oldfont);
  228. if (hFont)
  229. pRender->ReturnFontHandle(hFont);
  230. return hr;
  231. }
  232. //---------------------------------------------------------------------------
  233. HRESULT CTextDraw::GetTextExtent(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, LPCWSTR _pszText,
  234. int iCharCount, DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtentRect)
  235. {
  236. LPWSTR pszText = (LPWSTR)_pszText; // so DrawText() calls are happy
  237. dwTextFlags &= ~(DT_MODIFYSTRING); // we don't want to change the constant ptr
  238. Log(LOG_TM, L"GetTextExtent(): iPartId=%d, pszText=%s", iPartId, pszText);
  239. RESOURCE HFONT oldfont = NULL;
  240. HFONT hFont = NULL;
  241. HRESULT hr = S_OK;
  242. if (_fHaveFont)
  243. {
  244. hr = pRender->GetScaledFontHandle(hdc, &_lfFont, &hFont);
  245. if (FAILED(hr))
  246. goto exit;
  247. oldfont = (HFONT)SelectObject(hdc, hFont);
  248. }
  249. RECT rect;
  250. int iRetVal;
  251. if (pBoundingRect)
  252. rect = *pBoundingRect;
  253. else
  254. SetRect(&rect, 0, 0, 0, 0);
  255. iRetVal = DrawTextEx(hdc, pszText, iCharCount, &rect, dwTextFlags | DT_CALCRECT, NULL);
  256. if (! iRetVal)
  257. {
  258. hr = MakeErrorLast();
  259. goto exit;
  260. }
  261. //----do NOT adjust for text shadow (ok if shadows overlap...) ----
  262. *pExtentRect = rect;
  263. exit:
  264. //---- restore hdc objects ----
  265. if (oldfont)
  266. SelectObject(hdc, oldfont);
  267. Log(LOG_TM, L"END Of GetTextExtent()");
  268. if (hFont)
  269. pRender->ReturnFontHandle(hFont);
  270. return hr;
  271. }
  272. //---------------------------------------------------------------------------
  273. HRESULT CTextDraw::GetTextMetrics(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, TEXTMETRIC* ptm)
  274. {
  275. Log(LOG_TM, L"GetTextMetrics(): iPartId=%d, ", iPartId);
  276. HRESULT hr = S_OK;
  277. RESOURCE HFONT hFont = NULL;
  278. RESOURCE HFONT oldfont = NULL;
  279. if (! ptm)
  280. {
  281. hr = MakeError32(E_INVALIDARG);
  282. goto exit;
  283. }
  284. if (_fHaveFont)
  285. {
  286. hr = pRender->GetScaledFontHandle(hdc, &_lfFont, &hFont);
  287. if (FAILED(hr))
  288. goto exit;
  289. oldfont = (HFONT)SelectObject(hdc, hFont);
  290. }
  291. if (! ::GetTextMetrics(hdc, ptm))
  292. {
  293. hr = MakeErrorLast();
  294. goto exit;
  295. }
  296. exit:
  297. //---- restore hdc objects ----
  298. if (oldfont)
  299. SelectObject(hdc, oldfont);
  300. if (hFont)
  301. pRender->ReturnFontHandle(hFont);
  302. Log(LOG_TM, L"END Of GetTextMetrics()");
  303. return hr;
  304. }
  305. //---------------------------------------------------------------------------
  306. HRESULT CTextDraw::DrawEdge(CRenderObj *pRender, HDC hdc, int iPartId, int iStateId, const RECT *pDestRect,
  307. UINT uEdge, UINT uFlags, OUT RECT *pContentRect)
  308. {
  309. Log(LOG_TM, L"DrawEdge(): iPartId=%d, iStateId=%d, uEdge=0x%08x, uFlags=0x%08x", iPartId, iStateId, uEdge, uFlags);
  310. HRESULT hr = _DrawEdge(hdc, pDestRect, uEdge, uFlags,
  311. _crEdgeLight, _crEdgeHighlight, _crEdgeShadow, _crEdgeDkShadow, _crEdgeFill, pContentRect);
  312. Log(LOG_TM, L"END Of DrawEdge()");
  313. return hr;
  314. }
  315. //---------------------------------------------------------------------------