Leaked source code of windows server 2003
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.

1237 lines
34 KiB

  1. //---------------------------------------------------------------------------
  2. // Render.cpp - implements the themed drawing services
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "Render.h"
  6. #include "Utils.h"
  7. #include "Parser.h"
  8. #include "Loader.h"
  9. #include "tmutils.h"
  10. #include "gradient.h"
  11. #include "rgn.h"
  12. #include "info.h"
  13. #include "cache.h"
  14. #include "cachelist.h"
  15. #include "borderfill.h"
  16. #include "imagefile.h"
  17. #ifdef DEBUG
  18. static DWORD s_dwSize = 0;
  19. #endif
  20. //---------------------------------------------------------------------------
  21. HRESULT CreateRenderObj(CUxThemeFile *pThemeFile, int iCacheSlot, int iThemeOffset,
  22. int iClassNameOffset, __int64 iUniqueId, BOOL fEnableCache, CDrawBase *pBaseObj,
  23. CTextDraw *pTextObj, DWORD dwOtdFlags, CRenderObj **ppObj)
  24. {
  25. HRESULT hr = S_OK;
  26. CRenderObj *pRender = new CRenderObj(pThemeFile, iCacheSlot, iThemeOffset,
  27. iClassNameOffset, iUniqueId, fEnableCache, dwOtdFlags);
  28. if (! pRender)
  29. {
  30. hr = MakeError32(E_OUTOFMEMORY);
  31. }
  32. else
  33. {
  34. hr = pRender->Init(pBaseObj, pTextObj);
  35. if (FAILED(hr))
  36. delete pRender;
  37. else
  38. *ppObj = pRender;
  39. }
  40. return hr;
  41. }
  42. //---------------------------------------------------------------------------
  43. CRenderObj::CRenderObj(CUxThemeFile *pThemeFile, int iCacheSlot, int iThemeOffset,
  44. int iClassNameOffset, __int64 iUniqueId, BOOL fEnableCache, DWORD dwOtdFlags)
  45. {
  46. StringCchCopyA(_szHead, ARRAYSIZE(_szHead), "rendobj");
  47. StringCchCopyA(_szTail, ARRAYSIZE(_szTail), "end");
  48. _fCacheEnabled = fEnableCache;
  49. _fCloseThemeFile = FALSE;
  50. _dwOtdFlags = dwOtdFlags;
  51. if (pThemeFile)
  52. {
  53. if (SUCCEEDED(BumpThemeFileRefCount(pThemeFile)))
  54. _fCloseThemeFile = TRUE;
  55. }
  56. _pThemeFile = pThemeFile;
  57. _iCacheSlot = iCacheSlot;
  58. _iUniqueId = iUniqueId;
  59. if (pThemeFile)
  60. {
  61. _pbThemeData = pThemeFile->_pbThemeData;
  62. _pbSectionData = _pbThemeData + iThemeOffset;
  63. _ptm = GetThemeMetricsPtr(pThemeFile);
  64. }
  65. else
  66. {
  67. _pbThemeData = NULL;
  68. _pbSectionData = NULL;
  69. _ptm = NULL;
  70. }
  71. _pszClassName = ThemeString(pThemeFile, iClassNameOffset);
  72. _iMaxPart = 0;
  73. _pParts = NULL;
  74. _iDpiOverride = 0;
  75. //---- caller must call "Init()" after ctr! ----
  76. }
  77. //---------------------------------------------------------------------------
  78. HRESULT CRenderObj::PrepareAlphaBitmap(HBITMAP hBitmap)
  79. {
  80. HRESULT hr = S_OK;
  81. //---- convert to DIBDATA ----
  82. CBitmapPixels pixels;
  83. DWORD *pPixelQuads;
  84. int iWidth, iHeight, iBytesPerPixel, iBytesPerRow;
  85. hr = pixels.OpenBitmap(NULL, hBitmap, TRUE, &pPixelQuads, &iWidth, &iHeight,
  86. &iBytesPerPixel, &iBytesPerRow);
  87. if (FAILED(hr))
  88. goto exit;
  89. PreMultiplyAlpha(pPixelQuads, iWidth, iHeight);
  90. pixels.CloseBitmap(NULL, hBitmap);
  91. exit:
  92. return hr;
  93. }
  94. //---------------------------------------------------------------------------
  95. HRESULT CRenderObj::Init(CDrawBase *pBaseObj, CTextDraw *pTextObj)
  96. {
  97. HRESULT hr = S_OK;
  98. if (_fCacheEnabled)
  99. {
  100. hr = BuildPackedPtrs(pBaseObj, pTextObj);
  101. if (FAILED(hr))
  102. goto exit;
  103. }
  104. //---- prepare direct objects ----
  105. if ((pBaseObj) && (pBaseObj->_eBgType == BT_IMAGEFILE))
  106. {
  107. CMaxImageFile *pMaxIf = (CMaxImageFile *)pBaseObj;
  108. //---- process primary image ----
  109. DIBINFO *pdi = &pMaxIf->_ImageInfo;
  110. if (pdi->fAlphaChannel)
  111. {
  112. hr = PrepareAlphaBitmap(pdi->hProcessBitmap);
  113. if (FAILED(hr))
  114. goto exit;
  115. }
  116. //---- process glyph image ----
  117. pdi = &pMaxIf->_GlyphInfo;
  118. if (pdi->fAlphaChannel)
  119. {
  120. hr = PrepareAlphaBitmap(pdi->hProcessBitmap);
  121. if (FAILED(hr))
  122. goto exit;
  123. }
  124. //---- process multiple images ----
  125. for (int i=0; i < pMaxIf->_iMultiImageCount; i++)
  126. {
  127. pdi = pMaxIf->MultiDibPtr(i);
  128. if (pdi->fAlphaChannel)
  129. {
  130. hr = PrepareAlphaBitmap(pdi->hProcessBitmap);
  131. if (FAILED(hr))
  132. goto exit;
  133. }
  134. }
  135. }
  136. exit:
  137. return hr;
  138. }
  139. //---------------------------------------------------------------------------
  140. CRenderObj::~CRenderObj()
  141. {
  142. //---- delete memory allocated for pack objects looked ----
  143. if (_pParts)
  144. {
  145. for(int i=0; i<_iMaxPart+1; i++)
  146. {
  147. if (_pParts[i].pStateDrawObjs)
  148. delete[] _pParts[i].pStateDrawObjs;
  149. if (_pParts[i].pStateTextObjs)
  150. delete[] _pParts[i].pStateTextObjs;
  151. }
  152. delete[] _pParts;
  153. }
  154. //---- if we opened a refcount on a themefile, close it now ----
  155. if (_fCloseThemeFile)
  156. CloseThemeFile(_pThemeFile);
  157. //---- mark this object as "deleted" (for debugging) ----
  158. StringCchCopyA(_szHead, ARRAYSIZE(_szHead), "deleted");
  159. }
  160. //---------------------------------------------------------------------------
  161. int CRenderObj::GetDpiOverride()
  162. {
  163. return _iDpiOverride;
  164. }
  165. //---------------------------------------------------------------------------
  166. HRESULT CRenderObj::BuildPackedPtrs(CDrawBase *pBaseObj, CTextDraw *pTextObj)
  167. {
  168. MIXEDPTRS u;
  169. HRESULT hr = S_OK;
  170. int iPackedOffset = 0;
  171. int *iPartOffsets = NULL;
  172. BOOL fSingleObj = FALSE;
  173. //---- extract _iMaxPart ----
  174. if ((pBaseObj) || (pTextObj)) // single object to be used for all parts/states
  175. {
  176. _iMaxPart = 1; // dummy value
  177. fSingleObj = TRUE;
  178. }
  179. else
  180. {
  181. u.pb = _pbSectionData;
  182. if (*u.ps != TMT_PARTJUMPTABLE)
  183. {
  184. hr = MakeError32(E_FAIL); // something went amiss
  185. goto exit;
  186. }
  187. u.pb += ENTRYHDR_SIZE;
  188. iPackedOffset = *u.pi++;
  189. _iMaxPart = *u.pb - 1;
  190. u.pb++;
  191. iPartOffsets = u.pi;
  192. }
  193. //---- allocate _pParts ----
  194. _pParts = new PARTINFO[_iMaxPart+1];
  195. if (! _pParts)
  196. {
  197. hr = MakeError32(E_OUTOFMEMORY);
  198. goto exit;
  199. }
  200. memset(_pParts, 0, sizeof(PARTINFO)*(_iMaxPart+1));
  201. if (fSingleObj)
  202. {
  203. for (int i=0; i <= _iMaxPart; i++)
  204. _pParts[i].iMaxState = 1; // dummy value
  205. if (pBaseObj) // single draw object to be used for all parts/states
  206. {
  207. for (int i=0; i <= _iMaxPart; i++)
  208. {
  209. _pParts[i].pDrawObj = pBaseObj;
  210. }
  211. }
  212. if (pTextObj) // single text object t to be used for all parts/states
  213. {
  214. for (int i=0; i <= _iMaxPart; i++)
  215. {
  216. _pParts[i].pTextObj = pTextObj;
  217. }
  218. }
  219. }
  220. else
  221. {
  222. u.pb = _pbThemeData + iPackedOffset;
  223. hr = WalkDrawObjects(u, iPartOffsets);
  224. if (FAILED(hr))
  225. goto exit;
  226. hr = WalkTextObjects(u, iPartOffsets);
  227. if (FAILED(hr))
  228. goto exit;
  229. }
  230. exit:
  231. return hr;
  232. }
  233. //---------------------------------------------------------------------------
  234. HRESULT CRenderObj::WalkDrawObjects(MIXEDPTRS &u, int *iPartOffsets)
  235. {
  236. int iPartId;
  237. int iStateId;
  238. HRESULT hr = S_OK;
  239. THEMEHDR *pHdr = (THEMEHDR *)_pbThemeData;
  240. UNPACKED_ENTRYHDR hdr;
  241. //---- get ptr to global text obj ----
  242. BYTE *pb = _pbThemeData + pHdr->iGlobalsDrawObjOffset;
  243. pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
  244. CDrawBase *pGlobalObj = (CDrawBase *)pb;
  245. //---- start with all parts inheriting from [globals] ----
  246. for (int i=0; i <= _iMaxPart; i++)
  247. _pParts[i].pDrawObj = pGlobalObj;
  248. //---- now, process all specified objects ----
  249. while (1)
  250. {
  251. if ((*u.ps == TMT_RGNLIST))
  252. {
  253. //---- skip over this entry ----
  254. FillAndSkipHdr(u, &hdr);
  255. u.pb += hdr.dwDataLen;
  256. continue;
  257. }
  258. if (*u.ps != TMT_DRAWOBJ)
  259. break;
  260. FillAndSkipHdr(u, &hdr);
  261. DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
  262. CDrawBase *pCurrentObj = (CDrawBase *)(u.pb + sizeof(DRAWOBJHDR));
  263. u.pb += hdr.dwDataLen;
  264. iPartId = ph->iPartNum;
  265. iStateId = ph->iStateNum;
  266. if ((! iPartId) && (! iStateId))
  267. {
  268. //---- all parts inherit from this obj ----
  269. for (int i=0; i <= _iMaxPart; i++)
  270. _pParts[i].pDrawObj = pCurrentObj;
  271. continue;
  272. }
  273. PARTINFO *ppi = &_pParts[iPartId];
  274. if (! iStateId)
  275. {
  276. ppi->pDrawObj = pCurrentObj;
  277. }
  278. else
  279. {
  280. if (! ppi->iMaxState) // extract MaxState
  281. {
  282. MIXEDPTRS u2;
  283. u2.pb = _pbThemeData + iPartOffsets[iPartId];
  284. if (*u2.ps != TMT_STATEJUMPTABLE)
  285. {
  286. hr = MakeError32(E_FAIL); // something went amiss
  287. goto exit;
  288. }
  289. u2.pb += ENTRYHDR_SIZE;
  290. ppi->iMaxState = *u2.pb - 1;
  291. }
  292. if (! ppi->pStateDrawObjs) // allocate now
  293. {
  294. ppi->pStateDrawObjs = new CDrawBase *[ppi->iMaxState];
  295. if (! ppi->pStateDrawObjs)
  296. {
  297. hr = MakeError32(E_OUTOFMEMORY);
  298. goto exit;
  299. }
  300. //---- fill in default objs as state 0 ----
  301. for (int i=0; i < ppi->iMaxState; i++)
  302. ppi->pStateDrawObjs[i] = ppi->pDrawObj;
  303. }
  304. ppi->pStateDrawObjs[iStateId-1] = pCurrentObj;
  305. }
  306. }
  307. exit:
  308. return hr;
  309. }
  310. //---------------------------------------------------------------------------
  311. HRESULT CRenderObj::WalkTextObjects(MIXEDPTRS &u, int *iPartOffsets)
  312. {
  313. int iPartId;
  314. int iStateId;
  315. HRESULT hr = S_OK;
  316. THEMEHDR *pHdr = (THEMEHDR *)_pbThemeData;
  317. UNPACKED_ENTRYHDR hdr;
  318. //---- get ptr to global text obj ----
  319. BYTE *pb = _pbThemeData + pHdr->iGlobalsTextObjOffset;
  320. pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
  321. CTextDraw *pGlobalObj = (CTextDraw *)pb;
  322. //---- start with all parts inheriting from [globals] ----
  323. for (int i=0; i <= _iMaxPart; i++)
  324. _pParts[i].pTextObj = pGlobalObj;
  325. while (*u.ps == TMT_TEXTOBJ)
  326. {
  327. FillAndSkipHdr(u, &hdr);
  328. DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
  329. CTextDraw *pCurrentObj = (CTextDraw *)(u.pb + sizeof(DRAWOBJHDR));
  330. u.pb += hdr.dwDataLen;
  331. iPartId = ph->iPartNum;
  332. iStateId = ph->iStateNum;
  333. if ((! iPartId) && (! iStateId))
  334. {
  335. //---- all parts inherit from this obj ----
  336. for (int i=0; i <= _iMaxPart; i++)
  337. _pParts[i].pTextObj = pCurrentObj;
  338. continue;
  339. }
  340. PARTINFO *ppi = &_pParts[iPartId];
  341. if (! iStateId)
  342. {
  343. ppi->pTextObj = pCurrentObj;
  344. }
  345. else
  346. {
  347. if (! ppi->iMaxState) // extract MaxState
  348. {
  349. MIXEDPTRS u2;
  350. u2.pb = _pbThemeData + iPartOffsets[iPartId];
  351. if (*u2.ps != TMT_STATEJUMPTABLE)
  352. {
  353. hr = MakeError32(E_FAIL); // something went amiss
  354. goto exit;
  355. }
  356. u2.pb += ENTRYHDR_SIZE;
  357. ppi->iMaxState = *u2.pb - 1;
  358. }
  359. if (! ppi->pStateTextObjs) // allocate now
  360. {
  361. ppi->pStateTextObjs = new CTextDraw *[ppi->iMaxState];
  362. if (! ppi->pStateTextObjs)
  363. {
  364. hr = MakeError32(E_OUTOFMEMORY);
  365. goto exit;
  366. }
  367. //---- fill in default objs as state 0 ----
  368. for (int i=0; i < ppi->iMaxState; i++)
  369. ppi->pStateTextObjs[i] = ppi->pTextObj;
  370. }
  371. ppi->pStateTextObjs[iStateId-1] = pCurrentObj;
  372. }
  373. }
  374. exit:
  375. return hr;
  376. }
  377. //---------------------------------------------------------------------------
  378. HRESULT CRenderObj::GetBitmap(HDC hdc, int iDibOffset, OUT HBITMAP *phBitmap)
  379. {
  380. HRESULT hr = S_OK;
  381. HBITMAP hBitmap;
  382. if ((! iDibOffset) || (! _pbThemeData))
  383. {
  384. hr = E_FAIL;
  385. goto exit;
  386. }
  387. TMBITMAPHEADER *pThemeBitmapHeader;
  388. pThemeBitmapHeader = reinterpret_cast<TMBITMAPHEADER*>(_pbThemeData + iDibOffset);
  389. ASSERT(pThemeBitmapHeader->dwSize == TMBITMAPSIZE);
  390. *phBitmap = pThemeBitmapHeader->hBitmap;
  391. if (*phBitmap != NULL)
  392. {
  393. //Log(LOG_TMBITMAP, L"Used stock bitmap:%8X", *phBitmap);
  394. return hr;
  395. }
  396. hr = CreateBitmapFromData(hdc, iDibOffset + TMBITMAPSIZE, &hBitmap);
  397. if (FAILED(hr))
  398. goto exit;
  399. Log(LOG_TM, L"GetBitmap - CACHE MISS: class=%s, diboffset=%d, bitmap=0x%x",
  400. SHARECLASS(this), iDibOffset, hBitmap);
  401. *phBitmap = hBitmap;
  402. exit:
  403. return hr;
  404. }
  405. //---------------------------------------------------------------------------
  406. void CRenderObj::ReturnBitmap(HBITMAP hBitmap)
  407. {
  408. DeleteObject(hBitmap);
  409. }
  410. //---------------------------------------------------------------------------
  411. HRESULT CRenderObj::CreateBitmapFromData(HDC hdc, int iDibOffset, OUT HBITMAP *phBitmap)
  412. {
  413. BYTE *pDibData;
  414. RESOURCE HDC hdcTemp = NULL;
  415. RESOURCE HBITMAP hBitmap = NULL;
  416. HRESULT hr = S_OK;
  417. if ((! iDibOffset) || (! _pbThemeData))
  418. {
  419. hr = E_FAIL;
  420. goto exit;
  421. }
  422. pDibData = (BYTE *)(_pbThemeData + iDibOffset);
  423. BITMAPINFOHEADER *pBitmapHdr;
  424. pBitmapHdr = (BITMAPINFOHEADER *)pDibData;
  425. BOOL fAlphaChannel;
  426. fAlphaChannel = (pBitmapHdr->biBitCount == 32);
  427. if (! hdc)
  428. {
  429. hdcTemp = GetWindowDC(NULL);
  430. if (! hdcTemp)
  431. {
  432. Log(LOG_ALWAYS, L"GetWindowDC() failed in CreateBitmapFromData");
  433. hr = MakeErrorLast();
  434. goto exit;
  435. }
  436. hdc = hdcTemp;
  437. }
  438. //---- create the actual bitmap ----
  439. //---- if using alpha channel, we must use a DIB ----
  440. if (fAlphaChannel)
  441. {
  442. void *pv;
  443. hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)pBitmapHdr, DIB_RGB_COLORS,
  444. &pv, NULL, 0);
  445. }
  446. else
  447. {
  448. hBitmap = CreateCompatibleBitmap(hdc, pBitmapHdr->biWidth, pBitmapHdr->biHeight);
  449. }
  450. if (! hBitmap)
  451. {
  452. hr = MakeErrorLast();
  453. goto exit;
  454. }
  455. int iSetVal;
  456. //---- SetDIBits() can take unaligned data, right? ----
  457. iSetVal = SetDIBits(hdc, hBitmap, 0, pBitmapHdr->biHeight, DIBDATA(pBitmapHdr), (BITMAPINFO *)pBitmapHdr,
  458. DIB_RGB_COLORS);
  459. if (! iSetVal)
  460. {
  461. hr = MakeErrorLast();
  462. goto exit;
  463. }
  464. *phBitmap = hBitmap;
  465. #ifdef DEBUG
  466. if (hBitmap)
  467. {
  468. BITMAP bm;
  469. GetObject(hBitmap, sizeof bm, &bm);
  470. s_dwSize += bm.bmWidthBytes * bm.bmHeight;
  471. //Log(LOG_TMBITMAP, L"Created a bitmap of %d bytes. total is %d", bm.bmWidthBytes * bm.bmHeight, s_dwSize);
  472. }
  473. #endif
  474. exit:
  475. if (hdcTemp)
  476. ReleaseDC(NULL, hdcTemp);
  477. if (FAILED(hr))
  478. {
  479. if (hBitmap)
  480. DeleteObject(hBitmap);
  481. }
  482. return hr;
  483. }
  484. //---------------------------------------------------------------------------
  485. HRESULT CRenderObj::GetScaledFontHandle(HDC hdc, LOGFONT *plf, HFONT *phFont)
  486. {
  487. HRESULT hr = S_OK;
  488. if (_fCacheEnabled)
  489. {
  490. CRenderCache *pCacheObj = GetTlsCacheObj();
  491. if (pCacheObj)
  492. hr = pCacheObj->GetScaledFontHandle(hdc, plf, phFont);
  493. }
  494. else
  495. {
  496. LOGFONT lf = *plf;
  497. //---- convert to current screen dpi ----
  498. ScaleFontForHdcDpi(hdc, &lf);
  499. *phFont = CreateFontIndirect(&lf);
  500. if (! *phFont)
  501. hr = MakeError32(E_OUTOFMEMORY);
  502. }
  503. return hr;
  504. }
  505. //---------------------------------------------------------------------------
  506. void CRenderObj::ReturnFontHandle(HFONT hFont)
  507. {
  508. if (_fCacheEnabled)
  509. {
  510. //--- cache currently doesn't refcnt so save time by not calling ---
  511. //CRenderCache *pCacheObj = GetTlsCacheObj();
  512. //if (pCacheObj)
  513. //{
  514. //pCacheObj->ReturnFontHandle(hFont);
  515. //goto exit;
  516. //}
  517. }
  518. else
  519. {
  520. DeleteObject(hFont);
  521. }
  522. }
  523. //---------------------------------------------------------------------------
  524. HRESULT CRenderObj::PrepareRegionDataForScaling(
  525. RGNDATA *pRgnData, LPCRECT prcImage, MARGINS *pMargins)
  526. {
  527. //---- compute margin values ----
  528. int sw = prcImage->left;
  529. int lw = prcImage->left + pMargins->cxLeftWidth;
  530. int rw = prcImage->right - pMargins->cxRightWidth;
  531. int sh = prcImage->top;
  532. int th = prcImage->top + pMargins->cyTopHeight;
  533. int bh = prcImage->bottom - pMargins->cyBottomHeight;
  534. //---- step thru region data & customize it ----
  535. //---- classify each POINT according to a gridnum and ----
  536. //---- make it 0-relative to its grid location ----
  537. POINT *pt = (POINT *)pRgnData->Buffer;
  538. BYTE *pByte = (BYTE *)pRgnData->Buffer + pRgnData->rdh.nRgnSize;
  539. int iCount = 2 * pRgnData->rdh.nCount;
  540. for (int i=0; i < iCount; i++, pt++, pByte++)
  541. {
  542. if (pt->x < lw)
  543. {
  544. pt->x -= sw;
  545. if (pt->y < th) // left top
  546. {
  547. *pByte = GN_LEFTTOP;
  548. pt->y -= sh;
  549. }
  550. else if (pt->y < bh) // left middle
  551. {
  552. *pByte = GN_LEFTMIDDLE;
  553. pt->y -= th;
  554. }
  555. else // left bottom
  556. {
  557. *pByte = GN_LEFTBOTTOM;
  558. pt->y -= bh;
  559. }
  560. }
  561. else if (pt->x < rw)
  562. {
  563. pt->x -= lw;
  564. if (pt->y < th) // middle top
  565. {
  566. *pByte = GN_MIDDLETOP;
  567. pt->y -= sh;
  568. }
  569. else if (pt->y < bh) // middle middle
  570. {
  571. *pByte = GN_MIDDLEMIDDLE;
  572. pt->y -= th;
  573. }
  574. else // middle bottom
  575. {
  576. *pByte = GN_MIDDLEBOTTOM;
  577. pt->y -= bh;
  578. }
  579. }
  580. else
  581. {
  582. pt->x -= rw;
  583. if (pt->y < th) // right top
  584. {
  585. *pByte = GN_RIGHTTOP;
  586. pt->y -= sh;
  587. }
  588. else if (pt->y < bh) // right middle
  589. {
  590. *pByte = GN_RIGHTMIDDLE;
  591. pt->y -= th;
  592. }
  593. else // right bottom
  594. {
  595. *pByte = GN_RIGHTBOTTOM;
  596. pt->y -= bh;
  597. }
  598. }
  599. }
  600. return S_OK;
  601. }
  602. //---------------------------------------------------------------------------
  603. HRESULT CRenderObj::GetColor(int iPartId, int iStateId, int iPropId, COLORREF *pColor)
  604. {
  605. if (! pColor)
  606. return MakeError32(E_INVALIDARG);
  607. int index = GetValueIndex(iPartId, iStateId, iPropId);
  608. if (index < 0) // not found
  609. return MakeError32(ERROR_NOT_FOUND);
  610. MIXEDPTRS u;
  611. u.pb = _pbThemeData + index; // point at data
  612. *pColor = *u.pi;
  613. return S_OK;
  614. }
  615. //---------------------------------------------------------------------------
  616. HRESULT CRenderObj::GetString(int iPartId, int iStateId, int iPropId,
  617. LPWSTR pszBuff, DWORD cchBuff)
  618. {
  619. if (! pszBuff)
  620. return MakeError32(E_INVALIDARG);
  621. int index = GetValueIndex(iPartId, iStateId, iPropId);
  622. if (index < 0)
  623. return MakeError32(ERROR_NOT_FOUND);
  624. MIXEDPTRS u;
  625. u.pb = _pbThemeData + index - sizeof(int); // point at length
  626. DWORD len = *u.pdw++;
  627. len /= sizeof(WCHAR); // adjust to characters
  628. HRESULT hr = SafeStringCchCopyW(pszBuff, cchBuff, u.pw );
  629. return hr;
  630. }
  631. //---------------------------------------------------------------------------
  632. HRESULT CRenderObj::GetBool(int iPartId, int iStateId, int iPropId, BOOL *pfVal)
  633. {
  634. if (! pfVal)
  635. return MakeError32(E_INVALIDARG);
  636. int index = GetValueIndex(iPartId, iStateId, iPropId);
  637. if (index < 0)
  638. return MakeError32(ERROR_NOT_FOUND);
  639. MIXEDPTRS u;
  640. u.pb = _pbThemeData + index; // point at data
  641. *pfVal = *u.pb;
  642. return S_OK;
  643. }
  644. //---------------------------------------------------------------------------
  645. HRESULT CRenderObj::GetInt(int iPartId, int iStateId, int iPropId, int *piVal)
  646. {
  647. if (! piVal)
  648. return MakeError32(E_INVALIDARG);
  649. int index = GetValueIndex(iPartId, iStateId, iPropId);
  650. if (index < 0)
  651. return MakeError32(ERROR_NOT_FOUND);
  652. MIXEDPTRS u;
  653. u.pb = _pbThemeData + index; // point at data
  654. *piVal = *u.pi;
  655. return S_OK;
  656. }
  657. //---------------------------------------------------------------------------
  658. static int iMetricDefaults[] =
  659. {
  660. 1, // TMT_BORDERWIDTH
  661. 18, // TMT_VERTSCROLLWIDTH
  662. 18, // TMT_HORZSCROLLHEIGHT
  663. 27, // TMT_CAPTIONBUTTONWIDTH
  664. 27, // TMT_CAPTIONBUTTONHEIGHT
  665. 22, // TMT_SMCAPTIONBUTTONWIDTH
  666. 22, // TMT_SMCAPTIONBUTTONHEIGHT
  667. 22, // TMT_MENUBUTTONWIDTH
  668. 22, // TMT_MENUBUTTONHEIGHT
  669. };
  670. //---------------------------------------------------------------------------
  671. HRESULT CRenderObj::GetMetric(OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, int *piVal)
  672. {
  673. if (! piVal)
  674. return MakeError32(E_INVALIDARG);
  675. int index = GetValueIndex(iPartId, iStateId, iPropId);
  676. int value;
  677. if (index >= 0) // found
  678. {
  679. MIXEDPTRS u;
  680. u.pb = _pbThemeData + index; // point at data
  681. value = *u.pi;
  682. }
  683. else
  684. return MakeError32(ERROR_NOT_FOUND);
  685. *piVal = ScaleSizeForHdcDpi(hdc, value);
  686. return S_OK;
  687. }
  688. //---------------------------------------------------------------------------
  689. HRESULT CRenderObj::GetEnumValue(int iPartId, int iStateId, int iPropId, int *piVal)
  690. {
  691. if (! piVal)
  692. return MakeError32(E_INVALIDARG);
  693. int index = GetValueIndex(iPartId, iStateId, iPropId);
  694. if (index < 0)
  695. return MakeError32(ERROR_NOT_FOUND);
  696. MIXEDPTRS u;
  697. u.pb = _pbThemeData + index; // point at data
  698. *piVal = *u.pi;
  699. return S_OK;
  700. }
  701. //---------------------------------------------------------------------------
  702. HRESULT CRenderObj::GetPosition(int iPartId, int iStateId, int iPropId, POINT *pPoint)
  703. {
  704. if (! pPoint)
  705. return MakeError32(E_INVALIDARG);
  706. int index = GetValueIndex(iPartId, iStateId, iPropId);
  707. if (index < 0)
  708. return MakeError32(ERROR_NOT_FOUND);
  709. MIXEDPTRS u;
  710. u.pb = _pbThemeData + index; // point at data
  711. pPoint->x = *u.pi++;
  712. pPoint->y = *u.pi++;
  713. return S_OK;
  714. }
  715. //---------------------------------------------------------------------------
  716. HRESULT CRenderObj::GetFont(OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId,
  717. BOOL fWantHdcScaling, LOGFONT *pFont)
  718. {
  719. if (! pFont)
  720. return MakeError32(E_INVALIDARG);
  721. int index = GetValueIndex(iPartId, iStateId, iPropId);
  722. if (index < 0)
  723. return MakeError32(ERROR_NOT_FOUND);
  724. MIXEDPTRS u;
  725. u.pb = _pbThemeData + index; // point at data
  726. *pFont = *(LOGFONT *)u.pb;
  727. if (fWantHdcScaling)
  728. {
  729. ScaleFontForHdcDpi(hdc, pFont);
  730. }
  731. return S_OK;
  732. }
  733. //---------------------------------------------------------------------------
  734. HRESULT CRenderObj::GetMargins(OPTIONAL HDC hdc, int iPartId, int iStateId,
  735. int iPropId, OPTIONAL RECT *prc, MARGINS *pMargins)
  736. {
  737. //---- return unscaled margins ----
  738. if (! pMargins)
  739. return MakeError32(E_INVALIDARG);
  740. int index = GetValueIndex(iPartId, iStateId, iPropId);
  741. if (index < 0)
  742. return MakeError32(ERROR_NOT_FOUND);
  743. MIXEDPTRS u;
  744. u.pb = _pbThemeData + index; // point at data
  745. pMargins->cxLeftWidth = *u.pi++;
  746. pMargins->cxRightWidth = *u.pi++;
  747. pMargins->cyTopHeight = *u.pi++;
  748. pMargins->cyBottomHeight = *u.pi++;
  749. return S_OK;
  750. }
  751. //---------------------------------------------------------------------------
  752. HRESULT CRenderObj::GetIntList(int iPartId, int iStateId, int iPropId, INTLIST *pIntList)
  753. {
  754. if (! pIntList)
  755. return MakeError32(E_INVALIDARG);
  756. int index = GetValueIndex(iPartId, iStateId, iPropId);
  757. if (index < 0)
  758. return MakeError32(ERROR_NOT_FOUND);
  759. MIXEDPTRS u;
  760. u.pb = _pbThemeData + index; // point at data
  761. int iCount = *u.pi++;
  762. if (iCount > MAX_INTLIST_COUNT)
  763. {
  764. Log(LOG_ALWAYS, L"GetIntList() found bad theme data - Count=%d", iCount);
  765. return MakeError32(ERROR_NOT_FOUND);
  766. }
  767. pIntList->iValueCount = iCount;
  768. for (int i=0; i < iCount; i++)
  769. pIntList->iValues[i] = *u.pi++;
  770. return S_OK;
  771. }
  772. //---------------------------------------------------------------------------
  773. HRESULT CRenderObj::GetRect(int iPartId, int iStateId, int iPropId, RECT *pRect)
  774. {
  775. if (! pRect)
  776. return MakeError32(E_INVALIDARG);
  777. int index = GetValueIndex(iPartId, iStateId, iPropId);
  778. if (index < 0)
  779. return MakeError32(ERROR_NOT_FOUND);
  780. MIXEDPTRS u;
  781. u.pb = _pbThemeData + index; // point at data
  782. pRect->left = *u.pi++;
  783. pRect->top = *u.pi++;
  784. pRect->right = *u.pi++;
  785. pRect->bottom = *u.pi++;
  786. return S_OK;
  787. }
  788. //---------------------------------------------------------------------------
  789. HRESULT CRenderObj::GetFilename(int iPartId, int iStateId, int iPropId, LPWSTR pszBuff,
  790. DWORD cchBuff)
  791. {
  792. if (! pszBuff)
  793. return MakeError32(E_INVALIDARG);
  794. int index = GetValueIndex(iPartId, iStateId, iPropId);
  795. if (index < 0)
  796. return MakeError32(ERROR_NOT_FOUND);
  797. MIXEDPTRS u;
  798. u.pb = _pbThemeData + index - sizeof(int); // point at length
  799. DWORD len = *u.pdw++;
  800. len /= sizeof(WCHAR); // adjust to chars size
  801. HRESULT hr = SafeStringCchCopyW(pszBuff, cchBuff, u.pw);
  802. return hr;
  803. }
  804. //---------------------------------------------------------------------------
  805. HRESULT CRenderObj::GetData(int iPartId, int iStateId, int iPropId, BYTE **ppData,
  806. OPTIONAL int *piSize)
  807. {
  808. if (! ppData)
  809. return MakeError32(E_INVALIDARG);
  810. int index = GetValueIndex(iPartId, iStateId, iPropId);
  811. if (index < 0)
  812. return MakeError32(ERROR_NOT_FOUND);
  813. MIXEDPTRS u;
  814. u.pb = _pbThemeData + index - sizeof(int); // point at length
  815. DWORD len = *u.pdw++;
  816. *ppData = u.pb;
  817. if (piSize)
  818. *piSize = len;
  819. return S_OK;
  820. }
  821. //---------------------------------------------------------------------------
  822. int CRenderObj::GetValueIndex(int iPartId, int iStateId, int iTarget)
  823. {
  824. if (! iTarget)
  825. {
  826. Log(LOG_PARAMS, L"Invalid iProperyId passed to GetValueIndex: %d", iTarget);
  827. return -1;
  828. }
  829. if (! _pbSectionData)
  830. {
  831. return -1;
  832. }
  833. MIXEDPTRS u;
  834. int index;
  835. u.pb = _pbSectionData;
  836. //---- find end of data ----
  837. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  838. BYTE *pbLastValidChar = _pbThemeData + (hdr->dwTotalLength - 1) - kcbEndSignature;
  839. while (u.pb <= pbLastValidChar)
  840. {
  841. UNPACKED_ENTRYHDR hdr;
  842. FillAndSkipHdr(u, &hdr);
  843. if (hdr.usTypeNum == TMT_PARTJUMPTABLE)
  844. {
  845. u.pi++; // skip over offset to first drawobj
  846. BYTE cnt = *u.pb++;
  847. if ((iPartId < 0) || (iPartId >= cnt))
  848. {
  849. index = u.pi[0];
  850. }
  851. else
  852. {
  853. index = u.pi[iPartId];
  854. if (index == -1)
  855. index = u.pi[0];
  856. }
  857. u.pb = _pbThemeData + index;
  858. continue;
  859. }
  860. if (hdr.usTypeNum == (BYTE)TMT_STATEJUMPTABLE)
  861. {
  862. BYTE cnt = *u.pb++;
  863. if ((iStateId < 0) || (iStateId >= cnt))
  864. index = u.pi[0];
  865. else
  866. {
  867. index = u.pi[iStateId];
  868. if (index == -1)
  869. index = u.pi[0];
  870. }
  871. u.pb = _pbThemeData + index;
  872. continue;
  873. }
  874. if (hdr.usTypeNum == iTarget) // got our target
  875. {
  876. // Log("GetValueIndex: match at index=%d", u.pb - _pbThemeData);
  877. return (int)(u.pb - _pbThemeData); // point at actual data (not hdr)
  878. }
  879. if (hdr.ePrimVal == TMT_JUMPTOPARENT)
  880. {
  881. index = *u.pi;
  882. if (index == -1)
  883. {
  884. // Log("no match found");
  885. return -1;
  886. }
  887. // Log("GetValueIndex: jumping to parent at index=%d", index);
  888. u.pb = _pbThemeData + index;
  889. continue;
  890. }
  891. // Log("GetValueIndex: no match to hdr.usTypeNum=%d", hdr.usTypeNum);
  892. // advance to next value
  893. u.pb += hdr.dwDataLen;
  894. }
  895. //---- something went wrong ----
  896. Log(LOG_ERROR, L"GetValueIndex: ran off the valid data without a '-1' jump");
  897. return -1;
  898. }
  899. //---------------------------------------------------------------------------
  900. HRESULT CRenderObj::GetPropertyOrigin(int iPartId, int iStateId, int iTarget,
  901. PROPERTYORIGIN *pOrigin)
  902. {
  903. if (! iTarget)
  904. {
  905. Log(LOG_PARAMS, L"Invalid iProperyId passed to GetPropertyOrigin: %d", iTarget);
  906. return E_FAIL;
  907. }
  908. if (! _pbSectionData)
  909. {
  910. return E_FAIL;
  911. }
  912. MIXEDPTRS u;
  913. if (! pOrigin)
  914. return MakeError32(E_INVALIDARG);
  915. //---- start at our section ----
  916. u.pb = _pbSectionData;
  917. PROPERTYORIGIN origin = PO_CLASS;
  918. //---- find end of data ----
  919. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  920. BYTE *pbLastValidChar = _pbThemeData + (hdr->dwTotalLength - 1) - kcbEndSignature;
  921. while (u.pb <= pbLastValidChar)
  922. {
  923. UNPACKED_ENTRYHDR hdr;
  924. FillAndSkipHdr(u, &hdr);
  925. if (hdr.usTypeNum == TMT_PARTJUMPTABLE)
  926. {
  927. u.pi++; // skip over offset to first drawobj
  928. BYTE cnt = *u.pb++;
  929. int index;
  930. if ((iPartId <= 0) || (iPartId >= cnt))
  931. {
  932. index = u.pi[0];
  933. }
  934. else
  935. {
  936. index = u.pi[iPartId];
  937. if (index == -1)
  938. index = u.pi[0];
  939. }
  940. if (index == u.pi[0])
  941. origin = PO_CLASS;
  942. else
  943. origin = PO_PART;
  944. u.pb = _pbThemeData + index;
  945. continue;
  946. }
  947. if (hdr.usTypeNum == TMT_STATEJUMPTABLE)
  948. {
  949. BYTE cnt = *u.pb++;
  950. int index;
  951. if ((iStateId <= 0) || (iStateId >= cnt))
  952. {
  953. index = u.pi[0];
  954. }
  955. else
  956. {
  957. index = u.pi[iStateId];
  958. if (index == -1)
  959. index = u.pi[0];
  960. }
  961. if (index != u.pi[0])
  962. origin = PO_STATE;
  963. u.pb = _pbThemeData + index;
  964. continue;
  965. }
  966. //Log("GetPropertyOrgin: iPartId=%d, iTarget=%d, DataIndex=%d",
  967. // iPartId, iTarget, u.pb - _pbThemeData);
  968. if ((iTarget == -1) || (hdr.usTypeNum == iTarget)) // got our target
  969. {
  970. // Log("GetPropertyOrgin: match at index=%d", u.pb - _pbThemeData);
  971. *pOrigin = origin;
  972. return S_OK;
  973. }
  974. if (hdr.ePrimVal == TMT_JUMPTOPARENT)
  975. {
  976. int index = *u.pi;
  977. if (index == -1)
  978. {
  979. // Log("GetPropertyOrgin: no match found");
  980. *pOrigin = PO_NOTFOUND;
  981. return S_OK;
  982. }
  983. // Log("GetPropertyOrgin: jumping to parent at index=%d", index);
  984. u.pb = _pbThemeData + index;
  985. origin = (PROPERTYORIGIN) (origin + 1); // move down to next level of heirarchy
  986. continue;
  987. }
  988. // advance to next value
  989. u.pb += hdr.dwDataLen;
  990. }
  991. //---- something went wrong ----
  992. Log(LOG_ERROR, L"GetPropertyOrigin: ran off the valid data without a '-1' jump");
  993. return E_FAIL;
  994. }
  995. //---------------------------------------------------------------------------
  996. BOOL WINAPI CRenderObj::IsPartDefined(int iPartId, int iStateId)
  997. {
  998. PROPERTYORIGIN origin;
  999. HRESULT hr = GetPropertyOrigin(iPartId, iStateId, -1, &origin);
  1000. SET_LAST_ERROR(hr);
  1001. if (FAILED(hr))
  1002. {
  1003. return FALSE;
  1004. }
  1005. if (iStateId)
  1006. return (origin == PO_STATE);
  1007. return (origin == PO_PART);
  1008. }
  1009. //---------------------------------------------------------------------------
  1010. BOOL CRenderObj::ValidateObj()
  1011. {
  1012. BOOL fValid = TRUE;
  1013. //---- check object quickly ----
  1014. if ( (! this)
  1015. || (ULONGAT(_szHead) != 'dner') // "rend"
  1016. || (ULONGAT(&_szHead[4]) != 'jbo') // "obj"
  1017. || (ULONGAT(_szTail) != 'dne')) // "end"
  1018. {
  1019. Log(LOG_ALWAYS, L"CRenderObj is corrupt, addr=0x%08x", this);
  1020. fValid = FALSE;
  1021. }
  1022. return fValid;
  1023. }
  1024. //---------------------------------------------------------------------------
  1025. CRenderCache *CRenderObj::GetTlsCacheObj()
  1026. {
  1027. HRESULT hr = S_OK;
  1028. CRenderCache *pCacheObj = NULL;
  1029. CCacheList *pcl = GetTlsCacheList(TRUE);
  1030. if (pcl)
  1031. hr = pcl->GetCacheObject(this, _iCacheSlot, &pCacheObj);
  1032. return pCacheObj;
  1033. }