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.

2064 lines
62 KiB

  1. //---------------------------------------------------------------------------
  2. // ImageFile.cpp - implements the drawing API for bgtype = ImageFile
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "Render.h"
  6. #include "Utils.h"
  7. #include "tmutils.h"
  8. #include "rgn.h"
  9. #include "ImageFile.h"
  10. #include "CacheList.h"
  11. #include "DrawHelp.h"
  12. #include "ninegrid2.h"
  13. #include "TmReg.h"
  14. #include "globals.h"
  15. #include "bmpcache.h"
  16. //---------------------------------------------------------------------------
  17. void AdjustSizeMin(SIZE *psz, int ixMin, int iyMin)
  18. {
  19. if (psz->cx < ixMin)
  20. {
  21. psz->cx = ixMin;
  22. }
  23. if (psz->cy < iyMin)
  24. {
  25. psz->cy = iyMin;
  26. }
  27. }
  28. //---------------------------------------------------------------------------
  29. HRESULT CMaxImageFile::PackMaxProperties(CRenderObj *pRender, int iPartId, int iStateId,
  30. OUT int *piMultiDibCount)
  31. {
  32. HRESULT hr = PackProperties(pRender, iPartId, iStateId);
  33. *piMultiDibCount = _iMultiImageCount;
  34. return hr;
  35. }
  36. //---------------------------------------------------------------------------
  37. HRESULT CImageFile::PackProperties(CRenderObj *pRender, int iPartId, int iStateId)
  38. {
  39. HRESULT hr = S_OK;
  40. memset(this, 0, sizeof(CImageFile)); // allowed because we have no vtable
  41. _eBgType = BT_IMAGEFILE;
  42. //---- save off partid, stateid for debugging ----
  43. _iSourcePartId = iPartId;
  44. _iSourceStateId = iStateId;
  45. DIBINFO *pdi = &_ImageInfo;
  46. pdi->iMinDpi = 96; // only way this gets set for now
  47. pdi->iDibOffset = pRender->GetValueIndex(iPartId, iStateId, TMT_DIBDATA);
  48. if (pdi->iDibOffset == -1) // not found
  49. pdi->iDibOffset = 0;
  50. //---- image-related fields ----
  51. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_IMAGECOUNT, &_iImageCount)))
  52. _iImageCount = 1; // default value
  53. if (_iImageCount < 1) // avoid divide by zero problems
  54. _iImageCount = 1;
  55. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_IMAGELAYOUT, (int *)&_eImageLayout)))
  56. _eImageLayout = IL_HORIZONTAL; // default value until we are converted
  57. if (pdi->iDibOffset)
  58. {
  59. //---- compute some fields from bitmap ----
  60. hr = SetImageInfo(pdi, pRender, iPartId, iStateId);
  61. if (FAILED(hr))
  62. goto exit;
  63. }
  64. //---- get MinSize ----
  65. if (FAILED(pRender->GetPosition(iPartId, iStateId, TMT_MINSIZE, (POINT *)&pdi->szMinSize)))
  66. {
  67. pdi->szMinSize.cx = pdi->iSingleWidth;
  68. pdi->szMinSize.cy = pdi->iSingleHeight;
  69. }
  70. else
  71. {
  72. AdjustSizeMin(&pdi->szMinSize, 1, 1);
  73. }
  74. //---- get TrueSizeScalingType ----
  75. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_TRUESIZESCALINGTYPE, (int *)&_eTrueSizeScalingType)))
  76. _eTrueSizeScalingType = TSST_NONE; // default
  77. //---- sizing ----
  78. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_SIZINGTYPE, (int *)&pdi->eSizingType)))
  79. pdi->eSizingType = ST_STRETCH; // default
  80. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_BORDERONLY, &pdi->fBorderOnly)))
  81. pdi->fBorderOnly = FALSE;
  82. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_TRUESIZESTRETCHMARK, &_iTrueSizeStretchMark)))
  83. _iTrueSizeStretchMark = 0; // default
  84. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_UNIFORMSIZING, &_fUniformSizing)))
  85. _fUniformSizing = FALSE; // default
  86. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_INTEGRALSIZING, &_fIntegralSizing)))
  87. _fIntegralSizing = FALSE; // default
  88. //---- transparency ----
  89. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_TRANSPARENT, &pdi->fTransparent)))
  90. pdi->fTransparent = FALSE;
  91. if (pdi->fTransparent)
  92. {
  93. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_TRANSPARENTCOLOR, &pdi->crTransparent)))
  94. pdi->crTransparent = DEFAULT_TRANSPARENT_COLOR;
  95. }
  96. //---- MirrorImage ----
  97. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_MIRRORIMAGE, &_fMirrorImage)))
  98. _fMirrorImage = TRUE; // default setting
  99. //---- alignment ----
  100. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_HALIGN, (int *)&_eHAlign)))
  101. _eHAlign = HA_CENTER; // default value
  102. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_VALIGN, (int *)&_eVAlign)))
  103. _eVAlign = VA_CENTER; // default value
  104. //---- for regular or glyph truesize images ----
  105. if (SUCCEEDED(pRender->GetBool(iPartId, iStateId, TMT_BGFILL, &_fBgFill)))
  106. {
  107. //---- get fill color ----
  108. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_FILLCOLOR, &_crFill)))
  109. _crFill = RGB(255, 255, 255);
  110. }
  111. //---- SizingMargins ----
  112. if (FAILED(pRender->GetMargins(NULL, iPartId, iStateId, TMT_SIZINGMARGINS,
  113. NULL, &_SizingMargins)))
  114. {
  115. _SizingMargins.cxLeftWidth = 0;
  116. _SizingMargins.cxRightWidth = 0;
  117. _SizingMargins.cyTopHeight = 0;
  118. _SizingMargins.cyBottomHeight = 0;
  119. }
  120. //---- ContentMargins ----
  121. if (FAILED(pRender->GetMargins(NULL, iPartId, iStateId, TMT_CONTENTMARGINS,
  122. NULL, &_ContentMargins)))
  123. {
  124. _ContentMargins = _SizingMargins;
  125. }
  126. //---- SourceGrow ----
  127. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_SOURCEGROW, &_fSourceGrow)))
  128. _fSourceGrow = FALSE; // default
  129. //---- SourceShrink ----
  130. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_SOURCESHRINK, &_fSourceShrink)))
  131. _fSourceShrink = FALSE; // default
  132. //---- NormalSize ----
  133. if (FAILED(pRender->GetPosition(iPartId, iStateId, TMT_NORMALSIZE, (POINT *)&_szNormalSize)))
  134. {
  135. _szNormalSize.cx = 60;
  136. _szNormalSize.cy = 30;
  137. }
  138. else
  139. {
  140. AdjustSizeMin(&_szNormalSize, 1, 1);
  141. }
  142. //---- glphytype ----
  143. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_GLYPHTYPE, (int *)&_eGlyphType)))
  144. _eGlyphType = GT_NONE; // default value
  145. if (_eGlyphType == GT_FONTGLYPH)
  146. {
  147. //---- font-based glyphs ----
  148. if (FAILED(pRender->GetFont(NULL, iPartId, iStateId, TMT_GLYPHFONT, FALSE, &_lfGlyphFont)))
  149. goto exit; // required
  150. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_GLYPHTEXTCOLOR, &_crGlyphTextColor)))
  151. _crGlyphTextColor = RGB(0, 0, 0); // default color
  152. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_GLYPHINDEX, &_iGlyphIndex)))
  153. _iGlyphIndex = 1; // default index
  154. }
  155. else if (_eGlyphType == GT_IMAGEGLYPH)
  156. {
  157. //---- image-based glyphs ----
  158. pdi = &_GlyphInfo;
  159. pdi->iMinDpi = 96; // only way this gets set for now
  160. pdi->iDibOffset = pRender->GetValueIndex(iPartId, iStateId, TMT_GLYPHDIBDATA);
  161. if (pdi->iDibOffset == -1)
  162. pdi->iDibOffset = 0;
  163. if (pdi->iDibOffset > 0) // found
  164. {
  165. hr = SetImageInfo(pdi, pRender, iPartId, iStateId);
  166. if (FAILED(hr))
  167. goto exit;
  168. }
  169. if (SUCCEEDED(pRender->GetBool(iPartId, iStateId, TMT_GLYPHTRANSPARENT, &pdi->fTransparent)))
  170. {
  171. if (FAILED(pRender->GetColor(iPartId, iStateId, TMT_GLYPHTRANSPARENTCOLOR, &pdi->crTransparent)))
  172. pdi->crTransparent = DEFAULT_TRANSPARENT_COLOR;
  173. }
  174. pdi->eSizingType = ST_TRUESIZE; // glyphs are always true size
  175. pdi->fBorderOnly = FALSE; // glyphs are never borderonly (for now)
  176. }
  177. if (_eGlyphType != GT_NONE)
  178. {
  179. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_GLYPHONLY, &_fGlyphOnly)))
  180. _fGlyphOnly = FALSE;
  181. }
  182. //---- multi files specified? ----
  183. if (FAILED(pRender->GetEnumValue(iPartId, iStateId, TMT_IMAGESELECTTYPE, (int *)&_eImageSelectType)))
  184. _eImageSelectType = IST_NONE;
  185. //---- fill in multi DIBINFO's ----
  186. if (_eImageSelectType != IST_NONE)
  187. {
  188. DIBINFO *pParent;
  189. if (_eGlyphType == GT_IMAGEGLYPH)
  190. {
  191. pParent = &_GlyphInfo;
  192. }
  193. else
  194. {
  195. pParent = &_ImageInfo;
  196. }
  197. for (int i=0; i < MAX_IMAGEFILE_SIZES; i++)
  198. {
  199. //---- get ImageFileN ----
  200. int iDibOffset = pRender->GetValueIndex(iPartId, iStateId, TMT_DIBDATA1 + i);
  201. if (iDibOffset == -1)
  202. break;
  203. _iMultiImageCount++;
  204. DIBINFO *pdi = MultiDibPtr(i);
  205. *pdi = *pParent; // inherit some props from parent
  206. pdi->iDibOffset = iDibOffset;
  207. hr = SetImageInfo(pdi, pRender, iPartId, iStateId);
  208. if (FAILED(hr))
  209. goto exit;
  210. //---- get MinDpiN ----
  211. if (FAILED(pRender->GetInt(iPartId, iStateId, TMT_MINDPI1 + i, &pdi->iMinDpi)))
  212. {
  213. pdi->iMinDpi = 96; // default
  214. }
  215. else
  216. {
  217. //---- ensure value >= 1 ----
  218. if (pdi->iMinDpi < 1)
  219. {
  220. pdi->iMinDpi = 1;
  221. }
  222. }
  223. //---- get MinSizeN ----
  224. if (FAILED(pRender->GetPosition(iPartId, iStateId, TMT_MINSIZE1 + i,
  225. (POINT *)&pdi->szMinSize)))
  226. {
  227. pdi->szMinSize.cx = pdi->iSingleWidth;
  228. pdi->szMinSize.cy = pdi->iSingleHeight;
  229. }
  230. else
  231. {
  232. AdjustSizeMin(&pdi->szMinSize, 1, 1);
  233. }
  234. }
  235. if (_iMultiImageCount > 0)
  236. {
  237. *pParent = *MultiDibPtr(0); // use first multi entry as primary object
  238. }
  239. }
  240. exit:
  241. return hr;
  242. }
  243. //---------------------------------------------------------------------------
  244. BOOL CImageFile::KeyProperty(int iPropId)
  245. {
  246. BOOL fKey = FALSE;
  247. switch (iPropId)
  248. {
  249. case TMT_BGTYPE:
  250. case TMT_TRANSPARENT:
  251. case TMT_AUTOSIZE:
  252. case TMT_BORDERONLY:
  253. case TMT_IMAGECOUNT:
  254. case TMT_ALPHALEVEL:
  255. case TMT_ALPHATHRESHOLD:
  256. case TMT_IMAGEFILE:
  257. case TMT_IMAGEFILE1:
  258. case TMT_IMAGEFILE2:
  259. case TMT_IMAGEFILE3:
  260. case TMT_IMAGEFILE4:
  261. case TMT_IMAGEFILE5:
  262. case TMT_SIZINGMARGINS:
  263. case TMT_CONTENTMARGINS:
  264. case TMT_TRANSPARENTCOLOR:
  265. case TMT_SIZINGTYPE:
  266. case TMT_HALIGN:
  267. case TMT_VALIGN:
  268. case TMT_IMAGELAYOUT:
  269. case TMT_BGFILL:
  270. case TMT_MIRRORIMAGE:
  271. case TMT_TRUESIZESTRETCHMARK:
  272. case TMT_TRUESIZESCALINGTYPE:
  273. case TMT_IMAGESELECTTYPE:
  274. case TMT_UNIFORMSIZING:
  275. case TMT_INTEGRALSIZING:
  276. case TMT_SOURCEGROW:
  277. case TMT_SOURCESHRINK:
  278. case TMT_NORMALSIZE:
  279. case TMT_MINSIZE:
  280. case TMT_MINSIZE1:
  281. case TMT_MINSIZE2:
  282. case TMT_MINSIZE3:
  283. case TMT_MINSIZE4:
  284. case TMT_MINSIZE5:
  285. case TMT_MINDPI1:
  286. case TMT_MINDPI2:
  287. case TMT_MINDPI3:
  288. case TMT_MINDPI4:
  289. case TMT_MINDPI5:
  290. //---- glyph properties ----
  291. case TMT_GLYPHTYPE:
  292. case TMT_GLYPHIMAGEFILE:
  293. case TMT_GLYPHTRANSPARENT:
  294. case TMT_GLYPHTRANSPARENTCOLOR:
  295. case TMT_GLYPHFONT:
  296. case TMT_GLYPHINDEX:
  297. case TMT_GLYPHTEXTCOLOR:
  298. case TMT_GLYPHONLY:
  299. // case TMT_FILLCOLOR: - this prop belongs to BorderFill (we borrow it)
  300. fKey = TRUE;
  301. break;
  302. }
  303. return fKey;
  304. }
  305. //---------------------------------------------------------------------------
  306. DIBINFO *CImageFile::EnumImageFiles(int iIndex)
  307. {
  308. DIBINFO *pdi = NULL;
  309. BOOL fHasGlyph = (_eGlyphType == GT_IMAGEGLYPH);
  310. //---- enum in this order: primary, glyph, multi images ----
  311. if (iIndex == 0)
  312. {
  313. pdi = &_ImageInfo;
  314. }
  315. else if (iIndex == 1)
  316. {
  317. if (fHasGlyph)
  318. pdi = &_GlyphInfo;
  319. }
  320. if (! pdi) // not yet set
  321. {
  322. if (fHasGlyph)
  323. iIndex -= 2;
  324. else
  325. iIndex -= 1;
  326. if (iIndex < _iMultiImageCount)
  327. {
  328. pdi = MultiDibPtr(iIndex);
  329. }
  330. }
  331. return pdi;
  332. }
  333. //---------------------------------------------------------------------------
  334. void CImageFile::DumpProperties(CSimpleFile *pFile, BYTE *pbThemeData, BOOL fFullInfo)
  335. {
  336. if (fFullInfo)
  337. pFile->OutLine(L"Dump of CImageFile at offset=0x%x", (BYTE *)this - pbThemeData);
  338. else
  339. pFile->OutLine(L"Dump of CImageFile");
  340. pFile->OutLine(L" _eBgType=%d", _eBgType);
  341. DIBINFO *pdi = &_ImageInfo;
  342. if (fFullInfo)
  343. {
  344. pFile->OutLine(L" iDibOffset=%d, _iImageCount=%d, _eImageLayout=%d",
  345. pdi->iDibOffset, _iImageCount, _eImageLayout);
  346. }
  347. else
  348. {
  349. pFile->OutLine(L" _iImageCount=%d, _eImageLayout=%d, MinSize=(%d, %d)",
  350. _iImageCount, _eImageLayout, pdi->szMinSize.cx, pdi->szMinSize.cy);
  351. }
  352. pFile->OutLine(L" _iSingleWidth=%d, _iSingleHeight=%d, _fMirrorImage=%d",
  353. pdi->iSingleWidth, pdi->iSingleHeight, _fMirrorImage);
  354. //---- dump multiple image info ----
  355. for (int i=0; i < _iMultiImageCount; i++)
  356. {
  357. DIBINFO *pdi = MultiDibPtr(i);
  358. pFile->OutLine(L" Multi[%d]: sw=%d, sh=%d, diboff=%d, rgnoff=%d",
  359. i, pdi->iSingleWidth, pdi->iSingleHeight,
  360. (pdi->iDibOffset > 0), (pdi->iRgnListOffset > 0));
  361. pFile->OutLine(L" MinDpi=%d, MinSize=(%d, %d)",
  362. pdi->iMinDpi, pdi->szMinSize.cx, pdi->szMinSize.cy);
  363. pFile->OutLine(L" sizetype=%d, bordonly=%d, fTrans=%d, crTrans=0x%x, fAlpha=%d, iAlphaThres=%d",
  364. pdi->eSizingType, pdi->fBorderOnly, pdi->fTransparent, pdi->crTransparent,
  365. pdi->fAlphaChannel, pdi->iAlphaThreshold);
  366. }
  367. pFile->OutLine(L" _eSizingType=%d, _fBorderOnly=%d, _eTrueSizeScalingType=%d",
  368. pdi->eSizingType, pdi->fBorderOnly, _eTrueSizeScalingType);
  369. pFile->OutLine(L" _fTransparent=%d, _crTransparent=0x%08x",
  370. pdi->fTransparent, pdi->crTransparent);
  371. pFile->OutLine(L" _fAlphaChannel=%d, _iAlphaThreshold=%d",
  372. pdi->fAlphaChannel, pdi->iAlphaThreshold);
  373. pFile->OutLine(L" _eHAlign=%d, _eVAlign=%d, _iTrueSizeStretchMark=%d",
  374. _eHAlign, _eVAlign, _iTrueSizeStretchMark);
  375. pFile->OutLine(L" _fUniformSizing=%d, _fIntegralSizing=%d",
  376. _fUniformSizing, _fIntegralSizing);
  377. pFile->OutLine(L" _fBgFill=%d, _crFill=0x%08x",
  378. _fBgFill, _crFill);
  379. pFile->OutLine(L" _fSourceGrow=%d, _fSourceShrink=%d, _szNormalSize=(%d, %d)",
  380. _fSourceGrow, _fSourceShrink, _szNormalSize.cx, _szNormalSize.cy);
  381. pFile->OutLine(L" _SizingMargins=%d, %d, %d, %d",
  382. _SizingMargins.cxLeftWidth, _SizingMargins.cxRightWidth,
  383. _SizingMargins.cyTopHeight, _SizingMargins.cyBottomHeight);
  384. pFile->OutLine(L" _ContentMargins=%d, %d, %d, %d",
  385. _ContentMargins.cxLeftWidth, _ContentMargins.cxRightWidth,
  386. _ContentMargins.cyTopHeight, _ContentMargins.cyBottomHeight);
  387. pFile->OutLine(L" _fFontGlyph=%d, _iGlyphIndex=%d, _crGlyphTextColor=0x%x",
  388. (_eGlyphType==GT_FONTGLYPH), _iGlyphIndex, _crGlyphTextColor);
  389. pFile->OutLine(L" _lfGlyphFont=%s, _fGlyphOnly=%d, _fImageGlyph=%d",
  390. _lfGlyphFont.lfFaceName, _fGlyphOnly, (_eGlyphType==GT_IMAGEGLYPH));
  391. //---- dump glyph properties ----
  392. pdi = &_GlyphInfo;
  393. if (fFullInfo)
  394. {
  395. pFile->OutLine(L" Glyph: iDibOffset=%d, iSingleWidth=%d, iSingleHeight=%d",
  396. pdi->iDibOffset, pdi->iSingleWidth, pdi->iSingleHeight);
  397. }
  398. else
  399. {
  400. pFile->OutLine(L" _iGlyphSingleWidth=%d, _iGlyphSingleHeight=%d",
  401. pdi->iSingleWidth, pdi->iSingleHeight);
  402. }
  403. pFile->OutLine(L" _fGlyphTransparent=%d, _crGlyphTransparent=0x%x, _fGlyphAlpha=%d",
  404. pdi->fTransparent, pdi->crTransparent, pdi->fAlphaChannel);
  405. //pFile->OutLine(L" Glyph: iAlphaThreshold=%d", pdi->iAlphaThreshold);
  406. }
  407. //---------------------------------------------------------------------------
  408. HRESULT CImageFile::SetImageInfo(DIBINFO *pdi, CRenderObj *pRender, int iPartId, int iStateId)
  409. {
  410. HRESULT hr = S_OK;
  411. if (! pRender->_pbThemeData)
  412. {
  413. hr = E_FAIL;
  414. goto exit;
  415. }
  416. TMBITMAPHEADER *pThemeBitmapHeader = NULL;
  417. pThemeBitmapHeader = reinterpret_cast<TMBITMAPHEADER*>(pRender->_pbThemeData + pdi->iDibOffset);
  418. ASSERT(pThemeBitmapHeader->dwSize == TMBITMAPSIZE);
  419. pdi->fAlphaChannel = pThemeBitmapHeader->fTrueAlpha;
  420. if (pdi->fAlphaChannel)
  421. {
  422. if (FAILED(pRender->GetBool(iPartId, iStateId, TMT_ALPHATHRESHOLD, &pdi->iAlphaThreshold)))
  423. pdi->iAlphaThreshold = 255;
  424. }
  425. int iWidth = - 1;
  426. int iHeight = -1;
  427. if (pThemeBitmapHeader->hBitmap)
  428. {
  429. BITMAP bmInfo;
  430. if (GetObject(pThemeBitmapHeader->hBitmap, sizeof(bmInfo), &bmInfo))
  431. {
  432. iWidth = bmInfo.bmWidth;
  433. iHeight = bmInfo.bmHeight;
  434. }
  435. else
  436. {
  437. hr = E_FAIL;
  438. }
  439. }
  440. else
  441. {
  442. BITMAPINFOHEADER* pbmInfo = BITMAPDATA(pThemeBitmapHeader);
  443. if (pbmInfo)
  444. {
  445. iWidth = pbmInfo->biWidth;
  446. iHeight = pbmInfo->biHeight;
  447. }
  448. else
  449. {
  450. hr = E_FAIL;
  451. }
  452. }
  453. //---- get SingleWidth/SingleHeight of bitmap ----
  454. if ((iWidth != -1) && (iHeight != -1))
  455. {
  456. if (_eImageLayout == IL_HORIZONTAL)
  457. {
  458. pdi->iSingleWidth = iWidth / _iImageCount;
  459. pdi->iSingleHeight = iHeight;
  460. }
  461. else // vertical
  462. {
  463. pdi->iSingleWidth = iWidth;
  464. pdi->iSingleHeight = iHeight / _iImageCount;
  465. }
  466. }
  467. exit:
  468. return hr;
  469. }
  470. //---------------------------------------------------------------------------
  471. BOOL CImageFile::HasRegionImageFile(DIBINFO *pdi, int *piMaxState)
  472. {
  473. BOOL fGot = FALSE;
  474. if ((pdi->fTransparent) || (pdi->fAlphaChannel))
  475. {
  476. if (pdi->iDibOffset > 0)
  477. {
  478. fGot = TRUE;
  479. *piMaxState = _iImageCount;
  480. }
  481. }
  482. return fGot;
  483. }
  484. //---------------------------------------------------------------------------
  485. void CImageFile::SetRgnListOffset(DIBINFO *pdi, int iOffset)
  486. {
  487. //---- get offset to the actual jump table ----
  488. pdi->iRgnListOffset = iOffset + ENTRYHDR_SIZE;
  489. }
  490. //---------------------------------------------------------------------------
  491. HRESULT CImageFile::BuildRgnData(DIBINFO *pdi, CRenderObj *pRender, int iStateId, RGNDATA **ppRgnData,
  492. int *piDataLen)
  493. {
  494. RESOURCE HRGN hrgn = NULL;
  495. RESOURCE RGNDATA *pRgnData = NULL;
  496. int iTotalBytes = 0;
  497. int iRectCount;
  498. DWORD len, len2;
  499. HBITMAP hBitmap = NULL;
  500. HRESULT hr = S_OK;
  501. BOOL fStock = FALSE;
  502. if ((! pdi->fAlphaChannel) && (! pdi->fTransparent)) // empty region
  503. goto gotit;
  504. if (pRender->_pbThemeData && pdi->iDibOffset > 0)
  505. {
  506. fStock = ((reinterpret_cast<TMBITMAPHEADER*>(pRender->_pbThemeData + pdi->iDibOffset))->hBitmap != NULL);
  507. }
  508. hr = pRender->GetBitmap(NULL, pdi->iDibOffset, &hBitmap);
  509. if (FAILED(hr))
  510. goto exit;
  511. int iXOffset, iYOffset;
  512. GetOffsets(iStateId, pdi, &iXOffset, &iYOffset);
  513. //---- create a region ----
  514. hr = CreateBitmapRgn(hBitmap, iXOffset, iYOffset, pdi->iSingleWidth, pdi->iSingleHeight,
  515. pdi->fAlphaChannel, pdi->iAlphaThreshold, pdi->crTransparent, 0, &hrgn);
  516. if (FAILED(hr))
  517. {
  518. //---- soft error - author said it was transparent but it wasn't ----
  519. hr = S_OK;
  520. goto gotit;
  521. }
  522. //---- extract region data ----
  523. len = GetRegionData(hrgn, 0, NULL); // get required length
  524. if (! len)
  525. {
  526. hr = MakeErrorLast();
  527. goto exit;
  528. }
  529. iRectCount = len/sizeof(RECT); // # of rects
  530. len += ((sizeof(BYTE)+sizeof(BYTE))*iRectCount); // room for grid id's for each point
  531. iTotalBytes = len + sizeof(RGNDATAHEADER);
  532. pRgnData = (RGNDATA *) new BYTE[iTotalBytes];
  533. len2 = GetRegionData(hrgn, len, pRgnData);
  534. if (! len2)
  535. {
  536. hr = MakeErrorLast();
  537. goto exit;
  538. }
  539. //---- grid-ize the point values within each rect ----
  540. RECT rcImage;
  541. SetRect( &rcImage, 0, 0, pdi->iSingleWidth, pdi->iSingleHeight );
  542. hr = pRender->PrepareRegionDataForScaling(pRgnData, &rcImage, &_SizingMargins);
  543. if (FAILED(hr))
  544. goto exit;
  545. gotit:
  546. *ppRgnData = pRgnData;
  547. *piDataLen = iTotalBytes;
  548. exit:
  549. if (hBitmap && !fStock)
  550. {
  551. pRender->ReturnBitmap(hBitmap);
  552. }
  553. if (hrgn)
  554. DeleteObject(hrgn);
  555. if (FAILED(hr))
  556. {
  557. if (pRgnData)
  558. delete [] pRgnData;
  559. }
  560. return hr;
  561. }
  562. //---------------------------------------------------------------------------
  563. // Helper function for DrawBackgroundDS
  564. void StreamSetSource(BYTE** pvStream, HBITMAP hbmSrc)
  565. {
  566. DS_SETSOURCE* pdsSetSource = (DS_SETSOURCE*)*pvStream;
  567. pdsSetSource->ulCmdID = DS_SETSOURCEID;
  568. pdsSetSource->hbm = HandleToULong(hbmSrc);
  569. *pvStream += sizeof(DS_SETSOURCE);
  570. }
  571. //---------------------------------------------------------------------------
  572. void StreamInit(BYTE** pvStream, HDC hdcDest, HBITMAP hbmSrc, RECTL* prcl)
  573. {
  574. DS_HEADER* pdsHeader = (DS_HEADER*)*pvStream;
  575. pdsHeader->magic = DS_MAGIC;
  576. *pvStream += sizeof(DS_HEADER);
  577. DS_SETTARGET* pdsSetTarget = (DS_SETTARGET*)*pvStream;
  578. pdsSetTarget->ulCmdID = DS_SETTARGETID;
  579. pdsSetTarget->hdc = HandleToULong(hdcDest);
  580. pdsSetTarget->rclDstClip = *prcl;
  581. *pvStream += sizeof(DS_SETTARGET);
  582. StreamSetSource(pvStream, hbmSrc);
  583. }
  584. //---------------------------------------------------------------------------
  585. HBITMAP CreateScaledTempBitmap(HDC hdc, HBITMAP hSrcBitmap, int ixSrcOffset, int iySrcOffset,
  586. int iSrcWidth, int iSrcHeight, int iDestWidth, int iDestHeight)
  587. {
  588. HBITMAP hTempBitmap = NULL;
  589. if (hSrcBitmap) // create a DIB from caller's bitmap (Clipper test program)
  590. {
  591. //---- reuse our bitmap ----
  592. hTempBitmap = g_pBitmapCacheScaled->AcquireBitmap(hdc, iDestWidth, iDestHeight);
  593. if (hTempBitmap)
  594. {
  595. HDC hdcDest = CreateCompatibleDC(hdc);
  596. if (hdcDest)
  597. {
  598. HBITMAP hOldDestBitmap = (HBITMAP)SelectObject(hdcDest, hTempBitmap);
  599. HDC hdcSrc = CreateCompatibleDC(hdc);
  600. if (hdcSrc)
  601. {
  602. SetLayout(hdcSrc, 0);
  603. SetLayout(hdcDest, 0);
  604. HBITMAP hOldSrcBitmap = (HBITMAP) SelectObject(hdcSrc, hSrcBitmap);
  605. int iOldSM = SetStretchBltMode(hdcDest, COLORONCOLOR);
  606. //---- stretch src to dest ----
  607. StretchBlt(hdcDest, 0, 0, iDestWidth, iDestHeight,
  608. hdcSrc, ixSrcOffset, iySrcOffset, iSrcWidth, iSrcHeight,
  609. SRCCOPY);
  610. SetStretchBltMode(hdcDest, iOldSM);
  611. SelectObject(hdcSrc, hOldSrcBitmap);
  612. DeleteDC(hdcSrc);
  613. }
  614. SelectObject(hdcDest, hOldDestBitmap);
  615. DeleteDC(hdcDest);
  616. }
  617. }
  618. }
  619. return hTempBitmap;
  620. }
  621. //---------------------------------------------------------------------------
  622. HBITMAP CreateUnscaledTempBitmap(HDC hdc, HBITMAP hSrcBitmap, int ixSrcOffset, int iySrcOffset,
  623. int iDestWidth, int iDestHeight)
  624. {
  625. HBITMAP hTempBitmap = NULL;
  626. if (hSrcBitmap) // create a DIB from caller's bitmap (Clipper test program)
  627. {
  628. //---- reuse our bitmap ----
  629. hTempBitmap = g_pBitmapCacheUnscaled->AcquireBitmap(hdc, iDestWidth, iDestHeight);
  630. if (hTempBitmap)
  631. {
  632. HDC hdcDest = CreateCompatibleDC(hdc);
  633. if (hdcDest)
  634. {
  635. HBITMAP hOldDestBitmap = (HBITMAP) SelectObject(hdcDest, hTempBitmap);
  636. HDC hdcSrc = CreateCompatibleDC(hdc);
  637. if (hdcSrc)
  638. {
  639. SetLayout(hdcSrc, 0);
  640. SetLayout(hdcDest, 0);
  641. HBITMAP hOldSrcBitmap = (HBITMAP) SelectObject(hdcSrc, hSrcBitmap);
  642. //---- copy src to dest ----
  643. BitBlt(hdcDest, 0, 0, iDestWidth, iDestHeight, hdcSrc, ixSrcOffset, iySrcOffset,
  644. SRCCOPY);
  645. SelectObject(hdcSrc, hOldSrcBitmap);
  646. DeleteDC(hdcSrc);
  647. }
  648. SelectObject(hdcDest, hOldDestBitmap);
  649. DeleteDC(hdcDest);
  650. }
  651. }
  652. }
  653. return hTempBitmap;
  654. }
  655. //---------------------------------------------------------------------------
  656. HRESULT CImageFile::DrawBackgroundDS(DIBINFO *pdi, TMBITMAPHEADER *pThemeBitmapHeader, BOOL fStock,
  657. CRenderObj *pRender, HDC hdc, int iStateId, const RECT *pRect, BOOL fForceStretch,
  658. MARGINS *pmarDest, float xMarginFactor, float yMarginFactor, OPTIONAL const DTBGOPTS *pOptions)
  659. {
  660. //---- bitmaps we may create ----
  661. HBITMAP hBitmapStock = NULL;
  662. HBITMAP hBitmapTempScaled = NULL;
  663. HBITMAP hBitmapTempUnscaled = NULL;
  664. //---- copy of bitmap handle to use ----
  665. HBITMAP hDsBitmap = NULL;
  666. HRESULT hr = S_OK;
  667. int iTempSrcWidth = pdi->iSingleWidth;
  668. int iTempSrcHeight = pdi->iSingleHeight;
  669. int iXOffset, iYOffset;
  670. GetOffsets(iStateId, pdi, &iXOffset, &iYOffset);
  671. if (pThemeBitmapHeader) // get stock bitmap (32 bit format)
  672. {
  673. hr = pRender->GetBitmap(hdc, pdi->iDibOffset, &hBitmapStock);
  674. if (FAILED(hr))
  675. goto exit;
  676. hDsBitmap = hBitmapStock;
  677. }
  678. else // caller passed in bitmap (unknown format)
  679. {
  680. hBitmapTempUnscaled = CreateUnscaledTempBitmap(hdc, pdi->hProcessBitmap, iXOffset, iYOffset,
  681. pdi->iSingleWidth, pdi->iSingleHeight);
  682. if (! hBitmapTempUnscaled)
  683. {
  684. hr = E_FAIL;
  685. goto exit;
  686. }
  687. hDsBitmap = hBitmapTempUnscaled;
  688. //---- src is now just a single image ----
  689. iXOffset = iYOffset = 0;
  690. }
  691. //---- handle scaled margins ----
  692. if ((xMarginFactor != 1) || (yMarginFactor != 1))
  693. {
  694. iTempSrcWidth = int(pdi->iSingleWidth * xMarginFactor);
  695. iTempSrcHeight = int(pdi->iSingleHeight * yMarginFactor);
  696. hBitmapTempScaled = CreateScaledTempBitmap(hdc, hDsBitmap, iXOffset, iYOffset,
  697. pdi->iSingleWidth, pdi->iSingleHeight, iTempSrcWidth, iTempSrcHeight);
  698. if (! hBitmapTempScaled)
  699. {
  700. hr = E_FAIL;
  701. goto exit;
  702. }
  703. hDsBitmap = hBitmapTempScaled;
  704. //---- src is now just a single image ----
  705. iXOffset = iYOffset = 0;
  706. }
  707. if (hDsBitmap)
  708. {
  709. RECTL rclSrc = { iXOffset, iYOffset, iXOffset + iTempSrcWidth, iYOffset + iTempSrcHeight };
  710. RECTL rclDest = { pRect->left, pRect->top, pRect->right, pRect->bottom };
  711. // Flip Dest Rect if someone passed us inverted co-ordinates
  712. if (rclDest.left > rclDest.right)
  713. {
  714. int xTemp = rclDest.left;
  715. rclDest.left = rclDest.right;
  716. rclDest.right = xTemp;
  717. }
  718. if (rclDest.top > rclDest.bottom)
  719. {
  720. int yTemp = rclDest.bottom;
  721. rclDest.bottom = rclDest.top;
  722. rclDest.top = yTemp;
  723. }
  724. DWORD dwOptionFlags = 0;
  725. if (pOptions)
  726. {
  727. dwOptionFlags = pOptions->dwFlags;
  728. }
  729. // Initialize Drawing Stream
  730. BYTE stream[500];
  731. BYTE* pvStreamStart = stream;
  732. BYTE* pvStream = stream;
  733. RECTL rclClip = rclDest;
  734. if (dwOptionFlags & DTBG_CLIPRECT)
  735. {
  736. IntersectRect((LPRECT)&rclClip, (LPRECT)&rclDest, &pOptions->rcClip);
  737. }
  738. StreamInit(&pvStream, hdc, hDsBitmap, &rclClip);
  739. DS_NINEGRID* pvNineGrid = (DS_NINEGRID*)pvStream;
  740. pvNineGrid->ulCmdID = DS_NINEGRIDID;
  741. if ((fForceStretch) || (pdi->eSizingType == ST_STRETCH))
  742. {
  743. pvNineGrid->ngi.flFlags = DSDNG_STRETCH;
  744. }
  745. else if (pdi->eSizingType == ST_TRUESIZE)
  746. {
  747. pvNineGrid->ngi.flFlags = DSDNG_TRUESIZE;
  748. }
  749. else
  750. {
  751. pvNineGrid->ngi.flFlags = DSDNG_TILE;
  752. }
  753. if (pdi->fAlphaChannel)
  754. {
  755. pvNineGrid->ngi.flFlags |= DSDNG_PERPIXELALPHA;
  756. }
  757. else if (pdi->fTransparent)
  758. {
  759. pvNineGrid->ngi.flFlags |= DSDNG_TRANSPARENT;
  760. }
  761. if ((dwOptionFlags & DTBG_MIRRORDC) || (IsMirrored(hdc)))
  762. {
  763. if (_fMirrorImage)
  764. {
  765. pvNineGrid->ngi.flFlags |= DSDNG_MUSTFLIP;
  766. //---- workaround: needed by GdiDrawStream if we don't have a mirrored DC ----
  767. //---- gdi should only look at the DSDNG_MUSTFLIP flag ----
  768. if (! IsMirrored(hdc))
  769. {
  770. int xTemp = rclDest.left;
  771. rclDest.left = rclDest.right;
  772. rclDest.right = xTemp;
  773. }
  774. }
  775. }
  776. pvNineGrid->rclDst = rclDest;
  777. pvNineGrid->rclSrc = rclSrc;
  778. if (pdi->eSizingType == ST_TRUESIZE)
  779. {
  780. pvNineGrid->ngi.ulLeftWidth = 0;
  781. pvNineGrid->ngi.ulRightWidth = 0;
  782. pvNineGrid->ngi.ulTopHeight = 0;
  783. pvNineGrid->ngi.ulBottomHeight = 0;
  784. }
  785. else
  786. {
  787. //---- copy scaled Src margins ----
  788. pvNineGrid->ngi.ulLeftWidth = pmarDest->cxLeftWidth;
  789. pvNineGrid->ngi.ulRightWidth = pmarDest->cxRightWidth;
  790. pvNineGrid->ngi.ulTopHeight = pmarDest->cyTopHeight;
  791. pvNineGrid->ngi.ulBottomHeight = pmarDest->cyBottomHeight;
  792. }
  793. pvNineGrid->ngi.crTransparent = pdi->crTransparent;
  794. pvStream += sizeof(DS_NINEGRID);
  795. GdiDrawStream(hdc, (int)(pvStream - pvStreamStart), (char*) pvStreamStart);
  796. }
  797. else
  798. {
  799. hr = E_FAIL;
  800. }
  801. exit:
  802. //---- clean up temp bitmaps ----
  803. if (hBitmapTempScaled)
  804. {
  805. g_pBitmapCacheScaled->ReturnBitmap();
  806. }
  807. if (hBitmapTempUnscaled)
  808. {
  809. g_pBitmapCacheUnscaled->ReturnBitmap();
  810. }
  811. if ((hBitmapStock) && (! fStock)) // not really stock (was "create on demand")
  812. {
  813. pRender->ReturnBitmap(hBitmapStock);
  814. }
  815. return hr;
  816. }
  817. //---------------------------------------------------------------------------
  818. HRESULT CImageFile::DrawBackgroundDNG(DIBINFO *pdi, TMBITMAPHEADER *pThemeBitmapHeader, BOOL fStock, CRenderObj *pRender,
  819. HDC hdc, int iStateId, const RECT *pRect, BOOL fForceStretch,
  820. MARGINS *pmarDest, OPTIONAL const DTBGOPTS *pOptions)
  821. {
  822. HRESULT hr = E_FAIL;
  823. //---- options ----
  824. DWORD dwOptionFlags = 0;
  825. const RECT *pClipRect = NULL;
  826. if (pOptions)
  827. {
  828. dwOptionFlags = pOptions->dwFlags;
  829. if (dwOptionFlags & DTBG_CLIPRECT)
  830. pClipRect = &pOptions->rcClip;
  831. }
  832. int iXOffset, iYOffset;
  833. GetOffsets(iStateId, pdi, &iXOffset, &iYOffset);
  834. DWORD dwFlags = 0;
  835. if (! (dwOptionFlags & DTBG_DRAWSOLID))
  836. {
  837. if (pdi->fTransparent)
  838. {
  839. dwFlags = NGI_TRANS;
  840. }
  841. if (pdi->fAlphaChannel)
  842. {
  843. dwFlags = NGI_ALPHA;
  844. }
  845. }
  846. ULONG* pvSrcBits = NULL;
  847. int iWidth = 0;
  848. int iHeight = 0;
  849. BOOL fFreeBits = FALSE;
  850. if (pThemeBitmapHeader)
  851. {
  852. BITMAPINFOHEADER* pHeader = BITMAPDATA(pThemeBitmapHeader);
  853. if (pHeader && pHeader->biBitCount == 32)
  854. {
  855. pvSrcBits = (ULONG*)DIBDATA(pHeader);
  856. }
  857. iWidth = pHeader->biWidth;
  858. iHeight = pHeader->biHeight;
  859. }
  860. else if (pdi->hProcessBitmap)
  861. {
  862. BITMAP bm;
  863. if (GetObject(pdi->hProcessBitmap, sizeof(bm), &bm))
  864. {
  865. BITMAPINFO bmInfo = {{sizeof(BITMAPINFOHEADER), bm.bmWidth, bm.bmHeight, 1, 32, BI_RGB, 0, 0, 0, 0, 0}, NULL};
  866. pvSrcBits = new DWORD[bm.bmWidth * bm.bmHeight];
  867. if (pvSrcBits)
  868. {
  869. if (GetDIBits(hdc, pdi->hProcessBitmap, 0, bm.bmHeight, pvSrcBits, &bmInfo, DIB_RGB_COLORS))
  870. {
  871. fFreeBits = TRUE;
  872. iWidth = bm.bmWidth;
  873. iHeight = bm.bmHeight;
  874. }
  875. else
  876. {
  877. delete[] pvSrcBits;
  878. pvSrcBits = NULL;
  879. }
  880. }
  881. }
  882. }
  883. if (pvSrcBits)
  884. {
  885. NGIMAGE ngi;
  886. ngi.hbm = NULL;
  887. ngi.iWidth = pdi->iSingleWidth;
  888. ngi.iHeight = pdi->iSingleHeight;
  889. ngi.margin = _SizingMargins;
  890. //ngi.marDest = *pmarDest;
  891. ngi.dwFlags = dwFlags;
  892. ngi.crTrans = pdi->crTransparent;
  893. if (fForceStretch)
  894. ngi.eSize = ST_STRETCH;
  895. else
  896. ngi.eSize = pdi->eSizingType;
  897. DWORD dwDNGFlags = 0;
  898. if ((dwOptionFlags & DTBG_MIRRORDC) || (IsMirrored(hdc)))
  899. {
  900. if (_fMirrorImage)
  901. {
  902. dwDNGFlags |= DNG_MUSTFLIP;
  903. }
  904. }
  905. ngi.iBufWidth = iWidth;
  906. int iDibOffset = (iHeight - iYOffset) - pdi->iSingleHeight;
  907. ngi.pvBits = pvSrcBits + (iDibOffset * ngi.iBufWidth) + iXOffset;
  908. RECT rcDest = *pRect;
  909. if (pdi->fBorderOnly &&
  910. (RECTHEIGHT(&rcDest) > ngi.margin.cyTopHeight + ngi.margin.cyBottomHeight) &&
  911. (RECTWIDTH(&rcDest) > ngi.margin.cxLeftWidth + ngi.margin.cxRightWidth))
  912. {
  913. RECT rcTop = rcDest;
  914. RECT rcLeft = rcDest;
  915. RECT rcBottom = rcDest;
  916. RECT rcRight = rcDest;
  917. rcLeft.top = rcRight.top = rcTop.bottom = rcTop.top + ngi.margin.cyTopHeight;
  918. rcLeft.bottom = rcRight.bottom = rcBottom.top = rcBottom.bottom - ngi.margin.cyBottomHeight;
  919. rcLeft.right = rcLeft.left + ngi.margin.cxLeftWidth;
  920. rcRight.left = rcRight.right - ngi.margin.cxRightWidth;
  921. if (pClipRect)
  922. {
  923. IntersectRect(&rcLeft, pClipRect, &rcLeft);
  924. IntersectRect(&rcTop, pClipRect, &rcTop);
  925. IntersectRect(&rcRight, pClipRect, &rcRight);
  926. IntersectRect(&rcBottom, pClipRect, &rcBottom);
  927. }
  928. hr = DrawNineGrid2(hdc, &ngi, &rcDest, &rcTop, dwDNGFlags);
  929. if (SUCCEEDED(hr))
  930. {
  931. hr = DrawNineGrid2(hdc, &ngi, &rcDest, &rcLeft, dwDNGFlags);
  932. if (SUCCEEDED(hr))
  933. {
  934. hr = DrawNineGrid2(hdc, &ngi, &rcDest, &rcRight, dwDNGFlags);
  935. if (SUCCEEDED(hr))
  936. {
  937. hr = DrawNineGrid2(hdc, &ngi, &rcDest, &rcBottom, dwDNGFlags);
  938. }
  939. }
  940. }
  941. }
  942. else
  943. {
  944. hr = DrawNineGrid2(hdc, &ngi, &rcDest, pClipRect, dwDNGFlags);
  945. }
  946. if (fFreeBits)
  947. {
  948. delete[] pvSrcBits;
  949. }
  950. }
  951. if (FAILED(hr))
  952. {
  953. Log(LOG_ALWAYS, L"DrawBackground FAILED: class=%s, hr=0x%x",
  954. SHARECLASS(pRender), hr);
  955. }
  956. return hr;
  957. }
  958. //---------------------------------------------------------------------------
  959. DIBINFO *CImageFile::SelectCorrectImageFile(CRenderObj *pRender, HDC hdc, OPTIONAL const RECT *prc,
  960. BOOL fForGlyph, OPTIONAL TRUESTRETCHINFO *ptsInfo)
  961. {
  962. DIBINFO *pdiDefault = (fForGlyph) ? &_GlyphInfo : &_ImageInfo;
  963. DIBINFO *pdi = NULL;
  964. BOOL fForceRectSizing = FALSE;
  965. int iWidth = 1;
  966. int iHeight = 1;
  967. //---- do we need a screen dc? ----
  968. BOOL fReleaseDC = FALSE;
  969. if (! hdc)
  970. {
  971. hdc = GetWindowDC(NULL);
  972. if (hdc)
  973. fReleaseDC = TRUE;
  974. }
  975. if (prc)
  976. {
  977. iWidth = WIDTH(*prc);
  978. iHeight = HEIGHT(*prc);
  979. }
  980. //---- see if our clients wants to force a TRUESIZE to stretch ----
  981. if ((fForGlyph) || (_ImageInfo.eSizingType == ST_TRUESIZE))
  982. {
  983. if ((pRender) && (pRender->_dwOtdFlags & OTD_FORCE_RECT_SIZING))
  984. {
  985. fForceRectSizing = TRUE;
  986. }
  987. }
  988. //---- find correct file by DPI or Size ----
  989. if ((fForGlyph) || (_eGlyphType != GT_IMAGEGLYPH)) // match multifiles to reg or glyph
  990. {
  991. BOOL fSizing = FALSE;
  992. BOOL fDpi = FALSE;
  993. if ((fForceRectSizing) || (_eImageSelectType == IST_SIZE) || (_fSourceGrow))
  994. {
  995. if (prc)
  996. fSizing = TRUE;
  997. }
  998. else
  999. {
  1000. fDpi = (_eImageSelectType == IST_DPI);
  1001. }
  1002. if (fDpi) // DPI-based image selection
  1003. {
  1004. int iMinDestDpi = __min(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
  1005. //---- search from largest to smallest ----
  1006. for (int i=_iMultiImageCount-1; i >= 0; i--)
  1007. {
  1008. if (MultiDibPtr(i)->iMinDpi <= iMinDestDpi) // got him
  1009. {
  1010. pdi = MultiDibPtr(i);
  1011. break;
  1012. }
  1013. }
  1014. }
  1015. else if (fSizing) // Sizing-base image selection
  1016. {
  1017. if (_iMultiImageCount)
  1018. {
  1019. //---- search from largest to smallest ----
  1020. for (int i=_iMultiImageCount-1; i >= 0; i--)
  1021. {
  1022. DIBINFO *pdii = MultiDibPtr(i);
  1023. if ((pdii->szMinSize.cx <= iWidth) && (pdii->szMinSize.cy <= iHeight))
  1024. {
  1025. pdi = pdii;
  1026. break;
  1027. }
  1028. }
  1029. }
  1030. }
  1031. }
  1032. if (! pdi) // no match found
  1033. {
  1034. pdi = pdiDefault;
  1035. }
  1036. //---- determine drawing size of selected file (MultiImage or regular) ----
  1037. if (ptsInfo)
  1038. {
  1039. ptsInfo->fForceStretch = FALSE;
  1040. ptsInfo->fFullStretch = FALSE;
  1041. ptsInfo->szDrawSize.cx = 0;
  1042. ptsInfo->szDrawSize.cy = 0;
  1043. //---- this sizing only applies to TRUESIZE images ----
  1044. if ((pdi->eSizingType == ST_TRUESIZE) && (_eTrueSizeScalingType != TSST_NONE))
  1045. {
  1046. if (prc)
  1047. {
  1048. //---- force an exact stretch match? ----
  1049. if ((fForceRectSizing) || (pdi->iSingleWidth > iWidth) || (pdi->iSingleHeight > iHeight))
  1050. {
  1051. //---- either Forced to stretch by caller or image is too big for dest RECT ----
  1052. ptsInfo->fForceStretch = TRUE;
  1053. ptsInfo->fFullStretch = TRUE;
  1054. ptsInfo->szDrawSize.cx = iWidth;
  1055. ptsInfo->szDrawSize.cy = iHeight;
  1056. }
  1057. }
  1058. if (! ptsInfo->fForceStretch) // keep trying..
  1059. {
  1060. //---- see if image is too small for dest RECT ---
  1061. SIZE szTargetSize = {0, 0};
  1062. if (_eTrueSizeScalingType == TSST_DPI)
  1063. {
  1064. int ixDpiDc = GetDeviceCaps(hdc, LOGPIXELSX);
  1065. int iyDpiDc = GetDeviceCaps(hdc, LOGPIXELSY);
  1066. szTargetSize.cx = MulDiv(pdi->iSingleWidth, ixDpiDc, pdi->iMinDpi);
  1067. szTargetSize.cy = MulDiv(pdi->iSingleHeight, iyDpiDc, pdi->iMinDpi);
  1068. }
  1069. else if ((_eTrueSizeScalingType == TSST_SIZE) && (prc))
  1070. {
  1071. szTargetSize.cx = MulDiv(pdi->iSingleWidth, iWidth, pdi->szMinSize.cx);
  1072. szTargetSize.cy = MulDiv(pdi->iSingleHeight, iHeight, pdi->szMinSize.cy);
  1073. }
  1074. if (szTargetSize.cx) // was set
  1075. {
  1076. //---- clip targetsize against dest rect ----
  1077. if (prc)
  1078. {
  1079. szTargetSize.cx = __min(szTargetSize.cx, iWidth);
  1080. szTargetSize.cy = __min(szTargetSize.cy, iHeight);
  1081. }
  1082. int ixPercentExceed = 100*(szTargetSize.cx - pdi->iSingleWidth)/pdi->iSingleWidth;
  1083. int iyPercentExceed = 100*(szTargetSize.cy - pdi->iSingleHeight)/pdi->iSingleHeight;
  1084. if ((ixPercentExceed >= _iTrueSizeStretchMark) && (iyPercentExceed >= _iTrueSizeStretchMark))
  1085. {
  1086. ptsInfo->fForceStretch = TRUE;
  1087. ptsInfo->szDrawSize = szTargetSize;
  1088. }
  1089. }
  1090. }
  1091. }
  1092. }
  1093. if (! pdi)
  1094. {
  1095. pdi = pdiDefault;
  1096. }
  1097. if (fReleaseDC)
  1098. {
  1099. ReleaseDC(NULL, hdc);
  1100. }
  1101. return pdi;
  1102. }
  1103. //---------------------------------------------------------------------------
  1104. void CImageFile::GetDrawnImageSize(DIBINFO *pdi, const RECT *pRect, TRUESTRETCHINFO *ptsInfo,
  1105. SIZE *pszDraw)
  1106. {
  1107. //---- szDraw is the size image will be drawn to ----
  1108. if (pdi->eSizingType == ST_TRUESIZE)
  1109. {
  1110. if (ptsInfo->fForceStretch)
  1111. {
  1112. *pszDraw = ptsInfo->szDrawSize;
  1113. //---- integral sizing (stretched truesize only) ----
  1114. if ((_fIntegralSizing) && (! ptsInfo->fFullStretch))
  1115. {
  1116. float flFactX = float(ptsInfo->szDrawSize.cx)/pdi->iSingleWidth;
  1117. float flFactY = float(ptsInfo->szDrawSize.cy)/pdi->iSingleHeight;
  1118. //---- cast float's to int to get lowest int (vs. rounded) ----
  1119. pszDraw->cx = pdi->iSingleWidth * int(flFactX);
  1120. pszDraw->cy = pdi->iSingleHeight * int(flFactY);
  1121. }
  1122. }
  1123. else // use original image size
  1124. {
  1125. pszDraw->cx = pdi->iSingleWidth;
  1126. pszDraw->cy = pdi->iSingleHeight;
  1127. }
  1128. //---- Uniform Sizing ----
  1129. if (_fUniformSizing)
  1130. {
  1131. int iSingleWidth = pdi->iSingleWidth;
  1132. int iSingleHeight = pdi->iSingleHeight;
  1133. double fact1 = double(pszDraw->cx)/iSingleWidth;
  1134. double fact2 = double(pszDraw->cy)/iSingleHeight;
  1135. //---- select the smallest factor to use for both dims ----
  1136. if (fact1 < fact2)
  1137. {
  1138. pszDraw->cy = int(iSingleHeight*fact1);
  1139. }
  1140. else if (fact1 > fact2)
  1141. {
  1142. pszDraw->cx = int(iSingleWidth*fact2);
  1143. }
  1144. }
  1145. }
  1146. else // ST_TILE or ST_STRETCH: pRect determines size
  1147. {
  1148. if (pRect)
  1149. {
  1150. pszDraw->cx = WIDTH(*pRect);
  1151. pszDraw->cy = HEIGHT(*pRect);
  1152. }
  1153. else // void function so just return 0
  1154. {
  1155. pszDraw->cx = 0;
  1156. pszDraw->cy = 0;
  1157. }
  1158. }
  1159. }
  1160. //---------------------------------------------------------------------------
  1161. HRESULT CImageFile::DrawImageInfo(DIBINFO *pdi, CRenderObj *pRender, HDC hdc, int iStateId,
  1162. const RECT *pRect, const DTBGOPTS *pOptions, TRUESTRETCHINFO *ptsInfo)
  1163. {
  1164. HRESULT hr = S_OK;
  1165. TMBITMAPHEADER *pThemeBitmapHeader = NULL;
  1166. BOOL fStock = FALSE;
  1167. RECT rcLocal;
  1168. DWORD dwFlags;
  1169. SIZE szDraw;
  1170. BOOL fRectFilled;
  1171. MARGINS marDest;
  1172. float xFactor;
  1173. float yFactor;
  1174. if (pOptions)
  1175. dwFlags = pOptions->dwFlags;
  1176. else
  1177. dwFlags = 0;
  1178. //---- validate bitmap header ----
  1179. if (! pdi->hProcessBitmap) // regular, section based DIB
  1180. {
  1181. if (pRender->_pbThemeData && pdi->iDibOffset > 0)
  1182. {
  1183. pThemeBitmapHeader = reinterpret_cast<TMBITMAPHEADER*>(pRender->_pbThemeData + pdi->iDibOffset);
  1184. ASSERT(pThemeBitmapHeader->dwSize == TMBITMAPSIZE);
  1185. fStock = (pThemeBitmapHeader->hBitmap != NULL);
  1186. }
  1187. if (!pRender->IsReady())
  1188. {
  1189. // Stock bitmaps in section are cleaning, don't try to paint with an old HBITMAP
  1190. hr = E_FAIL;
  1191. //Log(LOG_TMBITMAP, L"Obsolete theme section: class=%s", SHARECLASS(pRender));
  1192. goto exit;
  1193. }
  1194. if (pThemeBitmapHeader == NULL)
  1195. {
  1196. hr = E_FAIL;
  1197. Log(LOG_ALWAYS, L"No TMBITMAPHEADER: class=%s, hr=0x%x", SHARECLASS(pRender), hr);
  1198. goto exit;
  1199. }
  1200. }
  1201. //----- set szDraw to size image will be drawn at ----
  1202. GetDrawnImageSize(pdi, pRect, ptsInfo, &szDraw);
  1203. rcLocal = *pRect;
  1204. fRectFilled = TRUE;
  1205. //---- horizontal alignment ----
  1206. if (WIDTH(rcLocal) > szDraw.cx)
  1207. {
  1208. fRectFilled = FALSE;
  1209. if (_eHAlign == HA_LEFT)
  1210. {
  1211. rcLocal.right = rcLocal.left + szDraw.cx;
  1212. }
  1213. else if (_eHAlign == HA_CENTER)
  1214. {
  1215. rcLocal.left += (WIDTH(rcLocal) - szDraw.cx) / 2;
  1216. rcLocal.right = rcLocal.left + szDraw.cx;
  1217. }
  1218. else
  1219. {
  1220. rcLocal.left = rcLocal.right - szDraw.cx;
  1221. }
  1222. }
  1223. //---- vertical alignment ----
  1224. if (HEIGHT(rcLocal) > szDraw.cy)
  1225. {
  1226. fRectFilled = FALSE;
  1227. if (_eVAlign == VA_TOP)
  1228. {
  1229. rcLocal.bottom = rcLocal.top + szDraw.cy;
  1230. }
  1231. else if (_eVAlign == VA_CENTER)
  1232. {
  1233. rcLocal.top += (HEIGHT(rcLocal) - szDraw.cy) / 2;
  1234. rcLocal.bottom = rcLocal.top + szDraw.cy;
  1235. }
  1236. else
  1237. {
  1238. rcLocal.top = rcLocal.bottom - szDraw.cy;
  1239. }
  1240. }
  1241. //---- BgFill ----
  1242. if ((! fRectFilled) && (! pdi->fBorderOnly) && (_fBgFill))
  1243. {
  1244. if (! (dwFlags & DTBG_OMITCONTENT))
  1245. {
  1246. //---- paint bg ----
  1247. HBRUSH hbr = CreateSolidBrush(_crFill);
  1248. if (! hbr)
  1249. {
  1250. hr = GetLastError();
  1251. goto exit;
  1252. }
  1253. FillRect(hdc, pRect, hbr);
  1254. DeleteObject(hbr);
  1255. }
  1256. }
  1257. //---- calculate source/margin scaling factors ----
  1258. marDest = _SizingMargins;
  1259. if (pdi->eSizingType == ST_TRUESIZE) // sizing margins ignored - no scaling needed
  1260. {
  1261. xFactor = 1;
  1262. yFactor = 1;
  1263. }
  1264. else
  1265. {
  1266. //---- scale destination sizing margins ----
  1267. ScaleMargins(&marDest, hdc, pRender, pdi, &szDraw, &xFactor, &yFactor);
  1268. }
  1269. #if 1 // keep this in sync with #if in parser.cpp
  1270. //---- new GDI drawing ----
  1271. hr = DrawBackgroundDS(pdi, pThemeBitmapHeader, fStock, pRender, hdc, iStateId, &rcLocal,
  1272. ptsInfo->fForceStretch, &marDest, xFactor, yFactor, pOptions);
  1273. #else
  1274. //---- old drawing (keep around until DS is burned in) ----
  1275. hr = DrawBackgroundDNG(pdi, pThemeBitmapHeader, fStock, pRender, hdc, iStateId, &rcLocal,
  1276. ptsInfo->fForceStretch, &marDest, pOptions);
  1277. #endif
  1278. exit:
  1279. return hr;
  1280. }
  1281. //---------------------------------------------------------------------------
  1282. HRESULT CImageFile::DrawBackground(CRenderObj *pRender, HDC hdc, int iStateId,
  1283. const RECT *pRect, OPTIONAL const DTBGOPTS *pOptions)
  1284. {
  1285. HRESULT hr = S_OK;
  1286. TRUESTRETCHINFO tsInfo;
  1287. if (! _fGlyphOnly)
  1288. {
  1289. DIBINFO *pdi = SelectCorrectImageFile(pRender, hdc, pRect, FALSE, &tsInfo);
  1290. //---- draw normal image ----
  1291. hr = DrawImageInfo(pdi, pRender, hdc, iStateId, pRect, pOptions, &tsInfo);
  1292. }
  1293. //---- draw glyph, if needed ----
  1294. if (SUCCEEDED(hr) && (_eGlyphType != GT_NONE))
  1295. {
  1296. RECT rc;
  1297. hr = GetBackgroundContentRect(pRender, hdc, pRect, &rc);
  1298. if (SUCCEEDED(hr))
  1299. {
  1300. if (_eGlyphType == GT_FONTGLYPH)
  1301. {
  1302. hr = DrawFontGlyph(pRender, hdc, &rc, pOptions);
  1303. }
  1304. else
  1305. {
  1306. DIBINFO *pdi = SelectCorrectImageFile(pRender, hdc, &rc, TRUE, &tsInfo);
  1307. //---- draw glyph image ----
  1308. hr = DrawImageInfo(pdi, pRender, hdc, iStateId, &rc, pOptions, &tsInfo);
  1309. }
  1310. }
  1311. }
  1312. return hr;
  1313. }
  1314. //---------------------------------------------------------------------------
  1315. HRESULT CImageFile::DrawFontGlyph(CRenderObj *pRender, HDC hdc, RECT *prc,
  1316. OPTIONAL const DTBGOPTS *pOptions)
  1317. {
  1318. HRESULT hr = S_OK;
  1319. DWORD dwFlags = DT_SINGLELINE;
  1320. HFONT hFont = NULL;
  1321. HFONT hOldFont = NULL;
  1322. COLORREF crOld = 0;
  1323. CSaveClipRegion scrOrig;
  1324. int iOldMode = 0;
  1325. WCHAR szText[2] = { (WCHAR)_iGlyphIndex, 0 };
  1326. //---- options ----
  1327. DWORD dwOptionFlags = 0;
  1328. const RECT *pClipRect = NULL;
  1329. if (pOptions)
  1330. {
  1331. dwOptionFlags = pOptions->dwFlags;
  1332. if (dwOptionFlags & DTBG_CLIPRECT)
  1333. pClipRect = &pOptions->rcClip;
  1334. }
  1335. //---- create the font ----
  1336. hr = pRender->GetScaledFontHandle(hdc, &_lfGlyphFont, &hFont);
  1337. if (FAILED(hr))
  1338. goto exit;
  1339. //---- make it active ----
  1340. hOldFont = (HFONT)SelectObject(hdc, hFont);
  1341. if (! hOldFont)
  1342. {
  1343. hr = MakeErrorLast();
  1344. goto exit;
  1345. }
  1346. //---- set the text color ----
  1347. crOld = SetTextColor(hdc, _crGlyphTextColor);
  1348. //---- draw text with transparent background ----
  1349. iOldMode = SetBkMode(hdc, TRANSPARENT);
  1350. //---- set the HORZ alignment flags ----
  1351. if (_eHAlign == HA_LEFT)
  1352. dwFlags |= DT_LEFT;
  1353. else if (_eHAlign == HA_CENTER)
  1354. dwFlags |= DT_CENTER;
  1355. else
  1356. dwFlags |= DT_RIGHT;
  1357. //---- set the VERT alignment flags ----
  1358. if (_eVAlign == VA_TOP)
  1359. dwFlags |= DT_TOP;
  1360. else if (_eVAlign == VA_CENTER)
  1361. dwFlags |= DT_VCENTER;
  1362. else
  1363. dwFlags |= DT_BOTTOM;
  1364. //---- add clipping ----
  1365. if (pClipRect)
  1366. {
  1367. //---- get previous clipping region (for restoring at end) ----
  1368. hr = scrOrig.Save(hdc);
  1369. if (FAILED(hr))
  1370. goto exit;
  1371. //---- add "pClipRect" to the GDI clipping region ----
  1372. int iRetVal = IntersectClipRect(hdc, pClipRect->left, pClipRect->top,
  1373. pClipRect->right, pClipRect->bottom);
  1374. if (iRetVal == ERROR)
  1375. {
  1376. hr = MakeErrorLast();
  1377. goto exit;
  1378. }
  1379. }
  1380. //---- draw the char ----
  1381. if (! DrawTextEx(hdc, szText, 1, prc, dwFlags, NULL))
  1382. {
  1383. hr = MakeErrorLast();
  1384. goto exit;
  1385. }
  1386. exit:
  1387. if (pClipRect)
  1388. scrOrig.Restore(hdc);
  1389. //---- reset the background mode ----
  1390. if (iOldMode != TRANSPARENT)
  1391. SetBkMode(hdc, iOldMode);
  1392. //---- restore text color ----
  1393. if (crOld != _crGlyphTextColor)
  1394. SetTextColor(hdc, crOld);
  1395. //---- restore font ----
  1396. if (hOldFont)
  1397. SelectObject(hdc, hOldFont);
  1398. if (hFont)
  1399. pRender->ReturnFontHandle(hFont);
  1400. return hr;
  1401. }
  1402. //---------------------------------------------------------------------------
  1403. BOOL CImageFile::IsBackgroundPartiallyTransparent(int iStateId)
  1404. {
  1405. DIBINFO *pdi = &_ImageInfo; // primary image determines transparency
  1406. return ((pdi->fAlphaChannel) || (pdi->fTransparent));
  1407. }
  1408. //---------------------------------------------------------------------------
  1409. HRESULT CImageFile::HitTestBackground(CRenderObj *pRender, OPTIONAL HDC hdc, int iStateId,
  1410. DWORD dwHTFlags, const RECT *pRect, HRGN hrgn, POINT ptTest, OUT WORD *pwHitCode)
  1411. {
  1412. *pwHitCode = HTNOWHERE;
  1413. if (! PtInRect(pRect, ptTest))
  1414. return S_OK; // nowhere
  1415. //---- background might have transparent parts - get its region ----
  1416. HRESULT hr = S_OK;
  1417. HRGN hrgnBk = NULL;
  1418. if( !hrgn && IsBackgroundPartiallyTransparent(iStateId) )
  1419. {
  1420. hr = GetBackgroundRegion(pRender, hdc, iStateId, pRect, &hrgnBk);
  1421. if( SUCCEEDED(hr) )
  1422. hrgn = hrgnBk;
  1423. }
  1424. MARGINS margins;
  1425. if( TESTFLAG(dwHTFlags, HTTB_SYSTEMSIZINGMARGINS) &&
  1426. TESTFLAG(dwHTFlags, HTTB_RESIZINGBORDER) &&
  1427. !TESTFLAG(dwHTFlags, HTTB_SIZINGTEMPLATE) )
  1428. {
  1429. ZeroMemory( &margins, sizeof(margins) );
  1430. int cxBorder = ClassicGetSystemMetrics( SM_CXSIZEFRAME );
  1431. int cyBorder = ClassicGetSystemMetrics( SM_CXSIZEFRAME );
  1432. if( TESTFLAG(dwHTFlags, HTTB_RESIZINGBORDER_LEFT) )
  1433. margins.cxLeftWidth = cxBorder;
  1434. if( TESTFLAG(dwHTFlags, HTTB_RESIZINGBORDER_RIGHT) )
  1435. margins.cxRightWidth = cxBorder;
  1436. if( TESTFLAG(dwHTFlags, HTTB_RESIZINGBORDER_TOP) )
  1437. margins.cyTopHeight = cyBorder;
  1438. if( TESTFLAG(dwHTFlags, HTTB_RESIZINGBORDER_BOTTOM) )
  1439. margins.cyBottomHeight = cyBorder;
  1440. }
  1441. else
  1442. {
  1443. hr = GetScaledContentMargins(pRender, hdc, pRect, &margins);
  1444. if (FAILED(hr))
  1445. goto exit;
  1446. }
  1447. if( hrgn )
  1448. {
  1449. // 122013 - we originally delegated to a sophisticated but broken
  1450. // resizing area region hit test algorithm for regioned windows,
  1451. // but for whistler we'll just do the bounding
  1452. // rectangle thang instead.
  1453. //*pwHitCode = HitTestRgn( dwHTFlags, pRect, hrgn, margins, ptTest );
  1454. RECT rcRgn;
  1455. if( GetRgnBox( hrgn, &rcRgn ) )
  1456. {
  1457. if( TESTFLAG(dwHTFlags, HTTB_SIZINGTEMPLATE) )
  1458. {
  1459. *pwHitCode = HitTestTemplate( dwHTFlags, &rcRgn, hrgn, margins, ptTest );
  1460. }
  1461. else
  1462. {
  1463. *pwHitCode = HitTestRect( dwHTFlags, &rcRgn, margins, ptTest );
  1464. }
  1465. }
  1466. SAFE_DELETE_GDIOBJ(hrgnBk);
  1467. }
  1468. else
  1469. {
  1470. *pwHitCode = HitTestRect( dwHTFlags, pRect, margins, ptTest );
  1471. }
  1472. exit:
  1473. return hr;
  1474. }
  1475. //---------------------------------------------------------------------------
  1476. HRESULT CImageFile::GetBackgroundRegion(CRenderObj *pRender, OPTIONAL HDC hdc, int iStateId,
  1477. const RECT *pRect, HRGN *pRegion)
  1478. {
  1479. HRESULT hr = S_OK;
  1480. RGNDATA *pRgnData;
  1481. CMemoryDC hdcMemory;
  1482. HRGN hrgn;
  1483. int iRgnDataOffset = 0;
  1484. MIXEDPTRS u;
  1485. DIBINFO *pdi = SelectCorrectImageFile(pRender, hdc, pRect, FALSE);
  1486. //---- get rgndata offset ----
  1487. if ((pdi->iRgnListOffset) && (pRender->_pbThemeData))
  1488. {
  1489. u.pb = pRender->_pbThemeData + pdi->iRgnListOffset;
  1490. int iMaxState = (*u.pb++) - 1;
  1491. if (iStateId > iMaxState)
  1492. iStateId = 0;
  1493. iRgnDataOffset = u.pi[iStateId];
  1494. }
  1495. //---- see if it even has a transparent part ----
  1496. if (iRgnDataOffset)
  1497. {
  1498. //---- stretch those puppies & create a new region ----
  1499. pRgnData = (RGNDATA *)(pRender->_pbThemeData + iRgnDataOffset
  1500. + sizeof(RGNDATAHDR) + ENTRYHDR_SIZE);
  1501. SIZE szSrcImage = {pdi->iSingleWidth, pdi->iSingleHeight};
  1502. hr = _ScaleRectsAndCreateRegion(pRgnData, pRect, &_SizingMargins, &szSrcImage, &hrgn);
  1503. if (FAILED(hr))
  1504. goto exit;
  1505. }
  1506. else
  1507. {
  1508. //---- return the bounding rect as the region ----
  1509. hrgn = CreateRectRgn(pRect->left, pRect->top,
  1510. pRect->right, pRect->bottom);
  1511. if (! hrgn)
  1512. {
  1513. hr = MakeErrorLast();
  1514. goto exit;
  1515. }
  1516. }
  1517. *pRegion = hrgn;
  1518. exit:
  1519. return hr;
  1520. }
  1521. //---------------------------------------------------------------------------
  1522. HRESULT CImageFile::GetBackgroundContentRect(CRenderObj *pRender, OPTIONAL HDC hdc,
  1523. const RECT *pBoundingRect, RECT *pContentRect)
  1524. {
  1525. MARGINS margins;
  1526. HRESULT hr = GetScaledContentMargins(pRender, hdc, pBoundingRect, &margins);
  1527. if (FAILED(hr))
  1528. goto exit;
  1529. pContentRect->left = pBoundingRect->left + margins.cxLeftWidth;
  1530. pContentRect->top = pBoundingRect->top + margins.cyTopHeight;
  1531. pContentRect->right = pBoundingRect->right - margins.cxRightWidth;
  1532. pContentRect->bottom = pBoundingRect->bottom - margins.cyBottomHeight;
  1533. exit:
  1534. return hr;
  1535. }
  1536. //---------------------------------------------------------------------------
  1537. HRESULT CImageFile::GetBackgroundExtent(CRenderObj *pRender, OPTIONAL HDC hdc,
  1538. const RECT *pContentRect, RECT *pExtentRect)
  1539. {
  1540. MARGINS margins;
  1541. HRESULT hr = GetScaledContentMargins(pRender, hdc, pContentRect, &margins);
  1542. if (FAILED(hr))
  1543. goto exit;
  1544. pExtentRect->left = pContentRect->left - margins.cxLeftWidth;
  1545. pExtentRect->top = pContentRect->top-+ margins.cyTopHeight;
  1546. pExtentRect->right = pContentRect->right + margins.cxRightWidth;
  1547. pExtentRect->bottom = pContentRect->bottom + margins.cyBottomHeight;
  1548. exit:
  1549. return hr;
  1550. }
  1551. //---------------------------------------------------------------------------
  1552. HRESULT CImageFile::GetScaledContentMargins(CRenderObj *pRender, OPTIONAL HDC hdc,
  1553. OPTIONAL const RECT *prcDest, MARGINS *pMargins)
  1554. {
  1555. HRESULT hr = S_OK;
  1556. *pMargins = _ContentMargins;
  1557. //---- now scale the margins ----
  1558. SIZE szDraw;
  1559. TRUESTRETCHINFO tsInfo;
  1560. DIBINFO *pdi = SelectCorrectImageFile(pRender, hdc, prcDest, FALSE, NULL);
  1561. GetDrawnImageSize(pdi, prcDest, &tsInfo, &szDraw);
  1562. hr = ScaleMargins(pMargins, hdc, pRender, pdi, &szDraw);
  1563. return hr;
  1564. }
  1565. //---------------------------------------------------------------------------
  1566. HRESULT CImageFile::GetPartSize(CRenderObj *pRender, HDC hdc, OPTIONAL const RECT *prc,
  1567. THEMESIZE eSize, SIZE *psz)
  1568. {
  1569. HRESULT hr = S_OK;
  1570. TRUESTRETCHINFO tsInfo;
  1571. DIBINFO *pdi = SelectCorrectImageFile(pRender, hdc, prc, FALSE, &tsInfo);
  1572. if (eSize == TS_MIN)
  1573. {
  1574. MARGINS margins;
  1575. hr = GetScaledContentMargins(pRender, hdc, prc, &margins);
  1576. if (FAILED(hr))
  1577. goto exit;
  1578. psz->cx = max(1, margins.cxLeftWidth + margins.cxRightWidth);
  1579. psz->cy = max(1, margins.cyTopHeight + margins.cyBottomHeight);
  1580. }
  1581. else if (eSize == TS_TRUE)
  1582. {
  1583. psz->cx = pdi->iSingleWidth;
  1584. psz->cy = pdi->iSingleHeight;
  1585. }
  1586. else if (eSize == TS_DRAW)
  1587. {
  1588. GetDrawnImageSize(pdi, prc, &tsInfo, psz);
  1589. }
  1590. else
  1591. {
  1592. hr = MakeError32(E_INVALIDARG);
  1593. goto exit;
  1594. }
  1595. exit:
  1596. return hr;
  1597. }
  1598. //---------------------------------------------------------------------------
  1599. HRESULT CImageFile::GetBitmap(CRenderObj *pRender, HDC hdc, const RECT *prc, HBITMAP *phBitmap)
  1600. {
  1601. int iStockDibOffset = pRender->GetValueIndex(_iSourcePartId, _iSourceStateId, TMT_STOCKDIBDATA);
  1602. if (iStockDibOffset > 0)
  1603. {
  1604. return pRender->GetBitmap(NULL, iStockDibOffset, phBitmap);
  1605. }
  1606. else
  1607. {
  1608. return E_INVALIDARG;
  1609. }
  1610. }
  1611. //---------------------------------------------------------------------------
  1612. void CImageFile::GetOffsets(int iStateId, DIBINFO *pdi, int *piXOffset, int *piYOffset)
  1613. {
  1614. if (_eImageLayout == IL_HORIZONTAL)
  1615. {
  1616. //---- iStateId in the image index ----
  1617. if ((iStateId <= 0) || (iStateId > _iImageCount))
  1618. *piXOffset = 0;
  1619. else
  1620. *piXOffset = (iStateId-1) * (pdi->iSingleWidth);
  1621. *piYOffset = 0;
  1622. }
  1623. else // vertical
  1624. {
  1625. //---- iStateId in the image index ----
  1626. if ((iStateId <= 0) || (iStateId > _iImageCount))
  1627. *piYOffset = 0;
  1628. else
  1629. *piYOffset = (iStateId-1) * (pdi->iSingleHeight);
  1630. *piXOffset = 0;
  1631. }
  1632. }
  1633. //---------------------------------------------------------------------------
  1634. HRESULT CImageFile::ScaleMargins(IN OUT MARGINS *pMargins, HDC hdcOrig, CRenderObj *pRender,
  1635. DIBINFO *pdi, const SIZE *pszDraw, OPTIONAL float *pfx, OPTIONAL float *pfy)
  1636. {
  1637. HRESULT hr = S_OK;
  1638. COptionalDC hdc(hdcOrig);
  1639. BOOL fForceRectSizing = FALSE;
  1640. if ((pRender) && (pRender->_dwOtdFlags & OTD_FORCE_RECT_SIZING))
  1641. {
  1642. fForceRectSizing = TRUE;
  1643. }
  1644. float xFactor = 1;
  1645. float yFactor = 1;
  1646. //---- any margins to size? ----
  1647. if ((pMargins->cxLeftWidth) || (pMargins->cxRightWidth) || (pMargins->cyBottomHeight)
  1648. || (pMargins->cyTopHeight))
  1649. {
  1650. if ((pszDraw->cx > 0) && (pszDraw->cy > 0))
  1651. {
  1652. BOOL fxNeedScale = FALSE;
  1653. BOOL fyNeedScale = FALSE;
  1654. //---- scale if dest rect is too small in one dimension ----
  1655. if ((_fSourceShrink) || (fForceRectSizing))
  1656. {
  1657. if (pszDraw->cx < pdi->szMinSize.cx)
  1658. {
  1659. fxNeedScale = TRUE;
  1660. }
  1661. if (pszDraw->cy < pdi->szMinSize.cy)
  1662. {
  1663. fyNeedScale = TRUE;
  1664. }
  1665. }
  1666. if ((_fSourceGrow) || (fForceRectSizing))
  1667. {
  1668. if ((! fxNeedScale) && (! fyNeedScale))
  1669. {
  1670. //---- calculate our Dest DPI ----
  1671. int iDestDpi;
  1672. if (fForceRectSizing)
  1673. {
  1674. iDestDpi = (pRender) ? (pRender->GetDpiOverride()) : 0;
  1675. if (! iDestDpi)
  1676. {
  1677. //---- make up a DPI based on sizes (IE will pass us the actual DPI soon) ----
  1678. int ixFakeDpi = MulDiv(pdi->iMinDpi, pszDraw->cx, _szNormalSize.cx);
  1679. int iyFakeDpi = MulDiv(pdi->iMinDpi, pszDraw->cy, _szNormalSize.cy);
  1680. iDestDpi = (ixFakeDpi + iyFakeDpi)/2;
  1681. }
  1682. }
  1683. else
  1684. {
  1685. iDestDpi = GetDeviceCaps(hdc, LOGPIXELSX);
  1686. }
  1687. //---- scale source/margins by Dest DPI ----
  1688. if (iDestDpi >= 2*pdi->iMinDpi)
  1689. {
  1690. xFactor *= iDestDpi/pdi->iMinDpi;
  1691. yFactor *= iDestDpi/pdi->iMinDpi;
  1692. }
  1693. }
  1694. }
  1695. //---- scale by ratio of our image to draw size ----
  1696. if (fxNeedScale)
  1697. {
  1698. xFactor *= float(pszDraw->cx)/float(_szNormalSize.cx);
  1699. }
  1700. if (fyNeedScale)
  1701. {
  1702. yFactor *= float(pszDraw->cy)/float(_szNormalSize.cy);
  1703. }
  1704. }
  1705. //---- use smallest factor for both ----
  1706. if (xFactor < yFactor)
  1707. {
  1708. yFactor = xFactor;
  1709. }
  1710. else if (yFactor < xFactor)
  1711. {
  1712. xFactor = yFactor;
  1713. }
  1714. //---- integer truncation ----
  1715. if (xFactor > 1.0)
  1716. {
  1717. xFactor = float(int(xFactor));
  1718. }
  1719. if (yFactor > 1.0)
  1720. {
  1721. yFactor = float(int(yFactor));
  1722. }
  1723. //---- scale the margin values ----
  1724. if (xFactor != 1)
  1725. {
  1726. pMargins->cxLeftWidth = ROUND(xFactor*pMargins->cxLeftWidth);
  1727. pMargins->cxRightWidth = ROUND(xFactor*pMargins->cxRightWidth);
  1728. }
  1729. if (yFactor != 1)
  1730. {
  1731. pMargins->cyTopHeight = ROUND(yFactor*pMargins->cyTopHeight);
  1732. pMargins->cyBottomHeight = ROUND(yFactor*pMargins->cyBottomHeight);
  1733. }
  1734. }
  1735. //---- return factors to interested callers ----
  1736. if (pfx)
  1737. {
  1738. *pfx = xFactor;
  1739. }
  1740. if (pfy)
  1741. {
  1742. *pfy = yFactor;
  1743. }
  1744. return hr;
  1745. }
  1746. //---------------------------------------------------------------------------