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.

1461 lines
39 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. strcpy(_szHead, "rendobj");
  47. strcpy(_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. strcpy(_szHead, "deleted");
  159. }
  160. //---------------------------------------------------------------------------
  161. HRESULT CRenderObj::SetDpiOverride(int iDpiOverride)
  162. {
  163. _iDpiOverride = iDpiOverride;
  164. return S_OK;
  165. }
  166. //---------------------------------------------------------------------------
  167. int CRenderObj::GetDpiOverride()
  168. {
  169. return _iDpiOverride;
  170. }
  171. //---------------------------------------------------------------------------
  172. HRESULT CRenderObj::BuildPackedPtrs(CDrawBase *pBaseObj, CTextDraw *pTextObj)
  173. {
  174. MIXEDPTRS u;
  175. HRESULT hr = S_OK;
  176. int iPackedOffset = 0;
  177. int *iPartOffsets = NULL;
  178. BOOL fSingleObj = FALSE;
  179. //---- extract _iMaxPart ----
  180. if ((pBaseObj) || (pTextObj)) // single object to be used for all parts/states
  181. {
  182. _iMaxPart = 1; // dummy value
  183. fSingleObj = TRUE;
  184. }
  185. else
  186. {
  187. u.pb = _pbSectionData;
  188. if (*u.ps != TMT_PARTJUMPTABLE)
  189. {
  190. hr = MakeError32(E_FAIL); // something went amiss
  191. goto exit;
  192. }
  193. u.pb += ENTRYHDR_SIZE;
  194. iPackedOffset = *u.pi++;
  195. _iMaxPart = *u.pb - 1;
  196. u.pb++;
  197. iPartOffsets = u.pi;
  198. }
  199. //---- allocate _pParts ----
  200. _pParts = new PARTINFO[_iMaxPart+1];
  201. if (! _pParts)
  202. {
  203. hr = MakeError32(E_OUTOFMEMORY);
  204. goto exit;
  205. }
  206. memset(_pParts, 0, sizeof(PARTINFO)*(_iMaxPart+1));
  207. if (fSingleObj)
  208. {
  209. for (int i=0; i <= _iMaxPart; i++)
  210. _pParts[i].iMaxState = 1; // dummy value
  211. if (pBaseObj) // single draw object to be used for all parts/states
  212. {
  213. for (int i=0; i <= _iMaxPart; i++)
  214. {
  215. _pParts[i].pDrawObj = pBaseObj;
  216. }
  217. }
  218. if (pTextObj) // single text object t to be used for all parts/states
  219. {
  220. for (int i=0; i <= _iMaxPart; i++)
  221. {
  222. _pParts[i].pTextObj = pTextObj;
  223. }
  224. }
  225. }
  226. else
  227. {
  228. u.pb = _pbThemeData + iPackedOffset;
  229. hr = WalkDrawObjects(u, iPartOffsets);
  230. if (FAILED(hr))
  231. goto exit;
  232. hr = WalkTextObjects(u, iPartOffsets);
  233. if (FAILED(hr))
  234. goto exit;
  235. }
  236. exit:
  237. return hr;
  238. }
  239. //---------------------------------------------------------------------------
  240. HRESULT CRenderObj::WalkDrawObjects(MIXEDPTRS &u, int *iPartOffsets)
  241. {
  242. int iPartId;
  243. int iStateId;
  244. HRESULT hr = S_OK;
  245. THEMEHDR *pHdr = (THEMEHDR *)_pbThemeData;
  246. UNPACKED_ENTRYHDR hdr;
  247. //---- get ptr to global text obj ----
  248. BYTE *pb = _pbThemeData + pHdr->iGlobalsDrawObjOffset;
  249. pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
  250. CDrawBase *pGlobalObj = (CDrawBase *)pb;
  251. //---- start with all parts inheriting from [globals] ----
  252. for (int i=0; i <= _iMaxPart; i++)
  253. _pParts[i].pDrawObj = pGlobalObj;
  254. //---- now, process all specified objects ----
  255. while (1)
  256. {
  257. if ((*u.ps == TMT_RGNLIST) || (*u.ps == TMT_STOCKBRUSHES))
  258. {
  259. //---- skip over this entry ----
  260. FillAndSkipHdr(u, &hdr);
  261. u.pb += hdr.dwDataLen;
  262. continue;
  263. }
  264. if (*u.ps != TMT_DRAWOBJ)
  265. break;
  266. FillAndSkipHdr(u, &hdr);
  267. DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
  268. CDrawBase *pCurrentObj = (CDrawBase *)(u.pb + sizeof(DRAWOBJHDR));
  269. u.pb += hdr.dwDataLen;
  270. iPartId = ph->iPartNum;
  271. iStateId = ph->iStateNum;
  272. if ((! iPartId) && (! iStateId))
  273. {
  274. //---- all parts inherit from this obj ----
  275. for (int i=0; i <= _iMaxPart; i++)
  276. _pParts[i].pDrawObj = pCurrentObj;
  277. continue;
  278. }
  279. PARTINFO *ppi = &_pParts[iPartId];
  280. if (! iStateId)
  281. {
  282. ppi->pDrawObj = pCurrentObj;
  283. }
  284. else
  285. {
  286. if (! ppi->iMaxState) // extract MaxState
  287. {
  288. MIXEDPTRS u2;
  289. u2.pb = _pbThemeData + iPartOffsets[iPartId];
  290. if (*u2.ps != TMT_STATEJUMPTABLE)
  291. {
  292. hr = MakeError32(E_FAIL); // something went amiss
  293. goto exit;
  294. }
  295. u2.pb += ENTRYHDR_SIZE;
  296. ppi->iMaxState = *u2.pb - 1;
  297. }
  298. if (! ppi->pStateDrawObjs) // allocate now
  299. {
  300. ppi->pStateDrawObjs = new CDrawBase *[ppi->iMaxState];
  301. if (! ppi->pStateDrawObjs)
  302. {
  303. hr = MakeError32(E_OUTOFMEMORY);
  304. goto exit;
  305. }
  306. //---- fill in default objs as state 0 ----
  307. for (int i=0; i < ppi->iMaxState; i++)
  308. ppi->pStateDrawObjs[i] = ppi->pDrawObj;
  309. }
  310. ppi->pStateDrawObjs[iStateId-1] = pCurrentObj;
  311. }
  312. }
  313. exit:
  314. return hr;
  315. }
  316. //---------------------------------------------------------------------------
  317. HRESULT CRenderObj::WalkTextObjects(MIXEDPTRS &u, int *iPartOffsets)
  318. {
  319. int iPartId;
  320. int iStateId;
  321. HRESULT hr = S_OK;
  322. THEMEHDR *pHdr = (THEMEHDR *)_pbThemeData;
  323. UNPACKED_ENTRYHDR hdr;
  324. //---- get ptr to global text obj ----
  325. BYTE *pb = _pbThemeData + pHdr->iGlobalsTextObjOffset;
  326. pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
  327. CTextDraw *pGlobalObj = (CTextDraw *)pb;
  328. //---- start with all parts inheriting from [globals] ----
  329. for (int i=0; i <= _iMaxPart; i++)
  330. _pParts[i].pTextObj = pGlobalObj;
  331. while (*u.ps == TMT_TEXTOBJ)
  332. {
  333. FillAndSkipHdr(u, &hdr);
  334. DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
  335. CTextDraw *pCurrentObj = (CTextDraw *)(u.pb + sizeof(DRAWOBJHDR));
  336. u.pb += hdr.dwDataLen;
  337. iPartId = ph->iPartNum;
  338. iStateId = ph->iStateNum;
  339. if ((! iPartId) && (! iStateId))
  340. {
  341. //---- all parts inherit from this obj ----
  342. for (int i=0; i <= _iMaxPart; i++)
  343. _pParts[i].pTextObj = pCurrentObj;
  344. continue;
  345. }
  346. PARTINFO *ppi = &_pParts[iPartId];
  347. if (! iStateId)
  348. {
  349. ppi->pTextObj = pCurrentObj;
  350. }
  351. else
  352. {
  353. if (! ppi->iMaxState) // extract MaxState
  354. {
  355. MIXEDPTRS u2;
  356. u2.pb = _pbThemeData + iPartOffsets[iPartId];
  357. if (*u2.ps != TMT_STATEJUMPTABLE)
  358. {
  359. hr = MakeError32(E_FAIL); // something went amiss
  360. goto exit;
  361. }
  362. u2.pb += ENTRYHDR_SIZE;
  363. ppi->iMaxState = *u2.pb - 1;
  364. }
  365. if (! ppi->pStateTextObjs) // allocate now
  366. {
  367. ppi->pStateTextObjs = new CTextDraw *[ppi->iMaxState];
  368. if (! ppi->pStateTextObjs)
  369. {
  370. hr = MakeError32(E_OUTOFMEMORY);
  371. goto exit;
  372. }
  373. //---- fill in default objs as state 0 ----
  374. for (int i=0; i < ppi->iMaxState; i++)
  375. ppi->pStateTextObjs[i] = ppi->pTextObj;
  376. }
  377. ppi->pStateTextObjs[iStateId-1] = pCurrentObj;
  378. }
  379. }
  380. exit:
  381. return hr;
  382. }
  383. //---------------------------------------------------------------------------
  384. HRESULT CRenderObj::GetBitmap(HDC hdc, int iDibOffset, OUT HBITMAP *phBitmap)
  385. {
  386. HRESULT hr = S_OK;
  387. HBITMAP hBitmap;
  388. if ((! iDibOffset) || (! _pbThemeData))
  389. {
  390. hr = E_FAIL;
  391. goto exit;
  392. }
  393. TMBITMAPHEADER *pThemeBitmapHeader;
  394. pThemeBitmapHeader = reinterpret_cast<TMBITMAPHEADER*>(_pbThemeData + iDibOffset);
  395. ASSERT(pThemeBitmapHeader->dwSize == TMBITMAPSIZE);
  396. *phBitmap = pThemeBitmapHeader->hBitmap;
  397. if (*phBitmap != NULL)
  398. {
  399. //Log(LOG_TMBITMAP, L"Used stock bitmap:%8X", *phBitmap);
  400. return hr;
  401. }
  402. hr = CreateBitmapFromData(hdc, iDibOffset + TMBITMAPSIZE, &hBitmap);
  403. if (FAILED(hr))
  404. goto exit;
  405. Log(LOG_TM, L"GetBitmap - CACHE MISS: class=%s, diboffset=%d, bitmap=0x%x",
  406. SHARECLASS(this), iDibOffset, hBitmap);
  407. #if 0
  408. if (lstrcmpi(SHARECLASS(this), L"progress")==0)
  409. {
  410. //---- validate the bitmap ----
  411. int iBytes = GetObject(hBitmap, 0, NULL);
  412. Log(LOG_RFBUG, L"progress: CREATE bitmap, diboff=%d, hbitmap=0x%x, iBytes=%d",
  413. iDibOffset, hBitmap, iBytes);
  414. }
  415. #endif
  416. *phBitmap = hBitmap;
  417. exit:
  418. return hr;
  419. }
  420. //---------------------------------------------------------------------------
  421. void CRenderObj::ReturnBitmap(HBITMAP hBitmap)
  422. {
  423. DeleteObject(hBitmap);
  424. }
  425. //---------------------------------------------------------------------------
  426. HRESULT CRenderObj::CreateBitmapFromData(HDC hdc, int iDibOffset, OUT HBITMAP *phBitmap)
  427. {
  428. BYTE *pDibData;
  429. RESOURCE HDC hdcTemp = NULL;
  430. RESOURCE HBITMAP hBitmap = NULL;
  431. HRESULT hr = S_OK;
  432. if ((! iDibOffset) || (! _pbThemeData))
  433. {
  434. hr = E_FAIL;
  435. goto exit;
  436. }
  437. pDibData = (BYTE *)(_pbThemeData + iDibOffset);
  438. BITMAPINFOHEADER *pBitmapHdr;
  439. pBitmapHdr = (BITMAPINFOHEADER *)pDibData;
  440. BOOL fAlphaChannel;
  441. fAlphaChannel = (pBitmapHdr->biBitCount == 32);
  442. if (! hdc)
  443. {
  444. hdcTemp = GetWindowDC(NULL);
  445. if (! hdcTemp)
  446. {
  447. Log(LOG_ALWAYS, L"GetWindowDC() failed in CreateBitmapFromData");
  448. hr = MakeErrorLast();
  449. goto exit;
  450. }
  451. hdc = hdcTemp;
  452. }
  453. //---- create the actual bitmap ----
  454. //---- if using alpha channel, we must use a DIB ----
  455. if (fAlphaChannel)
  456. {
  457. void *pv;
  458. hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)pBitmapHdr, DIB_RGB_COLORS,
  459. &pv, NULL, 0);
  460. }
  461. else
  462. {
  463. hBitmap = CreateCompatibleBitmap(hdc, pBitmapHdr->biWidth, pBitmapHdr->biHeight);
  464. }
  465. if (! hBitmap)
  466. {
  467. hr = MakeErrorLast();
  468. goto exit;
  469. }
  470. int iSetVal;
  471. //---- SetDIBits() can take unaligned data, right? ----
  472. iSetVal = SetDIBits(hdc, hBitmap, 0, pBitmapHdr->biHeight, DIBDATA(pBitmapHdr), (BITMAPINFO *)pBitmapHdr,
  473. DIB_RGB_COLORS);
  474. if (! iSetVal)
  475. {
  476. hr = MakeErrorLast();
  477. goto exit;
  478. }
  479. *phBitmap = hBitmap;
  480. #ifdef DEBUG
  481. if (hBitmap)
  482. {
  483. BITMAP bm;
  484. GetObject(hBitmap, sizeof bm, &bm);
  485. s_dwSize += bm.bmWidthBytes * bm.bmHeight;
  486. //Log(LOG_TMBITMAP, L"Created a bitmap of %d bytes. total is %d", bm.bmWidthBytes * bm.bmHeight, s_dwSize);
  487. }
  488. #endif
  489. exit:
  490. if (hdcTemp)
  491. ReleaseDC(NULL, hdcTemp);
  492. if (FAILED(hr))
  493. {
  494. if (hBitmap)
  495. DeleteObject(hBitmap);
  496. }
  497. return hr;
  498. }
  499. //---------------------------------------------------------------------------
  500. HRESULT CRenderObj::GetScaledFontHandle(HDC hdc, LOGFONT *plf, HFONT *phFont)
  501. {
  502. HRESULT hr = S_OK;
  503. if (_fCacheEnabled)
  504. {
  505. CRenderCache *pCacheObj = GetTlsCacheObj();
  506. if (pCacheObj)
  507. hr = pCacheObj->GetScaledFontHandle(hdc, plf, phFont);
  508. }
  509. else
  510. {
  511. LOGFONT lf = *plf;
  512. //---- convert to current screen dpi ----
  513. ScaleFontForHdcDpi(hdc, &lf);
  514. *phFont = CreateFontIndirect(&lf);
  515. if (! *phFont)
  516. hr = MakeError32(E_OUTOFMEMORY);
  517. }
  518. return hr;
  519. }
  520. //---------------------------------------------------------------------------
  521. void CRenderObj::ReturnFontHandle(HFONT hFont)
  522. {
  523. if (_fCacheEnabled)
  524. {
  525. //--- cache currently doesn't refcnt so save time by not calling ---
  526. //CRenderCache *pCacheObj = GetTlsCacheObj();
  527. //if (pCacheObj)
  528. //{
  529. //pCacheObj->ReturnFontHandle(hFont);
  530. //goto exit;
  531. //}
  532. }
  533. else
  534. {
  535. DeleteObject(hFont);
  536. }
  537. }
  538. //---------------------------------------------------------------------------
  539. HRESULT CRenderObj::PrepareRegionDataForScaling(
  540. RGNDATA *pRgnData, LPCRECT prcImage, MARGINS *pMargins)
  541. {
  542. //---- compute margin values ----
  543. int sw = prcImage->left;
  544. int lw = prcImage->left + pMargins->cxLeftWidth;
  545. int rw = prcImage->right - pMargins->cxRightWidth;
  546. int sh = prcImage->top;
  547. int th = prcImage->top + pMargins->cyTopHeight;
  548. int bh = prcImage->bottom - pMargins->cyBottomHeight;
  549. //---- step thru region data & customize it ----
  550. //---- classify each POINT according to a gridnum and ----
  551. //---- make it 0-relative to its grid location ----
  552. POINT *pt = (POINT *)pRgnData->Buffer;
  553. BYTE *pByte = (BYTE *)pRgnData->Buffer + pRgnData->rdh.nRgnSize;
  554. int iCount = 2 * pRgnData->rdh.nCount;
  555. for (int i=0; i < iCount; i++, pt++, pByte++)
  556. {
  557. if (pt->x < lw)
  558. {
  559. pt->x -= sw;
  560. if (pt->y < th) // left top
  561. {
  562. *pByte = GN_LEFTTOP;
  563. pt->y -= sh;
  564. }
  565. else if (pt->y < bh) // left middle
  566. {
  567. *pByte = GN_LEFTMIDDLE;
  568. pt->y -= th;
  569. }
  570. else // left bottom
  571. {
  572. *pByte = GN_LEFTBOTTOM;
  573. pt->y -= bh;
  574. }
  575. }
  576. else if (pt->x < rw)
  577. {
  578. pt->x -= lw;
  579. if (pt->y < th) // middle top
  580. {
  581. *pByte = GN_MIDDLETOP;
  582. pt->y -= sh;
  583. }
  584. else if (pt->y < bh) // middle middle
  585. {
  586. *pByte = GN_MIDDLEMIDDLE;
  587. pt->y -= th;
  588. }
  589. else // middle bottom
  590. {
  591. *pByte = GN_MIDDLEBOTTOM;
  592. pt->y -= bh;
  593. }
  594. }
  595. else
  596. {
  597. pt->x -= rw;
  598. if (pt->y < th) // right top
  599. {
  600. *pByte = GN_RIGHTTOP;
  601. pt->y -= sh;
  602. }
  603. else if (pt->y < bh) // right middle
  604. {
  605. *pByte = GN_RIGHTMIDDLE;
  606. pt->y -= th;
  607. }
  608. else // right bottom
  609. {
  610. *pByte = GN_RIGHTBOTTOM;
  611. pt->y -= bh;
  612. }
  613. }
  614. }
  615. return S_OK;
  616. }
  617. //---------------------------------------------------------------------------
  618. HRESULT CRenderObj::CreateImageBrush(HDC hdc, int iPartId, int iStateId,
  619. int iImageIndex, HBRUSH *phbr)
  620. {
  621. #if 0
  622. HRESULT hr;
  623. RESOURCE HDC dc2 = NULL;
  624. RESOURCE HBITMAP hOldBitmap2 = NULL;
  625. HBRUSH hBrush = NULL;
  626. //---- get our bitmap from the cache ----
  627. RESOURCE HBITMAP hBitmap;
  628. hr = GetBitmap(hdc, iPartId, iStateId, &hBitmap);
  629. if (FAILED(hr))
  630. goto exit;
  631. int iImageCount;
  632. if (FAILED(GetInt(iPartId, iStateId, TMT_IMAGECOUNT, &iImageCount)))
  633. iImageCount = 1; /// default value
  634. if (iImageCount == 1) // do easy case first
  635. {
  636. hBrush = CreatePatternBrush(hBitmap);
  637. goto gotit;
  638. }
  639. //---- create "dc2" to make our bitmap usable ----
  640. dc2 = CreateCompatibleDC(hdc);
  641. if (! dc2)
  642. {
  643. hr = MakeErrorLast();
  644. goto exit;
  645. }
  646. hOldBitmap2 = (HBITMAP) SelectObject(dc2, hBitmap);
  647. //---- create a sub-bitmap of just our target image in "memoryDC" ----
  648. int width, height, xoffset, yoffset;
  649. GetImageInfo(hBitmap, iPartId, iStateId, iImageIndex, &width, &height, &xoffset, &yoffset);
  650. //---- local block ----
  651. {
  652. CMemoryDC memoryDC;
  653. hr = memoryDC.OpenDC(dc2, width, height);
  654. if (FAILED(hr))
  655. return hr;
  656. BitBlt(memoryDC, 0, 0, width, height, dc2, xoffset, yoffset, SRCCOPY);
  657. //---- finally, create our brush ----
  658. hBrush = CreatePatternBrush(memoryDC._hBitmap);
  659. }
  660. gotit:
  661. if (hBrush)
  662. {
  663. *phbr = hBrush;
  664. hr = S_OK;
  665. }
  666. else
  667. hr = MakeErrorLast();
  668. exit:
  669. //---- now clean up all resources ----
  670. if (dc2)
  671. {
  672. SelectObject(dc2, hOldBitmap2);
  673. DeleteDC(dc2);
  674. }
  675. ReturnBitmap(hBitmap);
  676. return hr;
  677. #endif
  678. return E_NOTIMPL;
  679. }
  680. //---------------------------------------------------------------------------
  681. HRESULT CRenderObj::GetColor(int iPartId, int iStateId, int iPropId, COLORREF *pColor)
  682. {
  683. if (! pColor)
  684. return MakeError32(E_INVALIDARG);
  685. int index = GetValueIndex(iPartId, iStateId, iPropId);
  686. if (index < 0) // not found
  687. return MakeError32(ERROR_NOT_FOUND);
  688. MIXEDPTRS u;
  689. u.pb = _pbThemeData + index; // point at data
  690. *pColor = *u.pi;
  691. return S_OK;
  692. }
  693. //---------------------------------------------------------------------------
  694. HRESULT CRenderObj::GetString(int iPartId, int iStateId, int iPropId,
  695. LPWSTR pszBuff, DWORD dwMaxBuffChars)
  696. {
  697. if (! pszBuff)
  698. return MakeError32(E_INVALIDARG);
  699. int index = GetValueIndex(iPartId, iStateId, iPropId);
  700. if (index < 0)
  701. return MakeError32(ERROR_NOT_FOUND);
  702. MIXEDPTRS u;
  703. u.pb = _pbThemeData + index - sizeof(int); // point at length
  704. DWORD len = *u.pdw++;
  705. len /= sizeof(WCHAR); // adjust to characters
  706. HRESULT hr = hr_lstrcpy(pszBuff, u.pw, dwMaxBuffChars);
  707. return hr;
  708. }
  709. //---------------------------------------------------------------------------
  710. HRESULT CRenderObj::GetBool(int iPartId, int iStateId, int iPropId, BOOL *pfVal)
  711. {
  712. if (! pfVal)
  713. return MakeError32(E_INVALIDARG);
  714. int index = GetValueIndex(iPartId, iStateId, iPropId);
  715. if (index < 0)
  716. return MakeError32(ERROR_NOT_FOUND);
  717. MIXEDPTRS u;
  718. u.pb = _pbThemeData + index; // point at data
  719. *pfVal = *u.pb;
  720. return S_OK;
  721. }
  722. //---------------------------------------------------------------------------
  723. HRESULT CRenderObj::GetInt(int iPartId, int iStateId, int iPropId, int *piVal)
  724. {
  725. if (! piVal)
  726. return MakeError32(E_INVALIDARG);
  727. int index = GetValueIndex(iPartId, iStateId, iPropId);
  728. if (index < 0)
  729. return MakeError32(ERROR_NOT_FOUND);
  730. MIXEDPTRS u;
  731. u.pb = _pbThemeData + index; // point at data
  732. *piVal = *u.pi;
  733. return S_OK;
  734. }
  735. //---------------------------------------------------------------------------
  736. static int iMetricDefaults[] =
  737. {
  738. 1, // TMT_BORDERWIDTH
  739. 18, // TMT_VERTSCROLLWIDTH
  740. 18, // TMT_HORZSCROLLHEIGHT
  741. 27, // TMT_CAPTIONBUTTONWIDTH
  742. 27, // TMT_CAPTIONBUTTONHEIGHT
  743. 22, // TMT_SMCAPTIONBUTTONWIDTH
  744. 22, // TMT_SMCAPTIONBUTTONHEIGHT
  745. 22, // TMT_MENUBUTTONWIDTH
  746. 22, // TMT_MENUBUTTONHEIGHT
  747. };
  748. //---------------------------------------------------------------------------
  749. HRESULT CRenderObj::GetMetric(OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId, int *piVal)
  750. {
  751. if (! piVal)
  752. return MakeError32(E_INVALIDARG);
  753. int index = GetValueIndex(iPartId, iStateId, iPropId);
  754. int value;
  755. if (index >= 0) // found
  756. {
  757. MIXEDPTRS u;
  758. u.pb = _pbThemeData + index; // point at data
  759. value = *u.pi;
  760. }
  761. else
  762. return MakeError32(ERROR_NOT_FOUND);
  763. *piVal = ScaleSizeForHdcDpi(hdc, value);
  764. return S_OK;
  765. }
  766. //---------------------------------------------------------------------------
  767. HRESULT CRenderObj::GetEnumValue(int iPartId, int iStateId, int iPropId, int *piVal)
  768. {
  769. if (! piVal)
  770. return MakeError32(E_INVALIDARG);
  771. int index = GetValueIndex(iPartId, iStateId, iPropId);
  772. if (index < 0)
  773. return MakeError32(ERROR_NOT_FOUND);
  774. MIXEDPTRS u;
  775. u.pb = _pbThemeData + index; // point at data
  776. *piVal = *u.pi;
  777. return S_OK;
  778. }
  779. //---------------------------------------------------------------------------
  780. HRESULT CRenderObj::GetPosition(int iPartId, int iStateId, int iPropId, POINT *pPoint)
  781. {
  782. if (! pPoint)
  783. return MakeError32(E_INVALIDARG);
  784. int index = GetValueIndex(iPartId, iStateId, iPropId);
  785. if (index < 0)
  786. return MakeError32(ERROR_NOT_FOUND);
  787. MIXEDPTRS u;
  788. u.pb = _pbThemeData + index; // point at data
  789. pPoint->x = *u.pi++;
  790. pPoint->y = *u.pi++;
  791. return S_OK;
  792. }
  793. //---------------------------------------------------------------------------
  794. HRESULT CRenderObj::GetFont(OPTIONAL HDC hdc, int iPartId, int iStateId, int iPropId,
  795. BOOL fWantHdcScaling, LOGFONT *pFont)
  796. {
  797. if (! pFont)
  798. return MakeError32(E_INVALIDARG);
  799. int index = GetValueIndex(iPartId, iStateId, iPropId);
  800. if (index < 0)
  801. return MakeError32(ERROR_NOT_FOUND);
  802. MIXEDPTRS u;
  803. u.pb = _pbThemeData + index; // point at data
  804. *pFont = *(LOGFONT *)u.pb;
  805. if (fWantHdcScaling)
  806. {
  807. ScaleFontForHdcDpi(hdc, pFont);
  808. }
  809. return S_OK;
  810. }
  811. //---------------------------------------------------------------------------
  812. HRESULT CRenderObj::GetMargins(OPTIONAL HDC hdc, int iPartId, int iStateId,
  813. int iPropId, OPTIONAL RECT *prc, MARGINS *pMargins)
  814. {
  815. //---- return unscaled margins ----
  816. if (! pMargins)
  817. return MakeError32(E_INVALIDARG);
  818. int index = GetValueIndex(iPartId, iStateId, iPropId);
  819. if (index < 0)
  820. return MakeError32(ERROR_NOT_FOUND);
  821. MIXEDPTRS u;
  822. u.pb = _pbThemeData + index; // point at data
  823. pMargins->cxLeftWidth = *u.pi++;
  824. pMargins->cxRightWidth = *u.pi++;
  825. pMargins->cyTopHeight = *u.pi++;
  826. pMargins->cyBottomHeight = *u.pi++;
  827. return S_OK;
  828. }
  829. //---------------------------------------------------------------------------
  830. HRESULT CRenderObj::GetIntList(int iPartId, int iStateId, int iPropId, INTLIST *pIntList)
  831. {
  832. if (! pIntList)
  833. return MakeError32(E_INVALIDARG);
  834. int index = GetValueIndex(iPartId, iStateId, iPropId);
  835. if (index < 0)
  836. return MakeError32(ERROR_NOT_FOUND);
  837. MIXEDPTRS u;
  838. u.pb = _pbThemeData + index; // point at data
  839. int iCount = *u.pi++;
  840. if (iCount > MAX_INTLIST_COUNT)
  841. {
  842. Log(LOG_ALWAYS, L"GetIntList() found bad theme data - Count=%d", iCount);
  843. return MakeError32(ERROR_NOT_FOUND);
  844. }
  845. pIntList->iValueCount = iCount;
  846. for (int i=0; i < iCount; i++)
  847. pIntList->iValues[i] = *u.pi++;
  848. return S_OK;
  849. }
  850. //---------------------------------------------------------------------------
  851. HRESULT CRenderObj::GetRect(int iPartId, int iStateId, int iPropId, RECT *pRect)
  852. {
  853. if (! pRect)
  854. return MakeError32(E_INVALIDARG);
  855. int index = GetValueIndex(iPartId, iStateId, iPropId);
  856. if (index < 0)
  857. return MakeError32(ERROR_NOT_FOUND);
  858. MIXEDPTRS u;
  859. u.pb = _pbThemeData + index; // point at data
  860. pRect->left = *u.pi++;
  861. pRect->top = *u.pi++;
  862. pRect->right = *u.pi++;
  863. pRect->bottom = *u.pi++;
  864. return S_OK;
  865. }
  866. //---------------------------------------------------------------------------
  867. HRESULT CRenderObj::GetFilenameOffset(int iPartId, int iStateId, int iPropId,
  868. int *piFileNameOffset)
  869. {
  870. if (! piFileNameOffset)
  871. return MakeError32(E_INVALIDARG);
  872. int index = GetValueIndex(iPartId, iStateId, iPropId);
  873. if (index < 0)
  874. return MakeError32(ERROR_NOT_FOUND);
  875. *piFileNameOffset = index; // offset to filename
  876. return S_OK;
  877. }
  878. //---------------------------------------------------------------------------
  879. HRESULT CRenderObj::GetFilename(int iPartId, int iStateId, int iPropId, LPWSTR pszBuff,
  880. DWORD dwMaxBuffChars)
  881. {
  882. if (! pszBuff)
  883. return MakeError32(E_INVALIDARG);
  884. int index = GetValueIndex(iPartId, iStateId, iPropId);
  885. if (index < 0)
  886. return MakeError32(ERROR_NOT_FOUND);
  887. MIXEDPTRS u;
  888. u.pb = _pbThemeData + index - sizeof(int); // point at length
  889. DWORD len = *u.pdw++;
  890. len /= sizeof(WCHAR); // adjust to chars size
  891. HRESULT hr = hr_lstrcpy(pszBuff, u.pw, dwMaxBuffChars);
  892. return hr;
  893. }
  894. //---------------------------------------------------------------------------
  895. HRESULT CRenderObj::GetData(int iPartId, int iStateId, int iPropId, BYTE **ppData,
  896. OPTIONAL int *piSize)
  897. {
  898. if (! ppData)
  899. return MakeError32(E_INVALIDARG);
  900. int index = GetValueIndex(iPartId, iStateId, iPropId);
  901. if (index < 0)
  902. return MakeError32(ERROR_NOT_FOUND);
  903. MIXEDPTRS u;
  904. u.pb = _pbThemeData + index - sizeof(int); // point at length
  905. DWORD len = *u.pdw++;
  906. *ppData = u.pb;
  907. if (piSize)
  908. *piSize = len;
  909. return S_OK;
  910. }
  911. //---------------------------------------------------------------------------
  912. int CRenderObj::GetValueIndex(int iPartId, int iStateId, int iTarget)
  913. {
  914. if (! iTarget)
  915. {
  916. Log(LOG_PARAMS, L"Invalid iProperyId passed to GetValueIndex: %d", iTarget);
  917. return -1;
  918. }
  919. if (! _pbSectionData)
  920. {
  921. return -1;
  922. }
  923. MIXEDPTRS u;
  924. int index;
  925. u.pb = _pbSectionData;
  926. //---- find end of data ----
  927. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  928. BYTE *pbLastValidChar = _pbThemeData + (hdr->dwTotalLength - 1) - kcbEndSignature;
  929. while (u.pb <= pbLastValidChar)
  930. {
  931. UNPACKED_ENTRYHDR hdr;
  932. FillAndSkipHdr(u, &hdr);
  933. if (hdr.usTypeNum == TMT_PARTJUMPTABLE)
  934. {
  935. u.pi++; // skip over offset to first drawobj
  936. BYTE cnt = *u.pb++;
  937. if ((iPartId < 0) || (iPartId >= cnt))
  938. {
  939. index = u.pi[0];
  940. }
  941. else
  942. {
  943. index = u.pi[iPartId];
  944. if (index == -1)
  945. index = u.pi[0];
  946. }
  947. u.pb = _pbThemeData + index;
  948. continue;
  949. }
  950. if (hdr.usTypeNum == (BYTE)TMT_STATEJUMPTABLE)
  951. {
  952. BYTE cnt = *u.pb++;
  953. if ((iStateId < 0) || (iStateId >= cnt))
  954. index = u.pi[0];
  955. else
  956. {
  957. index = u.pi[iStateId];
  958. if (index == -1)
  959. index = u.pi[0];
  960. }
  961. u.pb = _pbThemeData + index;
  962. continue;
  963. }
  964. if (hdr.usTypeNum == iTarget) // got our target
  965. {
  966. // Log("GetValueIndex: match at index=%d", u.pb - _pbThemeData);
  967. return (int)(u.pb - _pbThemeData); // point at actual data (not hdr)
  968. }
  969. if (hdr.ePrimVal == TMT_JUMPTOPARENT)
  970. {
  971. index = *u.pi;
  972. if (index == -1)
  973. {
  974. // Log("no match found");
  975. return -1;
  976. }
  977. // Log("GetValueIndex: jumping to parent at index=%d", index);
  978. u.pb = _pbThemeData + index;
  979. continue;
  980. }
  981. // Log("GetValueIndex: no match to hdr.usTypeNum=%d", hdr.usTypeNum);
  982. // advance to next value
  983. u.pb += hdr.dwDataLen;
  984. }
  985. //---- something went wrong ----
  986. Log(LOG_ERROR, L"GetValueIndex: ran off the valid data without a '-1' jump");
  987. return -1;
  988. }
  989. //---------------------------------------------------------------------------
  990. HRESULT CRenderObj::GetPropertyOrigin(int iPartId, int iStateId, int iTarget,
  991. PROPERTYORIGIN *pOrigin)
  992. {
  993. if (! iTarget)
  994. {
  995. Log(LOG_PARAMS, L"Invalid iProperyId passed to GetPropertyOrigin: %d", iTarget);
  996. return E_FAIL;
  997. }
  998. if (! _pbSectionData)
  999. {
  1000. return E_FAIL;
  1001. }
  1002. MIXEDPTRS u;
  1003. if (! pOrigin)
  1004. return MakeError32(E_INVALIDARG);
  1005. //---- start at our section ----
  1006. u.pb = _pbSectionData;
  1007. PROPERTYORIGIN origin = PO_CLASS;
  1008. //---- find end of data ----
  1009. THEMEHDR *hdr = (THEMEHDR *)_pbThemeData;
  1010. BYTE *pbLastValidChar = _pbThemeData + (hdr->dwTotalLength - 1) - kcbEndSignature;
  1011. while (u.pb <= pbLastValidChar)
  1012. {
  1013. UNPACKED_ENTRYHDR hdr;
  1014. FillAndSkipHdr(u, &hdr);
  1015. if (hdr.usTypeNum == TMT_PARTJUMPTABLE)
  1016. {
  1017. u.pi++; // skip over offset to first drawobj
  1018. BYTE cnt = *u.pb++;
  1019. int index;
  1020. if ((iPartId <= 0) || (iPartId >= cnt))
  1021. {
  1022. index = u.pi[0];
  1023. }
  1024. else
  1025. {
  1026. index = u.pi[iPartId];
  1027. if (index == -1)
  1028. index = u.pi[0];
  1029. }
  1030. if (index == u.pi[0])
  1031. origin = PO_CLASS;
  1032. else
  1033. origin = PO_PART;
  1034. u.pb = _pbThemeData + index;
  1035. continue;
  1036. }
  1037. if (hdr.usTypeNum == TMT_STATEJUMPTABLE)
  1038. {
  1039. BYTE cnt = *u.pb++;
  1040. int index;
  1041. if ((iStateId <= 0) || (iStateId >= cnt))
  1042. {
  1043. index = u.pi[0];
  1044. }
  1045. else
  1046. {
  1047. index = u.pi[iStateId];
  1048. if (index == -1)
  1049. index = u.pi[0];
  1050. }
  1051. if (index != u.pi[0])
  1052. origin = PO_STATE;
  1053. u.pb = _pbThemeData + index;
  1054. continue;
  1055. }
  1056. //Log("GetPropertyOrgin: iPartId=%d, iTarget=%d, DataIndex=%d",
  1057. // iPartId, iTarget, u.pb - _pbThemeData);
  1058. if ((iTarget == -1) || (hdr.usTypeNum == iTarget)) // got our target
  1059. {
  1060. // Log("GetPropertyOrgin: match at index=%d", u.pb - _pbThemeData);
  1061. *pOrigin = origin;
  1062. return S_OK;
  1063. }
  1064. if (hdr.ePrimVal == TMT_JUMPTOPARENT)
  1065. {
  1066. int index = *u.pi;
  1067. if (index == -1)
  1068. {
  1069. // Log("GetPropertyOrgin: no match found");
  1070. *pOrigin = PO_NOTFOUND;
  1071. return S_OK;
  1072. }
  1073. // Log("GetPropertyOrgin: jumping to parent at index=%d", index);
  1074. u.pb = _pbThemeData + index;
  1075. origin = (PROPERTYORIGIN) (origin + 1); // move down to next level of heirarchy
  1076. continue;
  1077. }
  1078. // advance to next value
  1079. u.pb += hdr.dwDataLen;
  1080. }
  1081. //---- something went wrong ----
  1082. Log(LOG_ERROR, L"GetPropertyOrigin: ran off the valid data without a '-1' jump");
  1083. return E_FAIL;
  1084. }
  1085. //---------------------------------------------------------------------------
  1086. BOOL WINAPI CRenderObj::IsPartDefined(int iPartId, int iStateId)
  1087. {
  1088. PROPERTYORIGIN origin;
  1089. HRESULT hr = GetPropertyOrigin(iPartId, iStateId, -1, &origin);
  1090. SET_LAST_ERROR(hr);
  1091. if (FAILED(hr))
  1092. {
  1093. return FALSE;
  1094. }
  1095. if (iStateId)
  1096. return (origin == PO_STATE);
  1097. return (origin == PO_PART);
  1098. }
  1099. //---------------------------------------------------------------------------
  1100. BOOL CRenderObj::ValidateObj()
  1101. {
  1102. BOOL fValid = TRUE;
  1103. //---- check object quickly ----
  1104. if ( (! this)
  1105. || (ULONGAT(_szHead) != 'dner') // "rend"
  1106. || (ULONGAT(&_szHead[4]) != 'jbo') // "obj"
  1107. || (ULONGAT(_szTail) != 'dne')) // "end"
  1108. {
  1109. Log(LOG_ALWAYS, L"CRenderObj is corrupt, addr=0x%08x", this);
  1110. fValid = FALSE;
  1111. }
  1112. return fValid;
  1113. }
  1114. //---------------------------------------------------------------------------
  1115. CRenderCache *CRenderObj::GetTlsCacheObj()
  1116. {
  1117. HRESULT hr = S_OK;
  1118. CRenderCache *pCacheObj = NULL;
  1119. CCacheList *pcl = GetTlsCacheList(TRUE);
  1120. if (pcl)
  1121. hr = pcl->GetCacheObject(this, _iCacheSlot, &pCacheObj);
  1122. return pCacheObj;
  1123. }
  1124. //---------------------------------------------------------------------------
  1125. #if 0
  1126. HRESULT CRenderObj::DispatchDrawBg()
  1127. {
  1128. HRESULT hr = S_OK;
  1129. if (FAILED(GetEnumValue(iPartId, iStateId, TMT_BGTYPE, (int *)&eBgType)))
  1130. eBgType = BT_BORDERFILL; // default value
  1131. if (eBgType == BT_NTLFILE)
  1132. {
  1133. BYTE *pNtlData;
  1134. int iNtlLen;
  1135. hr = GetData(iPartId, iStateId, TMT_NTLDATA, &pNtlData, &iNtlLen);
  1136. if (FAILED(hr))
  1137. goto exit;
  1138. RECT rc = *pRect;
  1139. //---- need to get these from callers... ---
  1140. HBRUSH hbrDefault = NULL;
  1141. DWORD dwOptions = 0;
  1142. hr = RunNtl(hdc, rc, hbrDefault, dwOptions, iPartId, iStateId, pNtlData, iNtlLen, this);
  1143. goto exit;
  1144. }
  1145. return hr;
  1146. }
  1147. #endif
  1148. //---------------------------------------------------------------------------
  1149. HRESULT CRenderObj::FindGlobalDrawObj(BYTE *pb, int iPartId, int iStateId, CDrawBase **ppObj)
  1150. {
  1151. HRESULT hr = S_OK;
  1152. MIXEDPTRS u;
  1153. u.pb = pb;
  1154. BOOL fFound = FALSE;
  1155. UNPACKED_ENTRYHDR hdr;
  1156. while (1)
  1157. {
  1158. if ((*u.ps == TMT_RGNLIST) || (*u.ps == TMT_STOCKBRUSHES))
  1159. {
  1160. //---- skip over this entry ----
  1161. FillAndSkipHdr(u, &hdr);
  1162. u.pb += hdr.dwDataLen;
  1163. continue;
  1164. }
  1165. if (*u.ps != TMT_DRAWOBJ)
  1166. break;
  1167. FillAndSkipHdr(u, &hdr);
  1168. DRAWOBJHDR *ph = (DRAWOBJHDR *)u.pb;
  1169. if ((ph->iPartNum == iPartId) && (ph->iStateNum == iStateId))
  1170. {
  1171. *ppObj = (CDrawBase *)(u.pb + sizeof(DRAWOBJHDR));
  1172. fFound = TRUE;
  1173. break;
  1174. }
  1175. //---- skip over hdr+object ----
  1176. u.pb += hdr.dwDataLen;
  1177. }
  1178. if (! fFound)
  1179. hr = E_FAIL;
  1180. return hr;
  1181. }
  1182. //---------------------------------------------------------------------------
  1183. HRESULT CRenderObj::GetGlobalDrawObj(int iPartId, int iStateId, CDrawBase **ppObj)
  1184. {
  1185. //---- perf note: we don't currently cache the ptrs for LINE and BORDER ----
  1186. //---- global objects since they are not used much/at all ----
  1187. HRESULT hr = S_OK;
  1188. if (! _pbThemeData)
  1189. {
  1190. hr = E_FAIL;
  1191. goto exit;
  1192. }
  1193. THEMEHDR *pHdr;
  1194. pHdr = (THEMEHDR *)_pbThemeData;
  1195. //---- get ptr to global text obj ----
  1196. MIXEDPTRS u;
  1197. u.pb = _pbThemeData + pHdr->iGlobalsDrawObjOffset;
  1198. //---- first try exact match ---
  1199. hr = FindGlobalDrawObj(u.pb, iPartId, iStateId, ppObj);
  1200. if (FAILED(hr))
  1201. {
  1202. //---- look for state=0 ----
  1203. hr = FindGlobalDrawObj(u.pb, iPartId, 0, ppObj);
  1204. if (FAILED(hr))
  1205. {
  1206. //---- just use the global draw obj ----
  1207. if (*u.ps == TMT_DRAWOBJ)
  1208. {
  1209. u.pb += ENTRYHDR_SIZE + sizeof(DRAWOBJHDR);
  1210. *ppObj = (CDrawBase *)u.pb;
  1211. hr = S_OK;
  1212. }
  1213. }
  1214. }
  1215. exit:
  1216. return hr;
  1217. }
  1218. //---------------------------------------------------------------------------