Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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