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.

777 lines
26 KiB

  1. /****************************************************************************/
  2. // drawninegrid.cpp
  3. //
  4. // GdiDrawStream Emulation functions
  5. //
  6. // Copyright (C) 2001 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. #ifndef OS_WINCE
  10. extern "C" {
  11. #define TRC_GROUP TRC_GROUP_CORE
  12. #define TRC_FILE "drawninegrid"
  13. #include <atrcapi.h>
  14. }
  15. #include "aordprot.h"
  16. FNGDI_ALPHABLEND *g_pfnAlphaBlend = NULL;
  17. FNGDI_TRANSPARENTBLT *g_pfnTransparentBlt = NULL;
  18. typedef struct _DNGSTRETCH
  19. {
  20. ULONG xStart;
  21. ULONG xAccum;
  22. ULONG xFrac;
  23. ULONG xInt;
  24. ULONG ulDestWidth;
  25. ULONG ulSrcWidth;
  26. int left;
  27. int right;
  28. } DNGSTRETCH;
  29. typedef struct _DNGINTERNALDATA
  30. {
  31. int cxClipMin;
  32. int cxClipMax;
  33. ULONG* pvDestBits;
  34. LONG lDestDelta;
  35. int iDestWidth;
  36. int iClipWidth;
  37. ULONG* pvSrcBits;
  38. LONG lSrcDelta;
  39. int iSrcWidth;
  40. int iSrcBufWidth;
  41. int cxLeftWidth;
  42. int xMinLeft;
  43. int xMaxLeft;
  44. int cxRightWidth;
  45. int xMinRight;
  46. int xMaxRight;
  47. int cxMiddleWidth;
  48. int cxNewMiddleWidth;
  49. int xMinMiddle;
  50. int xMaxMiddle;
  51. // Variable for shrunken corners and sides
  52. BOOL fShowMiddle;
  53. DNGSTRETCH stretchLeft;
  54. DNGSTRETCH stretchRight;
  55. int cxNewLeftWidth;
  56. int cxNewRightWidth;
  57. BOOL fTileMode;
  58. // Specific to non-tile mode (i.e. stretch mode)
  59. DNGSTRETCH stretchMiddle;
  60. LONG lBufWidth;
  61. } DNGINTERNALDATA;
  62. static inline void DNG_StretchRow(ULONG* pvDestBits, ULONG* pvSrcBits, DNGSTRETCH * ps)
  63. {
  64. ULONG* pvTemp = pvDestBits + ps->left;
  65. ULONG* pvSentinel = pvDestBits + ps->right;
  66. ULONG xInt = ps->xInt;
  67. ULONG xFrac = ps->xFrac;
  68. ULONG xTmp;
  69. ULONG xAccum = ps->xAccum;
  70. ULONG * pulSrc = pvSrcBits + ps->xStart;
  71. ULONG ulSrc;
  72. while (pvTemp != pvSentinel)
  73. {
  74. ulSrc = *pulSrc;
  75. xTmp = xAccum + xFrac;
  76. pulSrc = pulSrc + xInt + (xTmp < xAccum);
  77. *pvTemp = ulSrc;
  78. pvTemp++;
  79. xAccum = xTmp;
  80. }
  81. }
  82. static inline void DNG_InitStretch(DNGSTRETCH* pStretch, ULONG ulDestWidth, ULONG ulSrcWidth, int left, int right)
  83. {
  84. pStretch->right = right;
  85. pStretch->left = left;
  86. ULONGLONG dx = ((((ULONGLONG) ulSrcWidth << 32) - 1) / (ULONGLONG) ulDestWidth) + 1;
  87. ULONGLONG x = (((ULONGLONG) ulSrcWidth << 32) / (ULONGLONG) ulDestWidth) >> 1;
  88. ULONG xInt = pStretch->xInt = (ULONG) (dx >> 32);
  89. ULONG xFrac = pStretch->xFrac = (ULONG) (dx & 0xFFFFFFFF);
  90. ULONG xAccum = (ULONG) (x & 0xFFFFFFFF);
  91. ULONG xTmp;
  92. ULONG xStart = (ULONG) (x >> 32);
  93. for (int i = 0; i < left; i++)
  94. {
  95. xTmp = xAccum + xFrac;
  96. xStart = xStart + xInt + (xTmp < xAccum);
  97. xAccum = xTmp;
  98. }
  99. pStretch->xStart = xStart;
  100. pStretch->xAccum = xAccum;
  101. }
  102. static inline void DNG_DrawRow(DNGINTERNALDATA* pdng)
  103. {
  104. ULONG* pvDestLoc = pdng->pvDestBits;
  105. ULONG* pvSrcLoc = pdng->pvSrcBits;
  106. // Left
  107. if (pdng->cxClipMin < pdng->cxNewLeftWidth)
  108. {
  109. if (pdng->cxLeftWidth == pdng->cxNewLeftWidth)
  110. {
  111. memcpy(pvDestLoc + pdng->xMinLeft, pvSrcLoc + pdng->xMinLeft, (pdng->xMaxLeft - pdng->xMinLeft) * sizeof(ULONG));
  112. }
  113. else
  114. {
  115. DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchLeft);
  116. }
  117. }
  118. pvDestLoc += pdng->cxNewLeftWidth;
  119. pvSrcLoc += pdng->cxLeftWidth;
  120. // Middle
  121. if (pdng->fShowMiddle)
  122. {
  123. if (pdng->xMinMiddle < pdng->xMaxMiddle)
  124. {
  125. if (pdng->fTileMode)
  126. {
  127. ULONG* pvTempSrc = pvSrcLoc;
  128. ULONG* pvTempDest = pvDestLoc;
  129. // Fill in Top Tile
  130. int xMin = pdng->xMinMiddle;
  131. int xDiff = xMin - pdng->cxLeftWidth;
  132. pvDestLoc += xDiff;
  133. int iTileSize = pdng->cxMiddleWidth - (xDiff % pdng->cxMiddleWidth);
  134. pvSrcLoc += xDiff % pdng->cxMiddleWidth;
  135. int xMax = pdng->xMaxMiddle;
  136. for (int x = xMin; x < xMax; x++, pvDestLoc++ , pvSrcLoc++)
  137. {
  138. *pvDestLoc = *pvSrcLoc;
  139. iTileSize--;
  140. if (iTileSize == 0)
  141. {
  142. iTileSize = pdng->cxMiddleWidth;
  143. pvSrcLoc -= iTileSize;
  144. }
  145. }
  146. pvDestLoc = pvTempDest;
  147. pvSrcLoc = pvTempSrc;
  148. }
  149. else
  150. {
  151. DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchMiddle);
  152. }
  153. }
  154. pvDestLoc += pdng->cxNewMiddleWidth;
  155. }
  156. pvSrcLoc += pdng->cxMiddleWidth;
  157. // Right
  158. if (pdng->cxClipMax > (pdng->iDestWidth - pdng->cxNewRightWidth))
  159. {
  160. if (pdng->cxRightWidth == pdng->cxNewRightWidth)
  161. {
  162. memcpy(pvDestLoc + pdng->xMinRight, pvSrcLoc + pdng->xMinRight, (pdng->xMaxRight - pdng->xMinRight) * sizeof(ULONG));
  163. }
  164. else
  165. {
  166. DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchRight);
  167. }
  168. }
  169. }
  170. static inline void DNG_StretchCol(DNGINTERNALDATA* pdng, DNGSTRETCH * ps)
  171. {
  172. ULONG* pvOldDestBits = pdng->pvDestBits;
  173. ULONG* pvOldSrcBits = pdng->pvSrcBits;
  174. ULONG* pvTemp = pdng->pvDestBits - (pdng->lDestDelta * ps->left);
  175. ULONG* pvSentinel = pdng->pvDestBits - (pdng->lDestDelta * ps->right);
  176. ULONG xInt = ps->xInt;
  177. ULONG xFrac = ps->xFrac;
  178. ULONG xTmp;
  179. ULONG xAccum = ps->xAccum;
  180. ULONG * pulSrc = pdng->pvSrcBits - (pdng->lSrcDelta * ps->xStart);
  181. ULONG xDelta = 1; // force stretch on first scan
  182. while (pvTemp != pvSentinel)
  183. {
  184. if (xDelta != 0)
  185. {
  186. pdng->pvDestBits = pvTemp;
  187. pdng->pvSrcBits = pulSrc;
  188. DNG_DrawRow(pdng);
  189. }
  190. else
  191. {
  192. memcpy(pvTemp + pdng->cxClipMin, pvTemp + pdng->cxClipMin + pdng->lDestDelta, pdng->iClipWidth * sizeof(ULONG));
  193. }
  194. xTmp = xAccum + xFrac;
  195. xDelta = (xInt + (xTmp < xAccum));
  196. pulSrc = pulSrc - (pdng->lSrcDelta * xDelta);
  197. pvTemp -= pdng->lDestDelta;
  198. xAccum = xTmp;
  199. }
  200. pdng->pvDestBits = pvOldDestBits;
  201. pdng->pvSrcBits = pvOldSrcBits;
  202. }
  203. static void RenderNineGridInternal(
  204. TS_BITMAPOBJ *psoScratch,
  205. TS_BITMAPOBJ *psoSrc,
  206. RECTL *prclClip,
  207. RECTL *prclDst,
  208. RECTL *prclSrc,
  209. DS_NINEGRIDINFO *ngi,
  210. BOOL bMirror)
  211. {
  212. RECTL rcDest = *prclDst;
  213. RECTL rcClip = *prclClip;
  214. ULONG* pvDestBits = NULL;
  215. int iDestWidth = rcDest.right - rcDest.left;
  216. int iDestHeight = rcDest.bottom - rcDest.top;
  217. int iClipWidth = rcClip.right - rcClip.left;
  218. int iClipHeight = rcClip.bottom - rcClip.top;
  219. LONG lBufWidth = psoScratch->sizlBitmap.cx;
  220. LONG lBufHeight = psoScratch->sizlBitmap.cy;
  221. DNGINTERNALDATA dng;
  222. // The code below assumes that the source and scratch is 32bpp
  223. //ASSERTGDI(psoSrc->iBitmapFormat == BMF_32BPP, "RenderNineGridInternal: source not 32bpp");
  224. //ASSERTGDI(psoScratch->iBitmapFormat == BMF_32BPP, "RenderNineGridInternal: scratch not 32bpp");
  225. // The code below assumes that both source and scratch are bottom up
  226. // ASSERTGDI(psoSrc->lDelta < 0, "RenderNineGridInternal: source is not bottom up");
  227. // ASSERTGDI(psoScratch->lDelta < 0, "RenderNineGridInternal: scratch is not bottom up");
  228. dng.lBufWidth = lBufWidth;
  229. LONG lDestDelta = psoScratch->lDelta / sizeof(ULONG);
  230. dng.lDestDelta = lDestDelta;
  231. LONG lSrcDelta = psoSrc->lDelta / sizeof(ULONG);
  232. dng.lSrcDelta = lSrcDelta;
  233. dng.cxClipMin = rcClip.left - rcDest.left;
  234. dng.cxClipMax = rcClip.right - rcDest.left;
  235. int cyClipMin = rcClip.top - rcDest.top;
  236. int cyClipMax = rcClip.bottom - rcDest.top;
  237. // pvBits points to the pixel addressed at (cxClipMin, cyClipMin)
  238. // pvDestBits points to the pixel addressed at (0, iDestHeight - 1)
  239. pvDestBits = (ULONG *) psoScratch->pvBits;
  240. pvDestBits += (iDestHeight - 1 - cyClipMin) * lDestDelta;
  241. pvDestBits -= dng.cxClipMin;
  242. int cxImage = rcClip.right - rcClip.left;
  243. int cyImage = rcClip.bottom - rcClip.top;
  244. LONG lSrcBufWidth = psoSrc->sizlBitmap.cx;
  245. LONG lSrcWidth = prclSrc->right - prclSrc->left;
  246. LONG lSrcHeight = prclSrc->bottom - prclSrc->top;
  247. ULONG * lSrcBits = (ULONG *) psoSrc->pvBits + (lSrcDelta * prclSrc->top) + prclSrc->left;
  248. lSrcBits += (lSrcDelta * (prclSrc->bottom - prclSrc->top - 1));
  249. // ULONG * lSrcBits = (ULONG *) psoSrc->pvScan0 + (lSrcDelta * (psoSrc->sizlBitmap.cy - 1));
  250. if (ngi->flFlags & DSDNG_TRUESIZE)
  251. {
  252. ULONG* pvDestLoc = pvDestBits - ((iDestHeight - 1) * lDestDelta);
  253. ULONG* pvSrcLoc = lSrcBits - ((lSrcHeight - 1) * lSrcDelta);
  254. int yMin = cyClipMin;
  255. pvDestLoc += yMin * lDestDelta;
  256. pvSrcLoc += yMin * lSrcDelta;
  257. int yMax = min(lSrcHeight, cyClipMax);
  258. int xMin = dng.cxClipMin;
  259. int xMax = min(lSrcWidth, dng.cxClipMax);
  260. if (xMax > xMin)
  261. {
  262. for (int y = yMin; y < yMax; y++, pvDestLoc += lDestDelta, pvSrcLoc += lSrcDelta)
  263. {
  264. memcpy(pvDestLoc + xMin, pvSrcLoc + xMin, (xMax - xMin) * 4);
  265. }
  266. }
  267. cxImage = xMax - xMin;
  268. cyImage = yMax - yMin;
  269. }
  270. else
  271. {
  272. // Setup data
  273. dng.iDestWidth = iDestWidth;
  274. dng.iClipWidth = iClipWidth;
  275. dng.iSrcWidth = lSrcWidth;
  276. dng.iSrcBufWidth = lSrcBufWidth;
  277. dng.cxLeftWidth = ngi->ulLeftWidth;
  278. dng.cxRightWidth = ngi->ulRightWidth;
  279. dng.fTileMode = (ngi->flFlags & DSDNG_TILE);
  280. // Calculate clip stuff
  281. // Pre-calc corner stretching variables
  282. dng.fShowMiddle = (iDestWidth - dng.cxLeftWidth - dng.cxRightWidth > 0);
  283. if (!dng.fShowMiddle)
  284. {
  285. dng.cxNewLeftWidth = (dng.cxLeftWidth + dng.cxRightWidth == 0) ? 0 : (dng.cxLeftWidth * dng.iDestWidth) / (dng.cxLeftWidth + dng.cxRightWidth);
  286. dng.cxNewRightWidth = dng.iDestWidth - dng.cxNewLeftWidth;
  287. }
  288. else
  289. {
  290. dng.cxNewLeftWidth = dng.cxLeftWidth;
  291. dng.cxNewRightWidth = dng.cxRightWidth;
  292. }
  293. // Pre-calc Left side variables
  294. dng.xMinLeft = dng.cxClipMin;
  295. dng.xMaxLeft = min(dng.cxNewLeftWidth, dng.cxClipMax);
  296. if (!dng.fShowMiddle && dng.cxNewLeftWidth)
  297. {
  298. DNG_InitStretch(&dng.stretchLeft, dng.cxNewLeftWidth, dng.cxLeftWidth, dng.xMinLeft, dng.xMaxLeft);
  299. }
  300. // Pre-calc Horizontal Middle Variables
  301. dng.cxMiddleWidth = dng.iSrcWidth - dng.cxLeftWidth - dng.cxRightWidth;
  302. dng.cxNewMiddleWidth = dng.iDestWidth - dng.cxNewLeftWidth - dng.cxNewRightWidth;
  303. dng.xMinMiddle = max(dng.cxNewLeftWidth, dng.cxClipMin);
  304. dng.xMaxMiddle = min(dng.cxNewLeftWidth + dng.cxNewMiddleWidth, dng.cxClipMax);
  305. if (dng.fShowMiddle)
  306. {
  307. DNG_InitStretch(&dng.stretchMiddle, dng.cxNewMiddleWidth, dng.cxMiddleWidth, dng.xMinMiddle - dng.cxNewLeftWidth, dng.xMaxMiddle - dng.cxNewLeftWidth);
  308. }
  309. // Pre-calc Right side variables
  310. dng.xMinRight = max(dng.iDestWidth - dng.cxNewRightWidth, dng.cxClipMin) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
  311. dng.xMaxRight = min(dng.iDestWidth, dng.cxClipMax) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
  312. if (!dng.fShowMiddle && dng.cxNewRightWidth)
  313. {
  314. DNG_InitStretch(&dng.stretchRight, dng.cxNewRightWidth, dng.cxRightWidth, dng.xMinRight, dng.xMaxRight);
  315. }
  316. BOOL fShowVertMiddle = (iDestHeight - ngi->ulTopHeight - ngi->ulBottomHeight > 0);
  317. int cyTopHeight = ngi->ulTopHeight;
  318. int cyBottomHeight = ngi->ulBottomHeight;
  319. int cyNewTopHeight;
  320. int cyNewBottomHeight;
  321. if (!fShowVertMiddle)
  322. {
  323. cyNewTopHeight = (cyTopHeight + cyBottomHeight == 0) ? 0 : (cyTopHeight * iDestHeight) / (cyTopHeight + cyBottomHeight);
  324. cyNewBottomHeight = iDestHeight - cyNewTopHeight;
  325. }
  326. else
  327. {
  328. cyNewTopHeight = cyTopHeight;
  329. cyNewBottomHeight = cyBottomHeight;
  330. }
  331. // Draw Bottom
  332. // Draw the scan line from (iDestHeight - cyNewBottomHeight) to less than iDestHeight, in screen coordinates
  333. int yMin = max(iDestHeight - cyNewBottomHeight, cyClipMin);
  334. int yMax = min(iDestHeight, cyClipMax);
  335. if (cyClipMax > iDestHeight - cyNewBottomHeight)
  336. {
  337. dng.pvDestBits = pvDestBits;
  338. dng.pvSrcBits = lSrcBits;
  339. if (cyBottomHeight == cyNewBottomHeight)
  340. {
  341. int yDiff = yMin - (iDestHeight - cyNewBottomHeight);
  342. dng.pvDestBits -= (cyBottomHeight - 1 - yDiff) * lDestDelta;
  343. dng.pvSrcBits -= (cyBottomHeight - 1 - yDiff) * lSrcDelta;
  344. for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lSrcDelta)
  345. {
  346. DNG_DrawRow(&dng);
  347. }
  348. }
  349. else if (cyNewBottomHeight > 0)
  350. {
  351. DNGSTRETCH stretch;
  352. DNG_InitStretch(&stretch, cyNewBottomHeight, cyBottomHeight, cyNewBottomHeight - (yMax - iDestHeight + cyNewBottomHeight), cyNewBottomHeight - (yMin - iDestHeight + cyNewBottomHeight));
  353. DNG_StretchCol(&dng, &stretch);
  354. }
  355. }
  356. // Draw Middle
  357. // Draw the scan line from cyNewTopHeight to less than (iDestHeight - cyNewBottomHeight), in screen coordinates
  358. if (fShowVertMiddle && (cyClipMin < iDestHeight - cyNewBottomHeight) && (cyClipMax > cyNewTopHeight))
  359. {
  360. int cySrcTileSize = lSrcHeight - ngi->ulTopHeight - ngi->ulBottomHeight;
  361. int cyDestTileSize = iDestHeight - ngi->ulTopHeight - ngi->ulBottomHeight;
  362. dng.pvDestBits = pvDestBits - ngi->ulBottomHeight * lDestDelta;
  363. dng.pvSrcBits = lSrcBits - ngi->ulBottomHeight * lSrcDelta;
  364. int yMin = max(cyTopHeight, cyClipMin);
  365. if (dng.fTileMode)
  366. {
  367. // Start off tile
  368. dng.pvDestBits -= (cyDestTileSize - 1) * lDestDelta;
  369. dng.pvSrcBits -= (cySrcTileSize - 1) * lSrcDelta;
  370. int yDiff = yMin - cyTopHeight;
  371. dng.pvDestBits += yDiff * lDestDelta;
  372. int yOffset = (yDiff % cySrcTileSize);
  373. dng.pvSrcBits += yOffset * dng.lSrcDelta;
  374. int iTileOffset = cySrcTileSize - yOffset;
  375. int yMax = min(yMin + min(cySrcTileSize, cyDestTileSize), min(iDestHeight - cyBottomHeight, cyClipMax));
  376. for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lSrcDelta)
  377. {
  378. DNG_DrawRow(&dng);
  379. iTileOffset--;
  380. if (iTileOffset == 0)
  381. {
  382. iTileOffset = cySrcTileSize;
  383. dng.pvSrcBits -= lSrcDelta * cySrcTileSize;
  384. }
  385. }
  386. // Repeat tile pattern
  387. dng.pvSrcBits = dng.pvDestBits - (lDestDelta * cySrcTileSize);
  388. yMin = yMax;
  389. yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
  390. for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lDestDelta)
  391. {
  392. memcpy(dng.pvDestBits + dng.cxClipMin, dng.pvSrcBits + dng.cxClipMin, dng.iClipWidth * sizeof(ULONG));
  393. }
  394. }
  395. else
  396. {
  397. int yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
  398. DNGSTRETCH stretch;
  399. DNG_InitStretch(&stretch, cyDestTileSize, cySrcTileSize, cyDestTileSize - (yMax - cyTopHeight), cyDestTileSize - (yMin - cyTopHeight));
  400. // Convert from screen coords to DIB coords
  401. DNG_StretchCol(&dng, &stretch);
  402. }
  403. }
  404. // Draw Top
  405. // Draw the scan line from 0 to less than cyNewTopHeight, in screen coordinates
  406. yMin = cyClipMin;
  407. yMax = min(cyNewTopHeight, cyClipMax);
  408. if (cyClipMin < cyNewTopHeight)
  409. {
  410. dng.pvDestBits = pvDestBits - (iDestHeight - cyNewTopHeight) * lDestDelta;
  411. dng.pvSrcBits = lSrcBits - (lSrcHeight - ngi->ulTopHeight) * lSrcDelta;
  412. if (cyTopHeight == cyNewTopHeight)
  413. {
  414. dng.pvDestBits -= (cyTopHeight - 1 - yMin) * lDestDelta;
  415. dng.pvSrcBits -= (cyTopHeight - 1 - yMin) * lSrcDelta;
  416. for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lSrcDelta)
  417. {
  418. DNG_DrawRow(&dng);
  419. }
  420. }
  421. else if (cyNewTopHeight > 0)
  422. {
  423. DNGSTRETCH stretch;
  424. DNG_InitStretch(&stretch, cyNewTopHeight, cyTopHeight, cyNewTopHeight - yMax, cyNewTopHeight - yMin);
  425. DNG_StretchCol(&dng, &stretch);
  426. }
  427. }
  428. }
  429. if (bMirror)
  430. {
  431. // Flip the buffer
  432. for (int y = 0; y < iClipHeight; y++)
  433. {
  434. ULONG* pvLeftBits = (ULONG *) psoScratch->pvBits + (y * lDestDelta);
  435. ULONG* pvRightBits = pvLeftBits + iClipWidth - 1;
  436. for (int x = 0; x < (iClipWidth / 2); x++)
  437. {
  438. ULONG ulTemp = *pvLeftBits;
  439. *pvLeftBits = *pvRightBits;
  440. *pvRightBits = ulTemp;
  441. pvLeftBits++;
  442. pvRightBits--;
  443. }
  444. }
  445. }
  446. }
  447. static void RenderNineGrid(
  448. HDC hdcDst,
  449. TS_BITMAPOBJ *psoSrc,
  450. TS_BITMAPOBJ *psoScratch,
  451. RECTL *prclClip,
  452. RECTL *prclDst,
  453. RECTL *prclSrc,
  454. DS_NINEGRIDINFO *ngi,
  455. BOOL bMirror)
  456. {
  457. // only mirror the contents if we need to
  458. bMirror = bMirror && (ngi->flFlags & DSDNG_MUSTFLIP);
  459. // render nine grid into scratch
  460. RECTL erclClip = *prclClip;
  461. if(bMirror)
  462. {
  463. // We need to remap the clip to ensure we generate the right flipped bits
  464. erclClip.right = prclDst->right - (prclClip->left - prclDst->left);
  465. erclClip.left = prclDst->right - (prclClip->right - prclDst->left);
  466. }
  467. RenderNineGridInternal(psoScratch, psoSrc, &erclClip, prclDst, prclSrc, ngi, bMirror);
  468. // copy scratch to destination
  469. LONG lClipWidth = prclClip->right - prclClip->left;
  470. LONG lClipHeight = prclClip->bottom - prclClip->top;
  471. RECTL erclScratch = {0, 0, lClipWidth, lClipHeight};
  472. if(ngi->flFlags & DSDNG_PERPIXELALPHA)
  473. {
  474. BLENDFUNCTION BlendFunc;
  475. BlendFunc.AlphaFormat = AC_SRC_ALPHA;
  476. BlendFunc.BlendFlags = 0;
  477. BlendFunc.SourceConstantAlpha = 255;
  478. BlendFunc.BlendOp = AC_SRC_OVER;
  479. //PPFNDIRECT(psoDst, AlphaBlend)(psoDst, psoScratch, prclClip, &erclScratch, &eBlendObj);
  480. g_pfnAlphaBlend(hdcDst, prclClip->left, prclClip->top, (prclClip->right - prclClip->left),
  481. (prclClip->bottom - prclClip->top), psoScratch->hdc, erclScratch.left, erclScratch.top,
  482. (erclScratch.right - erclScratch.left), (erclScratch.bottom - erclScratch.top),
  483. BlendFunc);
  484. }
  485. else if(ngi->flFlags & DSDNG_TRANSPARENT)
  486. {
  487. //PPFNDIRECT(psoDst, TransparentBlt)(psoDst, psoScratch, prclClip, &erclScratch, ngi->crTransparent, 0);
  488. g_pfnTransparentBlt(hdcDst, prclClip->left, prclClip->top, (prclClip->right - prclClip->left),
  489. (prclClip->bottom - prclClip->top), psoScratch->hdc, erclScratch.left, erclScratch.top,
  490. (erclScratch.right - erclScratch.left), (erclScratch.bottom - erclScratch.top),
  491. ngi->crTransparent);
  492. }
  493. else
  494. {
  495. //PPFNDIRECT(psoDst, CopyBits)(psoDst, psoScratch, prclClip, &gptlZero);
  496. BitBlt(hdcDst, prclClip->left, prclClip->top, (prclClip->right - prclClip->left),
  497. (prclClip->bottom - prclClip->top), psoScratch->hdc, erclScratch.left, erclScratch.top,
  498. SRCCOPY);
  499. }
  500. }
  501. BOOL DrawNineGrid(
  502. HDC hdcDst,
  503. TS_BITMAPOBJ *psoSrc,
  504. TS_DS_NINEGRID *pDNG)
  505. {
  506. BOOL bRet = FALSE;
  507. DS_NINEGRIDINFO *ngi;
  508. RECTL erclDst;
  509. PRECTL prclSrc;
  510. TS_BITMAPOBJ soScratch = { 0 };
  511. HBITMAP hBitmap = NULL;
  512. ngi = &(pDNG->dng.ngi);
  513. erclDst = pDNG->dng.rclDst;
  514. prclSrc = &(pDNG->dng.rclSrc);
  515. g_pfnAlphaBlend = pDNG->pfnAlphaBlend;
  516. g_pfnTransparentBlt = pDNG->pfnTransparentBlt;
  517. BOOL bMirror = (erclDst.left > erclDst.right);
  518. if(bMirror)
  519. {
  520. LONG lRight = erclDst.left;
  521. erclDst.left = erclDst.right;
  522. erclDst.right = lRight;
  523. }
  524. // NOTE: TRUESIZE is a hack. The caller should do this reduction
  525. // and pass us an appropriate destination.
  526. // TODO: Talk with Justin Mann about changing his behavior in how
  527. // he calls us here. We should add assertions that the
  528. // destination dimensions never exceeds the source dimensions and
  529. // modify GdiDrawStream callers to pass appropriate data.
  530. if(ngi->flFlags & DSDNG_TRUESIZE)
  531. {
  532. LONG lSrcWidth = prclSrc->right - prclSrc->left;
  533. LONG lSrcHeight = prclSrc->bottom - prclSrc->top;
  534. // reduce destination to source size
  535. if((erclDst.right - erclDst.left) > lSrcWidth)
  536. {
  537. if(bMirror)
  538. erclDst.left = erclDst.right - lSrcWidth;
  539. else
  540. erclDst.right = erclDst.left + lSrcWidth;
  541. }
  542. if((erclDst.bottom - erclDst.top) > lSrcHeight)
  543. {
  544. if(bMirror)
  545. erclDst.top = erclDst.bottom - lSrcHeight;
  546. else
  547. erclDst.bottom = erclDst.top + lSrcHeight;
  548. }
  549. }
  550. RECTL erclClip = erclDst;
  551. // For now, we only support 32bpp sources
  552. //ASSERTGDI(psoSrc->iBitmapFormat == BMF_32BPP, "EngNineGrid: source not 32bpp");
  553. //ASSERTGDI(erclClip.left >= 0 &&
  554. // erclClip.top >= 0 &&
  555. // erclClip.right <= psoDst->sizlBitmap.cx &&
  556. // erclClip.bottom <= psoDst->sizlBitmap.cy, "EngNineGrid: bad clip");
  557. if(erclClip.left <= erclClip.right && erclClip.top <= erclClip.bottom)
  558. {
  559. LONG lClipWidth = erclClip.right - erclClip.left;
  560. LONG lClipHeight = erclClip.bottom - erclClip.top;
  561. //ASSERTGDI(lClipWidth > 0, "RenderNineGrid: clip width <= 0");
  562. //ASSERTGDI(lClipHeight > 0, "RenderNineGrid: clip height <= 0");
  563. #define SCRATCH_WIDTH (256)
  564. #define SCRATCH_HEIGHT (64)
  565. {
  566. BITMAPINFO bi = { 0 };
  567. void * pvBits = NULL;
  568. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  569. bi.bmiHeader.biWidth = SCRATCH_WIDTH;
  570. bi.bmiHeader.biHeight = 0 - SCRATCH_HEIGHT;
  571. bi.bmiHeader.biPlanes = 1;
  572. bi.bmiHeader.biBitCount = 32;
  573. bi.bmiHeader.biCompression = BI_RGB;
  574. hBitmap = CreateDIBSection(psoSrc->hdc, &bi, DIB_RGB_COLORS,
  575. (VOID**)&pvBits, NULL, 0);
  576. if (hBitmap) {
  577. soScratch.cjBits = SCRATCH_WIDTH * SCRATCH_HEIGHT * 32 / 8;
  578. soScratch.iBitmapFormat = 32;
  579. soScratch.lDelta = SCRATCH_WIDTH * sizeof(ULONG);
  580. soScratch.pvBits = pvBits;
  581. soScratch.sizlBitmap.cx = SCRATCH_WIDTH;
  582. soScratch.sizlBitmap.cy = SCRATCH_HEIGHT;
  583. soScratch.hdc = CreateCompatibleDC(NULL);
  584. if (soScratch.hdc != NULL) {
  585. SelectBitmap(soScratch.hdc, hBitmap);
  586. }
  587. else {
  588. goto exit;
  589. }
  590. }
  591. else {
  592. goto exit;
  593. }
  594. }
  595. if(lClipWidth > SCRATCH_WIDTH || lClipHeight > SCRATCH_HEIGHT)
  596. {
  597. LONG lBufWidth = SCRATCH_WIDTH;
  598. LONG lBufHeight = SCRATCH_HEIGHT;
  599. LONG lReducedClipTop = erclClip.top;
  600. while(lReducedClipTop < erclClip.bottom)
  601. {
  602. LONG lReducedClipBottom = lReducedClipTop + lBufHeight;
  603. if(lReducedClipBottom > erclClip.bottom)
  604. lReducedClipBottom = erclClip.bottom;
  605. LONG lReducedClipLeft = erclClip.left;
  606. while(lReducedClipLeft < erclClip.right)
  607. {
  608. LONG lReducedClipRight = lReducedClipLeft + lBufWidth;
  609. if(lReducedClipRight > erclClip.right)
  610. lReducedClipRight = erclClip.right;
  611. RECTL erclReducedClip = {lReducedClipLeft, lReducedClipTop,
  612. lReducedClipRight, lReducedClipBottom};
  613. RenderNineGrid(hdcDst,
  614. psoSrc,
  615. &soScratch,
  616. &erclReducedClip,
  617. &erclDst,
  618. prclSrc,
  619. ngi,
  620. bMirror);
  621. lReducedClipLeft += lBufWidth;
  622. }
  623. lReducedClipTop += lBufHeight;
  624. }
  625. }
  626. else
  627. {
  628. RenderNineGrid(hdcDst, psoSrc, &soScratch, &erclClip, &erclDst, prclSrc, ngi, bMirror);
  629. }
  630. }
  631. bRet = TRUE;
  632. exit:
  633. if (hBitmap != NULL) {
  634. DeleteObject(hBitmap);
  635. }
  636. if (soScratch.hdc != NULL) {
  637. DeleteDC(soScratch.hdc);
  638. }
  639. return bRet;
  640. }
  641. #endif