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.

688 lines
24 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: NineGrid2.cpp
  3. //
  4. // Copyright (c) 2000, 2001 Microsoft Corporation
  5. //
  6. // Implementation of the DrawNineGrid2 function
  7. //
  8. // History: 2000-12-20 justmann created
  9. // --------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "resource.h"
  12. #include "tmschema.h"
  13. #include "ninegrid2.h"
  14. #define DNG_BUF_WIDTH 256
  15. #define DNG_BUF_HEIGHT 60
  16. typedef struct STRETCH
  17. {
  18. ULONG xStart;
  19. ULONG xAccum;
  20. ULONG xFrac;
  21. ULONG xInt;
  22. ULONG ulDestWidth;
  23. ULONG ulSrcWidth;
  24. int left;
  25. int right;
  26. } STRETCH;
  27. typedef struct DNGINTERNALDATAtag
  28. {
  29. int cxClipMin;
  30. int cxClipMax;
  31. ULONG* pvDestBits;
  32. int iDestWidth;
  33. int iClipWidth;
  34. ULONG* pvSrcBits;
  35. int iSrcWidth;
  36. int iSrcBufWidth;
  37. int cxLeftWidth;
  38. int xMinLeft;
  39. int xMaxLeft;
  40. int cxRightWidth;
  41. int xMinRight;
  42. int xMaxRight;
  43. int cxMiddleWidth;
  44. int cxNewMiddleWidth;
  45. int xMinMiddle;
  46. int xMaxMiddle;
  47. // Variable for shrunken corners and sides
  48. BOOL fShowMiddle;
  49. STRETCH stretchLeft;
  50. STRETCH stretchRight;
  51. int cxNewLeftWidth;
  52. int cxNewRightWidth;
  53. BOOL fTileMode;
  54. // Specific to non-tile mode (i.e. stretch mode)
  55. STRETCH stretchMiddle;
  56. } DNGINTERNALDATA;
  57. static HDC s_hdcBuf = NULL;
  58. static HBITMAP s_hbmBuf = NULL;
  59. static HBITMAP s_hbmOldBuf = NULL;
  60. static CRITICAL_SECTION s_dngLock;
  61. void DNG_FreeDIB(HDC* phdcDest, HBITMAP* phbmDest, HBITMAP* phbmDestOld);
  62. BOOL NineGrid2StartUp()
  63. {
  64. InitializeCriticalSection(&s_dngLock);
  65. return TRUE;
  66. }
  67. void NineGrid2ShutDown()
  68. {
  69. DNG_FreeDIB(&s_hdcBuf, &s_hbmBuf, &s_hbmOldBuf);
  70. DeleteCriticalSection(&s_dngLock);
  71. }
  72. inline void DNG_CreateDIB(HDC hdc, int iWidth, int iHeight, ULONG** ppvDestBits, HDC* phdcDest, HBITMAP* phbmDest, HBITMAP* phbmDestOld)
  73. {
  74. *phdcDest = CreateCompatibleDC(hdc);
  75. if (*phdcDest)
  76. {
  77. BITMAPINFO bi = {0};
  78. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  79. bi.bmiHeader.biWidth = iWidth;
  80. bi.bmiHeader.biHeight = iHeight;
  81. bi.bmiHeader.biPlanes = 1;
  82. bi.bmiHeader.biBitCount = 32;
  83. bi.bmiHeader.biCompression = BI_RGB;
  84. *phbmDest = CreateDIBSection(*phdcDest, &bi, DIB_RGB_COLORS, (VOID**)ppvDestBits, NULL, 0);
  85. if (*phbmDest)
  86. {
  87. *phbmDestOld = (HBITMAP) SelectObject(*phdcDest, *phbmDest);
  88. }
  89. else
  90. {
  91. DeleteDC(*phdcDest);
  92. *phdcDest = NULL;
  93. }
  94. }
  95. }
  96. void DNG_FreeDIB(HDC* phdcDest, HBITMAP* phbmDest, HBITMAP* phbmDestOld)
  97. {
  98. if (*phdcDest)
  99. {
  100. SelectObject(*phdcDest, *phbmDestOld);
  101. DeleteObject(*phbmDest);
  102. DeleteDC(*phdcDest);
  103. }
  104. *phdcDest = NULL;
  105. }
  106. HRESULT BitmapToNGImage(HDC hdc, HBITMAP hbm, int left, int top, int right, int bottom, MARGINS margin, SIZINGTYPE eSize, DWORD dwFlags, COLORREF crTrans, PNGIMAGE pngi)
  107. {
  108. HRESULT hr = E_INVALIDARG;
  109. if (pngi)
  110. {
  111. pngi->margin = margin;
  112. pngi->eSize = eSize;
  113. pngi->dwFlags = dwFlags;
  114. pngi->crTrans = crTrans;
  115. pngi->iWidth = right - left;
  116. pngi->iHeight = bottom - top;
  117. HDC hdcBuf = NULL;
  118. HBITMAP hbmOld;
  119. DNG_CreateDIB(hdc, pngi->iWidth, pngi->iHeight, &(pngi->pvBits), &hdcBuf, &pngi->hbm, &hbmOld);
  120. if (hdcBuf)
  121. {
  122. HDC hdcTempMem = CreateCompatibleDC(hdc);
  123. if (hdcTempMem)
  124. {
  125. HBITMAP hbmTempOld = (HBITMAP) SelectObject(hdcTempMem, hbm);
  126. BitBlt(hdcBuf, 0, 0, pngi->iWidth, pngi->iHeight, hdcTempMem, left, top, SRCCOPY);
  127. hr = S_OK;
  128. SelectObject(hdcTempMem, hbmTempOld);
  129. DeleteDC(hdcTempMem);
  130. }
  131. SelectObject(hdcBuf, hbmOld);
  132. DeleteDC(hdcBuf);
  133. }
  134. }
  135. return hr;
  136. }
  137. HRESULT FreeNGImage(PNGIMAGE pngi)
  138. {
  139. HRESULT hr = E_INVALIDARG;
  140. if (pngi)
  141. {
  142. if (pngi->hbm)
  143. {
  144. DeleteObject(pngi->hbm);
  145. }
  146. pngi->hbm = NULL;
  147. hr = S_OK;
  148. }
  149. return hr;
  150. }
  151. inline void DNG_StretchRow(ULONG* pvDestBits, ULONG* pvSrcBits, STRETCH * ps)
  152. {
  153. ULONG* pvTemp = pvDestBits + ps->left;
  154. ULONG* pvSentinel = pvDestBits + ps->right;
  155. ULONG xInt = ps->xInt;
  156. ULONG xFrac = ps->xFrac;
  157. ULONG xTmp;
  158. ULONG xAccum = ps->xAccum;
  159. ULONG * pulSrc = pvSrcBits + ps->xStart;
  160. ULONG ulSrc;
  161. while (pvTemp != pvSentinel)
  162. {
  163. ulSrc = *pulSrc;
  164. xTmp = xAccum + xFrac;
  165. pulSrc = pulSrc + xInt + (xTmp < xAccum);
  166. *pvTemp = ulSrc;
  167. pvTemp++;
  168. xAccum = xTmp;
  169. }
  170. }
  171. inline void DNG_InitStretch(STRETCH* pStretch, ULONG ulDestWidth, ULONG ulSrcWidth, int left, int right)
  172. {
  173. pStretch->right = right;
  174. pStretch->left = left;
  175. ULONGLONG dx = ((((ULONGLONG) ulSrcWidth << 32) - 1) / (ULONGLONG) ulDestWidth) + 1;
  176. ULONGLONG x = (((ULONGLONG) ulSrcWidth << 32) / (ULONGLONG) ulDestWidth) >> 1;
  177. ULONG xInt = pStretch->xInt = (ULONG) (dx >> 32);
  178. ULONG xFrac = pStretch->xFrac = (ULONG) (dx & 0xFFFFFFFF);
  179. ULONG xAccum = (ULONG) (x & 0xFFFFFFFF);
  180. ULONG xTmp;
  181. ULONG xStart = (ULONG) (x >> 32);
  182. for (int i = 0; i < left; i++)
  183. {
  184. xTmp = xAccum + xFrac;
  185. xStart = xStart + xInt + (xTmp < xAccum);
  186. xAccum = xTmp;
  187. }
  188. pStretch->xStart = xStart;
  189. pStretch->xAccum = xAccum;
  190. }
  191. inline void DNG_DrawRow(DNGINTERNALDATA* pdng)
  192. {
  193. ULONG* pvDestLoc = pdng->pvDestBits;
  194. ULONG* pvSrcLoc = pdng->pvSrcBits;
  195. // Left
  196. if (pdng->cxClipMin < pdng->cxNewLeftWidth)
  197. {
  198. if (pdng->cxLeftWidth == pdng->cxNewLeftWidth)
  199. {
  200. CopyMemory(pvDestLoc + pdng->xMinLeft, pvSrcLoc + pdng->xMinLeft, (pdng->xMaxLeft - pdng->xMinLeft) * sizeof(ULONG));
  201. }
  202. else
  203. {
  204. DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchLeft);
  205. }
  206. }
  207. pvDestLoc += pdng->cxNewLeftWidth;
  208. pvSrcLoc += pdng->cxLeftWidth;
  209. // Middle
  210. if (pdng->fShowMiddle)
  211. {
  212. if (pdng->xMinMiddle < pdng->xMaxMiddle)
  213. {
  214. if (pdng->fTileMode)
  215. {
  216. ULONG* pvTempSrc = pvSrcLoc;
  217. ULONG* pvTempDest = pvDestLoc;
  218. // Fill in Top Tile
  219. int xMin = pdng->xMinMiddle;
  220. int xDiff = xMin - pdng->cxLeftWidth;
  221. pvDestLoc += xDiff;
  222. int iTileSize = pdng->cxMiddleWidth - (xDiff % pdng->cxMiddleWidth);
  223. pvSrcLoc += xDiff % pdng->cxMiddleWidth;
  224. int xMax = pdng->xMaxMiddle;
  225. for (int x = xMin; x < xMax; x++, pvDestLoc++ , pvSrcLoc++)
  226. {
  227. *pvDestLoc = *pvSrcLoc;
  228. iTileSize--;
  229. if (iTileSize == 0)
  230. {
  231. iTileSize = pdng->cxMiddleWidth;
  232. pvSrcLoc -= iTileSize;
  233. }
  234. }
  235. pvDestLoc = pvTempDest;
  236. pvSrcLoc = pvTempSrc;
  237. }
  238. else
  239. {
  240. DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchMiddle);
  241. }
  242. }
  243. pvDestLoc += pdng->cxNewMiddleWidth;
  244. }
  245. pvSrcLoc += pdng->cxMiddleWidth;
  246. // Right
  247. if (pdng->cxClipMax > (pdng->iDestWidth - pdng->cxNewRightWidth))
  248. {
  249. if (pdng->cxRightWidth == pdng->cxNewRightWidth)
  250. {
  251. CopyMemory(pvDestLoc + pdng->xMinRight, pvSrcLoc + pdng->xMinRight, (pdng->xMaxRight - pdng->xMinRight) * sizeof(ULONG));
  252. }
  253. else
  254. {
  255. DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchRight);
  256. }
  257. }
  258. }
  259. inline void DNG_StretchCol(DNGINTERNALDATA* pdng, STRETCH * ps)
  260. {
  261. ULONG* pvOldDestBits = pdng->pvDestBits;
  262. ULONG* pvOldSrcBits = pdng->pvSrcBits;
  263. ULONG* pvTemp = pdng->pvDestBits + (DNG_BUF_WIDTH * ps->left);
  264. ULONG* pvSentinel = pdng->pvDestBits + (DNG_BUF_WIDTH * ps->right);
  265. ULONG xInt = ps->xInt;
  266. ULONG xFrac = ps->xFrac;
  267. ULONG xTmp;
  268. ULONG xAccum = ps->xAccum;
  269. ULONG * pulSrc = pdng->pvSrcBits + (pdng->iSrcBufWidth * ps->xStart);
  270. ULONG xDelta = 1; // force stretch on first scan
  271. while (pvTemp != pvSentinel)
  272. {
  273. if (xDelta != 0)
  274. {
  275. pdng->pvDestBits = pvTemp;
  276. pdng->pvSrcBits = pulSrc;
  277. DNG_DrawRow(pdng);
  278. }
  279. else
  280. {
  281. memcpy(pvTemp + pdng->cxClipMin, pvTemp + pdng->cxClipMin - DNG_BUF_WIDTH, pdng->iClipWidth * sizeof(ULONG));
  282. }
  283. xTmp = xAccum + xFrac;
  284. xDelta = (xInt + (xTmp < xAccum));
  285. pulSrc = pulSrc + (pdng->iSrcBufWidth * xDelta);
  286. pvTemp += DNG_BUF_WIDTH;
  287. xAccum = xTmp;
  288. }
  289. pdng->pvDestBits = pvOldDestBits;
  290. pdng->pvSrcBits = pvOldSrcBits;
  291. }
  292. HRESULT DrawNineGrid2(HDC hdc, PNGIMAGE pngiSrc, RECT* pRect, const RECT *prcClip, DWORD dwFlags)
  293. {
  294. // Store the static buffer
  295. static ULONG* s_pvBitsBuf = NULL;
  296. // Make sure that coordinates are valid;
  297. RECT rcDest = *pRect;
  298. if (rcDest.left > rcDest.right)
  299. {
  300. int xTemp = rcDest.left;
  301. rcDest.left = rcDest.right;
  302. rcDest.right = xTemp;
  303. }
  304. if (rcDest.top > rcDest.bottom)
  305. {
  306. int yTemp = rcDest.bottom;
  307. rcDest.bottom = rcDest.top;
  308. rcDest.top = yTemp;
  309. }
  310. RECT rcClip;
  311. if (prcClip)
  312. {
  313. IntersectRect(&rcClip, &rcDest, prcClip);
  314. }
  315. else
  316. {
  317. CopyRect(&rcClip, &rcDest);
  318. }
  319. HRESULT hr = S_OK;
  320. if ((pngiSrc->eSize == ST_TILE) || (pngiSrc->eSize == ST_STRETCH) || (pngiSrc->eSize == ST_TRUESIZE))
  321. {
  322. ULONG* pvDestBits = NULL;
  323. int iDestWidth = rcDest.right - rcDest.left;
  324. int iDestHeight = rcDest.bottom - rcDest.top;
  325. int iClipWidth = rcClip.right - rcClip.left;
  326. int iClipHeight = rcClip.bottom - rcClip.top;
  327. if ((iClipWidth > DNG_BUF_WIDTH) || (iClipHeight > DNG_BUF_HEIGHT))
  328. {
  329. // Divide the image into chunks smaller or equal to the buffer
  330. for (int y = rcClip.top; y < rcClip.bottom; y += DNG_BUF_HEIGHT)
  331. {
  332. for (int x = rcClip.left; x < rcClip.right; x += DNG_BUF_WIDTH)
  333. {
  334. RECT rcTemp = { x, y, x + DNG_BUF_WIDTH, y + DNG_BUF_HEIGHT };
  335. RECT rcNewClip;
  336. IntersectRect(&rcNewClip, &rcTemp, &rcClip);
  337. DrawNineGrid2(hdc, pngiSrc, &rcDest, &rcNewClip, dwFlags);
  338. }
  339. }
  340. }
  341. else
  342. {
  343. EnterCriticalSection(&s_dngLock);
  344. // Use temporary buffer
  345. if (!s_hdcBuf)
  346. {
  347. DNG_CreateDIB(hdc, DNG_BUF_WIDTH, DNG_BUF_HEIGHT, &s_pvBitsBuf, &s_hdcBuf, &s_hbmBuf, &s_hbmOldBuf);
  348. SetLayout(s_hdcBuf, LAYOUT_BITMAPORIENTATIONPRESERVED);
  349. }
  350. pvDestBits = s_pvBitsBuf;
  351. if (s_hdcBuf)
  352. {
  353. DNGINTERNALDATA dng;
  354. dng.cxClipMin = rcClip.left - rcDest.left;
  355. dng.cxClipMax = rcClip.right - rcDest.left;
  356. int cyClipMin = rcClip.top - rcDest.top;
  357. int cyClipMax = rcClip.bottom - rcDest.top;
  358. pvDestBits += ((cyClipMin - (iDestHeight - DNG_BUF_HEIGHT)) * DNG_BUF_WIDTH) - dng.cxClipMin;
  359. int cxImage = rcClip.right - rcClip.left;
  360. int cyImage = rcClip.bottom - rcClip.top;
  361. if (pngiSrc->eSize == ST_TRUESIZE)
  362. {
  363. ULONG* pvDestLoc = pvDestBits + (iDestHeight - 1) * DNG_BUF_WIDTH;
  364. ULONG* pvSrcLoc = pngiSrc->pvBits + pngiSrc->iBufWidth * (pngiSrc->iHeight - 1);
  365. int yMin = cyClipMin;
  366. pvDestLoc -= yMin * DNG_BUF_WIDTH;
  367. pvSrcLoc -= yMin * pngiSrc->iBufWidth;
  368. int yMax = min(pngiSrc->iHeight, cyClipMax);
  369. int xMin = dng.cxClipMin;
  370. int xMax = min(pngiSrc->iWidth, dng.cxClipMax);
  371. if (xMax > xMin)
  372. {
  373. for (int y = yMin; y < yMax; y++, pvDestLoc -= DNG_BUF_WIDTH, pvSrcLoc -= pngiSrc->iBufWidth)
  374. {
  375. CopyMemory(pvDestLoc + xMin, pvSrcLoc + xMin, (xMax - xMin) * 4);
  376. }
  377. }
  378. cxImage = xMax - xMin;
  379. cyImage = yMax - yMin;
  380. }
  381. else
  382. {
  383. // Setup data
  384. dng.iDestWidth = iDestWidth;
  385. dng.iClipWidth = iClipWidth;
  386. dng.iSrcWidth = pngiSrc->iWidth;
  387. dng.iSrcBufWidth = pngiSrc->iBufWidth;
  388. dng.cxLeftWidth = pngiSrc->margin.cxLeftWidth;
  389. dng.cxRightWidth = pngiSrc->margin.cxRightWidth;
  390. dng.fTileMode = (pngiSrc->eSize == ST_TILE);
  391. // Calculate clip stuff
  392. // Pre-calc corner stretching variables
  393. dng.fShowMiddle = (iDestWidth - pngiSrc->margin.cxLeftWidth - pngiSrc->margin.cxRightWidth > 0);
  394. if (!dng.fShowMiddle)
  395. {
  396. dng.cxNewLeftWidth = (dng.cxLeftWidth + dng.cxRightWidth == 0) ? 0 : (dng.cxLeftWidth * dng.iDestWidth) / (dng.cxLeftWidth + dng.cxRightWidth);
  397. dng.cxNewRightWidth = dng.iDestWidth - dng.cxNewLeftWidth;
  398. }
  399. else
  400. {
  401. dng.cxNewLeftWidth = pngiSrc->margin.cxLeftWidth;
  402. dng.cxNewRightWidth = pngiSrc->margin.cxRightWidth;
  403. }
  404. // Pre-calc Left side variables
  405. dng.xMinLeft = dng.cxClipMin;
  406. dng.xMaxLeft = min(dng.cxNewLeftWidth, dng.cxClipMax);
  407. if (!dng.fShowMiddle && dng.cxNewLeftWidth)
  408. {
  409. DNG_InitStretch(&dng.stretchLeft, dng.cxNewLeftWidth, dng.cxLeftWidth, dng.xMinLeft, dng.xMaxLeft);
  410. }
  411. // Pre-calc Horizontal Middle Variables
  412. dng.cxMiddleWidth = dng.iSrcWidth - dng.cxLeftWidth - dng.cxRightWidth;
  413. dng.cxNewMiddleWidth = dng.iDestWidth - dng.cxNewLeftWidth - dng.cxNewRightWidth;
  414. dng.xMinMiddle = max(dng.cxNewLeftWidth, dng.cxClipMin);
  415. dng.xMaxMiddle = min(dng.cxNewLeftWidth + dng.cxNewMiddleWidth, dng.cxClipMax);
  416. if (dng.fShowMiddle)
  417. {
  418. DNG_InitStretch(&dng.stretchMiddle, dng.cxNewMiddleWidth, dng.cxMiddleWidth, dng.xMinMiddle - dng.cxNewLeftWidth, dng.xMaxMiddle - dng.cxNewLeftWidth);
  419. }
  420. // Pre-calc Right side variables
  421. dng.xMinRight = max(dng.iDestWidth - dng.cxNewRightWidth, dng.cxClipMin) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
  422. dng.xMaxRight = min(dng.iDestWidth, dng.cxClipMax) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
  423. if (!dng.fShowMiddle && dng.cxNewRightWidth)
  424. {
  425. DNG_InitStretch(&dng.stretchRight, dng.cxNewRightWidth, dng.cxRightWidth, dng.xMinRight, dng.xMaxRight);
  426. }
  427. BOOL fShowVertMiddle = (iDestHeight - pngiSrc->margin.cyTopHeight - pngiSrc->margin.cyBottomHeight > 0);
  428. int cyTopHeight = pngiSrc->margin.cyTopHeight;
  429. int cyBottomHeight = pngiSrc->margin.cyBottomHeight;
  430. int cyNewTopHeight;
  431. int cyNewBottomHeight;
  432. if (!fShowVertMiddle)
  433. {
  434. cyNewTopHeight = (cyTopHeight + cyBottomHeight == 0) ? 0 : (cyTopHeight * iDestHeight) / (cyTopHeight + cyBottomHeight);
  435. cyNewBottomHeight = iDestHeight - cyNewTopHeight;
  436. }
  437. else
  438. {
  439. cyNewTopHeight = cyTopHeight;
  440. cyNewBottomHeight = cyBottomHeight;
  441. }
  442. // Draw Bottom
  443. // Draw the scan line from (iDestHeight - cyNewBottomHeight) to less than iDestHeight, in screen coordinates
  444. int yMin = max(iDestHeight - cyNewBottomHeight, cyClipMin);
  445. int yMax = min(iDestHeight, cyClipMax);
  446. if (cyClipMax > iDestHeight - cyNewBottomHeight)
  447. {
  448. dng.pvDestBits = pvDestBits;
  449. dng.pvSrcBits = pngiSrc->pvBits;
  450. if (cyBottomHeight == cyNewBottomHeight)
  451. {
  452. int yDiff = yMin - (iDestHeight - cyNewBottomHeight);
  453. dng.pvDestBits += (cyBottomHeight - 1 - yDiff) * DNG_BUF_WIDTH;
  454. dng.pvSrcBits += (cyBottomHeight - 1 - yDiff) * dng.iSrcBufWidth;
  455. for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= dng.iSrcBufWidth)
  456. {
  457. DNG_DrawRow(&dng);
  458. }
  459. }
  460. else if (cyNewBottomHeight > 0)
  461. {
  462. STRETCH stretch;
  463. DNG_InitStretch(&stretch, cyNewBottomHeight, cyBottomHeight, cyNewBottomHeight - (yMax - iDestHeight + cyNewBottomHeight), cyNewBottomHeight - (yMin - iDestHeight + cyNewBottomHeight));
  464. DNG_StretchCol(&dng, &stretch);
  465. }
  466. }
  467. // Draw Middle
  468. // Draw the scan line from cyNewTopHeight to less than (iDestHeight - cyNewBottomHeight), in screen coordinates
  469. if (fShowVertMiddle && (cyClipMin < iDestHeight - cyNewBottomHeight) && (cyClipMax > cyNewTopHeight))
  470. {
  471. int cySrcTileSize = pngiSrc->iHeight - pngiSrc->margin.cyTopHeight - pngiSrc->margin.cyBottomHeight;
  472. int cyDestTileSize = iDestHeight - pngiSrc->margin.cyTopHeight - pngiSrc->margin.cyBottomHeight;
  473. dng.pvDestBits = pvDestBits + pngiSrc->margin.cyBottomHeight * DNG_BUF_WIDTH;
  474. dng.pvSrcBits = pngiSrc->pvBits + pngiSrc->margin.cyBottomHeight * pngiSrc->iBufWidth;
  475. int yMin = max(cyTopHeight, cyClipMin);
  476. if (dng.fTileMode)
  477. {
  478. // Start off tile
  479. dng.pvDestBits += (cyDestTileSize - 1) * DNG_BUF_WIDTH;
  480. dng.pvSrcBits += (cySrcTileSize - 1) * dng.iSrcBufWidth;
  481. int yDiff = yMin - cyTopHeight;
  482. dng.pvDestBits -= yDiff * DNG_BUF_WIDTH;
  483. int yOffset = (yDiff % cySrcTileSize);
  484. dng.pvSrcBits -= yOffset * dng.iSrcBufWidth;
  485. int iTileOffset = cySrcTileSize - yOffset;
  486. int yMax = min(yMin + min(cySrcTileSize, cyDestTileSize), min(iDestHeight - cyBottomHeight, cyClipMax));
  487. for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= dng.iSrcBufWidth)
  488. {
  489. DNG_DrawRow(&dng);
  490. iTileOffset--;
  491. if (iTileOffset == 0)
  492. {
  493. iTileOffset = cySrcTileSize;
  494. dng.pvSrcBits += dng.iSrcBufWidth * cySrcTileSize;
  495. }
  496. }
  497. // Repeat tile pattern
  498. dng.pvSrcBits = dng.pvDestBits + (DNG_BUF_WIDTH * cySrcTileSize);
  499. yMin = yMax;
  500. yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
  501. for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= DNG_BUF_WIDTH)
  502. {
  503. CopyMemory(dng.pvDestBits + dng.cxClipMin, dng.pvSrcBits + dng.cxClipMin, dng.iClipWidth * sizeof(ULONG));
  504. }
  505. }
  506. else
  507. {
  508. int yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
  509. STRETCH stretch;
  510. DNG_InitStretch(&stretch, cyDestTileSize, cySrcTileSize, cyDestTileSize - (yMax - cyTopHeight), cyDestTileSize - (yMin - cyTopHeight));
  511. // Convert from screen coords to DIB coords
  512. DNG_StretchCol(&dng, &stretch);
  513. }
  514. }
  515. // Draw Top
  516. // Draw the scan line from 0 to less than cyNewTopHeight, in screen coordinates
  517. yMin = cyClipMin;
  518. yMax = min(cyNewTopHeight, cyClipMax);
  519. if (cyClipMin < cyNewTopHeight)
  520. {
  521. dng.pvDestBits = pvDestBits + (iDestHeight - cyNewTopHeight) * DNG_BUF_WIDTH;
  522. dng.pvSrcBits = pngiSrc->pvBits + (pngiSrc->iHeight - pngiSrc->margin.cyTopHeight) * pngiSrc->iBufWidth;
  523. if (cyTopHeight == cyNewTopHeight)
  524. {
  525. dng.pvDestBits += (cyTopHeight - 1 - yMin) * DNG_BUF_WIDTH;
  526. dng.pvSrcBits += (cyTopHeight - 1 - yMin) * dng.iSrcBufWidth;
  527. for (int y = yMin; y < yMax; y++, dng.pvDestBits -= DNG_BUF_WIDTH, dng.pvSrcBits -= dng.iSrcBufWidth)
  528. {
  529. DNG_DrawRow(&dng);
  530. }
  531. }
  532. else if (cyNewTopHeight > 0)
  533. {
  534. STRETCH stretch;
  535. DNG_InitStretch(&stretch, cyNewTopHeight, cyTopHeight, cyNewTopHeight - yMax, cyNewTopHeight - yMin);
  536. DNG_StretchCol(&dng, &stretch);
  537. }
  538. }
  539. }
  540. if ((dwFlags & DNG_MUSTFLIP) && ((pngiSrc->dwFlags & NGI_TRANS) || (pngiSrc->dwFlags & NGI_ALPHA)))
  541. {
  542. // Flip the buffer
  543. for (int y = 0; y < DNG_BUF_HEIGHT; y++)
  544. {
  545. ULONG* pvLeftBits = s_pvBitsBuf + (y * DNG_BUF_WIDTH);
  546. ULONG* pvRightBits = s_pvBitsBuf + (y * DNG_BUF_WIDTH) + iClipWidth - 1;
  547. for (int x = 0; x < (iClipWidth / 2); x++)
  548. {
  549. ULONG ulTemp = *pvLeftBits;
  550. *pvLeftBits = *pvRightBits;
  551. *pvRightBits = ulTemp;
  552. pvLeftBits++;
  553. pvRightBits--;
  554. }
  555. }
  556. }
  557. if (pngiSrc->dwFlags & NGI_ALPHA)
  558. {
  559. BLENDFUNCTION bf;
  560. bf.BlendOp = AC_SRC_OVER;
  561. bf.BlendFlags = 0;
  562. bf.SourceConstantAlpha = 255;
  563. bf.AlphaFormat = AC_SRC_ALPHA;
  564. GdiAlphaBlend(hdc, rcClip.left, rcClip.top, cxImage, cyImage, s_hdcBuf, 0, 0, cxImage, cyImage, bf);
  565. }
  566. else if (pngiSrc->dwFlags & NGI_TRANS)
  567. {
  568. GdiTransparentBlt(hdc, rcClip.left, rcClip.top, cxImage, cyImage, s_hdcBuf, 0, 0, cxImage, cyImage, pngiSrc->crTrans);
  569. }
  570. else
  571. {
  572. BitBlt(hdc, rcClip.left, rcClip.top, cxImage, cyImage, s_hdcBuf, 0, 0, SRCCOPY);
  573. }
  574. }
  575. else
  576. {
  577. hr = E_OUTOFMEMORY;
  578. }
  579. LeaveCriticalSection(&s_dngLock);
  580. }
  581. }
  582. return hr;
  583. }