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.

738 lines
21 KiB

  1. /******************************************************************************\
  2. *
  3. * $Workfile: stretch.c $
  4. *
  5. * DrvStretchBlt function.
  6. *
  7. * Copyright (c) 1993-1995 Microsoft Corporation
  8. * Copyright (c) 1996 Cirrus Logic, Inc.
  9. *
  10. * $Log: S:/projects/drivers/ntsrc/display/STRETCH.C_V $
  11. *
  12. * Rev 1.3 10 Jan 1997 15:40:16 PLCHU
  13. *
  14. *
  15. * Rev 1.2 Nov 07 1996 16:48:04 unknown
  16. *
  17. *
  18. * Rev 1.1 Oct 10 1996 15:39:02 unknown
  19. *
  20. *
  21. * Rev 1.1 12 Aug 1996 16:55:00 frido
  22. * Removed unaccessed local variables.
  23. *
  24. * chu01 : 01-02-97 5480 BitBLT enhancement
  25. *
  26. \******************************************************************************/
  27. #include "precomp.h"
  28. #define STRETCH_MAX_EXTENT 32767
  29. typedef DWORDLONG ULONGLONG;
  30. /******************************Public*Routine******************************\
  31. *
  32. * Routine Name
  33. *
  34. * vDirectStretch8Narrow
  35. *
  36. * Routine Description:
  37. *
  38. * Stretch blt 8->8 when the width is 7 or less
  39. *
  40. * Arguments:
  41. *
  42. * pStrBlt - contains all params for blt
  43. *
  44. * Return Value:
  45. *
  46. * VOID
  47. *
  48. \**************************************************************************/
  49. VOID vDirectStretch8Narrow(
  50. STR_BLT* pStrBlt)
  51. {
  52. BYTE* pjSrc;
  53. ULONG xAccum;
  54. ULONG xTmp;
  55. LONG xDst = pStrBlt->XDstStart;
  56. LONG xSrc = pStrBlt->XSrcStart;
  57. BYTE* pjSrcScan = pStrBlt->pjSrcScan + xSrc;
  58. BYTE* pjDst = pStrBlt->pjDstScan + xDst;
  59. LONG yCount = pStrBlt->YDstCount;
  60. LONG WidthX = pStrBlt->XDstEnd - xDst;
  61. ULONG xInt = pStrBlt->ulXDstToSrcIntCeil;
  62. ULONG xFrac = pStrBlt->ulXDstToSrcFracCeil;
  63. ULONG yAccum = pStrBlt->ulYFracAccumulator;
  64. ULONG yFrac = pStrBlt->ulYDstToSrcFracCeil;
  65. LONG lDstStride = pStrBlt->lDeltaDst - WidthX;
  66. ULONG yInt = 0;
  67. yInt = pStrBlt->lDeltaSrc * pStrBlt->ulYDstToSrcIntCeil;
  68. //
  69. // Narrow blt
  70. //
  71. do {
  72. ULONG yTmp = yAccum + yFrac;
  73. BYTE jSrc0;
  74. BYTE* pjDstEndNarrow = pjDst + WidthX;
  75. pjSrc = pjSrcScan;
  76. xAccum = pStrBlt->ulXFracAccumulator;
  77. do {
  78. jSrc0 = *pjSrc;
  79. xTmp = xAccum + xFrac;
  80. pjSrc = pjSrc + xInt + (xTmp < xAccum);
  81. *pjDst++ = jSrc0;
  82. xAccum = xTmp;
  83. } while (pjDst != pjDstEndNarrow);
  84. pjSrcScan += yInt;
  85. if (yTmp < yAccum)
  86. {
  87. pjSrcScan += pStrBlt->lDeltaSrc;
  88. }
  89. yAccum = yTmp;
  90. pjDst += lDstStride;
  91. } while (--yCount);
  92. }
  93. /******************************Public*Routine******************************\
  94. *
  95. * Routine Description:
  96. *
  97. * StretchBlt using integer math. Must be from one surface to another
  98. * surface of the same format.
  99. *
  100. * Arguments:
  101. *
  102. * ppdev - PDEV for device
  103. * pvDst - Pointer to start of dst bitmap
  104. * lDeltaDst - Bytes from start of dst scan line to start of next
  105. * DstCx - Width of Dst Bitmap in pixels
  106. * DstCy - Height of Dst Bitmap in pixels
  107. * prclDst - Pointer to rectangle of Dst extents
  108. * pvSrc - Pointer to start of Src bitmap
  109. * lDeltaSrc - Bytes from start of Src scan line to start of next
  110. * SrcCx - Width of Src Bitmap in pixels
  111. * SrcCy - Height of Src Bitmap in pixels
  112. * prclSrc - Pointer to rectangle of Src extents
  113. * prclSClip - Clip Dest to this rect
  114. *
  115. * Return Value:
  116. *
  117. * Status
  118. *
  119. \**************************************************************************/
  120. BOOL bStretchDIB(
  121. PDEV* ppdev,
  122. VOID* pvDst,
  123. LONG lDeltaDst,
  124. RECTL* prclDst,
  125. VOID* pvSrc,
  126. LONG lDeltaSrc,
  127. RECTL* prclSrc,
  128. RECTL* prclClip)
  129. {
  130. STR_BLT StrBlt;
  131. ULONG ulXDstToSrcIntCeil;
  132. ULONG ulXDstToSrcFracCeil;
  133. ULONG ulYDstToSrcIntCeil;
  134. ULONG ulYDstToSrcFracCeil;
  135. ULONG ulXFracAccumulator;
  136. ULONG ulYFracAccumulator;
  137. LONG LeftClipDistance;
  138. LONG TopClipDistance;
  139. BOOL bStretch;
  140. union {
  141. LARGE_INTEGER large;
  142. ULONGLONG li;
  143. } liInit;
  144. PFN_DIRSTRETCH pfnStr;
  145. //
  146. // Calculate exclusive start and end points:
  147. //
  148. LONG WidthDst = prclDst->right - prclDst->left;
  149. LONG HeightDst = prclDst->bottom - prclDst->top;
  150. LONG WidthSrc = prclSrc->right - prclSrc->left;
  151. LONG HeightSrc = prclSrc->bottom - prclSrc->top;
  152. LONG XSrcStart = prclSrc->left;
  153. LONG XSrcEnd = prclSrc->right;
  154. LONG XDstStart = prclDst->left;
  155. LONG XDstEnd = prclDst->right;
  156. LONG YSrcStart = prclSrc->top;
  157. LONG YSrcEnd = prclSrc->bottom;
  158. LONG YDstStart = prclDst->top;
  159. LONG YDstEnd = prclDst->bottom;
  160. //
  161. // Validate parameters:
  162. //
  163. ASSERTDD(pvDst != (VOID*)NULL, "Bad destination bitmap pointer");
  164. ASSERTDD(pvSrc != (VOID*)NULL, "Bad source bitmap pointer");
  165. ASSERTDD(prclDst != (RECTL*)NULL, "Bad destination rectangle");
  166. ASSERTDD(prclSrc != (RECTL*)NULL, "Bad source rectangle");
  167. ASSERTDD((WidthDst > 0) && (HeightDst > 0) &&
  168. (WidthSrc > 0) && (HeightSrc > 0),
  169. "Can't do mirroring or empty rectangles here");
  170. ASSERTDD((WidthDst <= STRETCH_MAX_EXTENT) &&
  171. (HeightDst <= STRETCH_MAX_EXTENT) &&
  172. (WidthSrc <= STRETCH_MAX_EXTENT) &&
  173. (HeightSrc <= STRETCH_MAX_EXTENT), "Stretch exceeds limits");
  174. ASSERTDD(prclClip != NULL, "Bad clip rectangle");
  175. //
  176. // Calculate X Dst to Src mapping
  177. //
  178. //
  179. // dst->src = ( CEIL( (2k*WidthSrc)/WidthDst) ) / 2k
  180. //
  181. // = ( FLOOR( (2k*WidthSrc -1) / WidthDst) + 1) / 2k
  182. //
  183. // where 2k = 2 ^ 32
  184. //
  185. {
  186. ULONGLONG liWidthSrc;
  187. ULONGLONG liQuo;
  188. ULONG ulTemp;
  189. //
  190. // Work around a compiler bug dealing with the assignment
  191. // 'liHeightSrc = (((LONGLONG)HeightSrc) << 32) - 1':
  192. //
  193. liInit.large.LowPart = (ULONG) -1;
  194. liInit.large.HighPart = WidthSrc - 1;
  195. liWidthSrc = liInit.li;
  196. liQuo = liWidthSrc / (ULONGLONG) WidthDst;
  197. ulXDstToSrcIntCeil = (ULONG)(liQuo >> 32);
  198. ulXDstToSrcFracCeil = (ULONG)liQuo;
  199. //
  200. // Now add 1, use fake carry:
  201. //
  202. ulTemp = ulXDstToSrcFracCeil + 1;
  203. ulXDstToSrcIntCeil += (ulTemp < ulXDstToSrcFracCeil);
  204. ulXDstToSrcFracCeil = ulTemp;
  205. }
  206. //
  207. // Calculate Y Dst to Src mapping
  208. //
  209. //
  210. // dst->src = ( CEIL( (2k*HeightSrc)/HeightDst) ) / 2k
  211. //
  212. // = ( FLOOR( (2k*HeightSrc -1) / HeightDst) + 1) / 2k
  213. //
  214. // where 2k = 2 ^ 32
  215. //
  216. {
  217. ULONGLONG liHeightSrc;
  218. ULONGLONG liQuo;
  219. ULONG ulTemp;
  220. //
  221. // Work around a compiler bug dealing with the assignment
  222. // 'liHeightSrc = (((LONGLONG)HeightSrc) << 32) - 1':
  223. //
  224. liInit.large.LowPart = (ULONG) -1;
  225. liInit.large.HighPart = HeightSrc - 1;
  226. liHeightSrc = liInit.li;
  227. liQuo = liHeightSrc / (ULONGLONG) HeightDst;
  228. ulYDstToSrcIntCeil = (ULONG)(liQuo >> 32);
  229. ulYDstToSrcFracCeil = (ULONG)liQuo;
  230. //
  231. // Now add 1, use fake carry:
  232. //
  233. ulTemp = ulYDstToSrcFracCeil + 1;
  234. ulYDstToSrcIntCeil += (ulTemp < ulYDstToSrcFracCeil);
  235. ulYDstToSrcFracCeil = ulTemp;
  236. }
  237. //
  238. // Now clip Dst in X, and/or calc src clipping effect on dst
  239. //
  240. // adjust left and right edges if needed, record
  241. // distance adjusted for fixing the src
  242. //
  243. if (XDstStart < prclClip->left)
  244. {
  245. XDstStart = prclClip->left;
  246. }
  247. if (XDstEnd > prclClip->right)
  248. {
  249. XDstEnd = prclClip->right;
  250. }
  251. //
  252. // Check for totally clipped out destination:
  253. //
  254. if (XDstEnd <= XDstStart)
  255. {
  256. return(TRUE);
  257. }
  258. LeftClipDistance = XDstStart - prclDst->left;
  259. {
  260. ULONG ulTempInt;
  261. ULONG ulTempFrac;
  262. //
  263. // Calculate displacement for .5 in destination and add:
  264. //
  265. ulTempFrac = (ulXDstToSrcFracCeil >> 1) | (ulXDstToSrcIntCeil << 31);
  266. ulTempInt = (ulXDstToSrcIntCeil >> 1);
  267. XSrcStart += ulTempInt;
  268. ulXFracAccumulator = ulTempFrac;
  269. if (LeftClipDistance != 0)
  270. {
  271. ULONGLONG ullFraction;
  272. ULONG ulTmp;
  273. ullFraction = UInt32x32To64(ulXDstToSrcFracCeil, LeftClipDistance);
  274. ulTmp = ulXFracAccumulator;
  275. ulXFracAccumulator += (ULONG) (ullFraction);
  276. if (ulXFracAccumulator < ulTmp)
  277. XSrcStart++;
  278. XSrcStart += (ulXDstToSrcIntCeil * LeftClipDistance)
  279. + (ULONG) (ullFraction >> 32);
  280. }
  281. }
  282. //
  283. // Now clip Dst in Y, and/or calc src clipping effect on dst
  284. //
  285. // adjust top and bottom edges if needed, record
  286. // distance adjusted for fixing the src
  287. //
  288. if (YDstStart < prclClip->top)
  289. {
  290. YDstStart = prclClip->top;
  291. }
  292. if (YDstEnd > prclClip->bottom)
  293. {
  294. YDstEnd = prclClip->bottom;
  295. }
  296. //
  297. // Check for totally clipped out destination:
  298. //
  299. if (YDstEnd <= YDstStart)
  300. {
  301. return(TRUE);
  302. }
  303. TopClipDistance = YDstStart - prclDst->top;
  304. {
  305. ULONG ulTempInt;
  306. ULONG ulTempFrac;
  307. //
  308. // Calculate displacement for .5 in destination and add:
  309. //
  310. ulTempFrac = (ulYDstToSrcFracCeil >> 1) | (ulYDstToSrcIntCeil << 31);
  311. ulTempInt = ulYDstToSrcIntCeil >> 1;
  312. YSrcStart += (LONG)ulTempInt;
  313. ulYFracAccumulator = ulTempFrac;
  314. if (TopClipDistance != 0)
  315. {
  316. ULONGLONG ullFraction;
  317. ULONG ulTmp;
  318. ullFraction = UInt32x32To64(ulYDstToSrcFracCeil, TopClipDistance);
  319. ulTmp = ulYFracAccumulator;
  320. ulYFracAccumulator += (ULONG) (ullFraction);
  321. if (ulYFracAccumulator < ulTmp)
  322. YSrcStart++;
  323. YSrcStart += (ulYDstToSrcIntCeil * TopClipDistance)
  324. + (ULONG) (ullFraction >> 32);
  325. }
  326. }
  327. //
  328. // Warm up the hardware if doing an expanding stretch in 'y':
  329. //
  330. bStretch = (HeightDst > HeightSrc);
  331. if (bStretch)
  332. {
  333. //
  334. // Set up the info that is constant during the StretchBlt
  335. //
  336. ppdev->pfnBankSelectMode(ppdev, BANK_ON);
  337. //
  338. // BankSelectMode(BANK_ON) guarentees that the last
  339. // blt is completed. We don't need to wait.
  340. //
  341. if (ppdev->flCaps & CAPS_MM_IO)
  342. {
  343. BYTE* pjBase = ppdev->pjBase;
  344. CP_MM_BLT_MODE(ppdev, pjBase, 0); // GR30
  345. CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY); // GR32
  346. CP_MM_SRC_Y_OFFSET(ppdev, pjBase, lDeltaDst); // GR26, GR27
  347. CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDeltaDst); // GR24, GR25
  348. }
  349. else
  350. {
  351. BYTE* pjPorts = ppdev->pjPorts;
  352. CP_IO_BLT_MODE(ppdev, pjPorts, 0);
  353. CP_IO_ROP(ppdev, pjPorts, CL_SRC_COPY);
  354. CP_IO_SRC_Y_OFFSET(ppdev, pjPorts, lDeltaDst);
  355. CP_IO_DST_Y_OFFSET(ppdev, pjPorts, lDeltaDst);
  356. }
  357. }
  358. //
  359. // Fill out blt structure, then call format-specific stretch code
  360. //
  361. StrBlt.ppdev = ppdev;
  362. StrBlt.XDstEnd = XDstEnd;
  363. StrBlt.YDstStart = YDstStart;
  364. StrBlt.YDstCount = YDstEnd - YDstStart;
  365. if (StrBlt.YDstCount > 0)
  366. {
  367. //
  368. // Caclulate starting scan line address. Since the inner loop
  369. // routines are format dependent, they must add XDstStart/XSrcStart
  370. // to pjDstScan/pjSrcScan to get the actual starting pixel address.
  371. //
  372. StrBlt.pjSrcScan = (BYTE*) pvSrc + (YSrcStart * lDeltaSrc);
  373. StrBlt.pjDstScan = (BYTE*) pvDst + (YDstStart * lDeltaDst);
  374. StrBlt.lDeltaSrc = lDeltaSrc;
  375. StrBlt.XSrcStart = XSrcStart;
  376. StrBlt.XDstStart = XDstStart;
  377. StrBlt.lDeltaDst = lDeltaDst;
  378. StrBlt.ulXDstToSrcIntCeil = ulXDstToSrcIntCeil;
  379. StrBlt.ulXDstToSrcFracCeil = ulXDstToSrcFracCeil;
  380. StrBlt.ulYDstToSrcIntCeil = ulYDstToSrcIntCeil;
  381. StrBlt.ulYDstToSrcFracCeil = ulYDstToSrcFracCeil;
  382. StrBlt.ulXFracAccumulator = ulXFracAccumulator;
  383. StrBlt.ulYFracAccumulator = ulYFracAccumulator;
  384. // chu01
  385. if ((ppdev->flCaps & CAPS_COMMAND_LIST) && (ppdev->pCommandList != NULL))
  386. {
  387. if (ppdev->iBitmapFormat == BMF_8BPP)
  388. {
  389. if ((XDstEnd - XDstStart) < 7)
  390. pfnStr = vDirectStretch8Narrow;
  391. else
  392. pfnStr = vDirectStretch8_80;
  393. }
  394. else if (ppdev->iBitmapFormat == BMF_16BPP)
  395. {
  396. pfnStr = vDirectStretch16_80;
  397. }
  398. else
  399. {
  400. ASSERTDD(ppdev->iBitmapFormat == BMF_24BPP,
  401. "Only handle stretches at 8/16/24bpp");
  402. pfnStr = vDirectStretch24_80;
  403. }
  404. }
  405. else
  406. {
  407. if (ppdev->iBitmapFormat == BMF_8BPP)
  408. {
  409. if ((XDstEnd - XDstStart) < 7)
  410. pfnStr = vDirectStretch8Narrow;
  411. else
  412. pfnStr = vDirectStretch8;
  413. }
  414. else if (ppdev->iBitmapFormat == BMF_16BPP)
  415. {
  416. pfnStr = vDirectStretch16;
  417. }
  418. else
  419. {
  420. ASSERTDD(ppdev->iBitmapFormat == BMF_24BPP,
  421. "Only handle stretches at 8/16/24bpp");
  422. pfnStr = vDirectStretch24;
  423. }
  424. }
  425. (*pfnStr)(&StrBlt);
  426. }
  427. return(TRUE);
  428. }
  429. /******************************Public*Routine******************************\
  430. * BOOL bBankedStretch
  431. *
  432. \**************************************************************************/
  433. BOOL bBankedStretch(
  434. PDEV* ppdev,
  435. VOID* pvDst,
  436. LONG lDeltaDst,
  437. RECTL* prclDst,
  438. VOID* pvSrc,
  439. LONG lDeltaSrc,
  440. RECTL* prclSrc,
  441. RECTL* prclClip)
  442. {
  443. BANK bnk;
  444. BOOL b;
  445. RECTL rclDst;
  446. b = TRUE;
  447. if (bIntersect(prclDst, prclClip, &rclDst))
  448. {
  449. vBankStart(ppdev, &rclDst, NULL, &bnk);
  450. do {
  451. b &= bStretchDIB(ppdev,
  452. bnk.pso->pvScan0,
  453. lDeltaDst,
  454. prclDst,
  455. pvSrc,
  456. lDeltaSrc,
  457. prclSrc,
  458. &bnk.pco->rclBounds);
  459. } while (bBankEnum(&bnk));
  460. }
  461. return(b);
  462. }
  463. /******************************Public*Routine******************************\
  464. * BOOL DrvStretchBlt
  465. *
  466. \**************************************************************************/
  467. BOOL DrvStretchBlt(
  468. SURFOBJ* psoDst,
  469. SURFOBJ* psoSrc,
  470. SURFOBJ* psoMsk,
  471. CLIPOBJ* pco,
  472. XLATEOBJ* pxlo,
  473. COLORADJUSTMENT* pca,
  474. POINTL* pptlHTOrg,
  475. RECTL* prclDst,
  476. RECTL* prclSrc,
  477. POINTL* pptlMsk,
  478. ULONG iMode)
  479. {
  480. DSURF* pdsurfSrc;
  481. DSURF* pdsurfDst;
  482. PDEV* ppdev;
  483. OH* poh;
  484. // GDI guarantees us that for a StretchBlt the destination surface
  485. // will always be a device surface, and not a DIB:
  486. ppdev = (PDEV*) psoDst->dhpdev;
  487. if (!DIRECT_ACCESS(ppdev))
  488. {
  489. goto Punt_It;
  490. }
  491. // It's quicker for GDI to do a StretchBlt when the source surface
  492. // is not a device-managed surface, because then it can directly
  493. // read the source bits without having to allocate a temporary
  494. // buffer and call DrvCopyBits to get a copy that it can use.
  495. if (psoSrc->iType == STYPE_DEVBITMAP)
  496. {
  497. pdsurfSrc = (DSURF*) psoSrc->dhsurf;
  498. if (pdsurfSrc->dt == DT_SCREEN)
  499. {
  500. goto Punt_It;
  501. }
  502. ASSERTDD(pdsurfSrc->dt == DT_DIB, "Can only handle DIB DFBs here");
  503. psoSrc = pdsurfSrc->pso;
  504. }
  505. pdsurfDst = (DSURF*) psoDst->dhsurf;
  506. if (pdsurfDst->dt == DT_DIB)
  507. {
  508. // The destination was a device bitmap that we just converted
  509. // to a DIB:
  510. psoDst = pdsurfDst->pso;
  511. goto Punt_It;
  512. }
  513. poh = pdsurfDst->poh;
  514. ppdev->xOffset = poh->x;
  515. ppdev->yOffset = poh->y;
  516. ppdev->xyOffset = poh->xy;
  517. {
  518. RECTL rclClip;
  519. RECTL* prclClip;
  520. ULONG cxDst;
  521. ULONG cyDst;
  522. ULONG cxSrc;
  523. ULONG cySrc;
  524. BOOL bMore;
  525. CLIPENUM ce;
  526. LONG c;
  527. LONG i;
  528. if ((psoSrc->iType == STYPE_BITMAP) &&
  529. (psoMsk == NULL) &&
  530. ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) &&
  531. ((psoSrc->iBitmapFormat == ppdev->iBitmapFormat)) &&
  532. (ppdev->iBitmapFormat <= BMF_24BPP))
  533. {
  534. cxDst = prclDst->right - prclDst->left;
  535. cyDst = prclDst->bottom - prclDst->top;
  536. cxSrc = prclSrc->right - prclSrc->left;
  537. cySrc = prclSrc->bottom - prclSrc->top;
  538. // Our 'bStretchDIB' routine requires that the stretch be
  539. // non-inverting, within a certain size, to have no source
  540. // clipping, and to have no empty rectangles (the latter is the
  541. // reason for the '- 1' on the unsigned compare here):
  542. if (((cxSrc - 1) < STRETCH_MAX_EXTENT) &&
  543. ((cySrc - 1) < STRETCH_MAX_EXTENT) &&
  544. ((cxDst - 1) < STRETCH_MAX_EXTENT) &&
  545. ((cyDst - 1) < STRETCH_MAX_EXTENT) &&
  546. (prclSrc->left >= 0) &&
  547. (prclSrc->top >= 0) &&
  548. (prclSrc->right <= psoSrc->sizlBitmap.cx) &&
  549. (prclSrc->bottom <= psoSrc->sizlBitmap.cy))
  550. {
  551. // Our snazzy routine only does COLORONCOLOR. But for
  552. // stretching blts, BLACKONWHITE and WHITEONBLACK are also
  553. // equivalent to COLORONCOLOR:
  554. if ((iMode == COLORONCOLOR) ||
  555. ((iMode < COLORONCOLOR) && (cxSrc <= cxDst) && (cySrc <= cyDst)))
  556. {
  557. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  558. {
  559. rclClip.left = LONG_MIN;
  560. rclClip.top = LONG_MIN;
  561. rclClip.right = LONG_MAX;
  562. rclClip.bottom = LONG_MAX;
  563. prclClip = &rclClip;
  564. StretchSingleClipRect:
  565. if (bBankedStretch(ppdev,
  566. NULL,
  567. ppdev->lDelta,
  568. prclDst,
  569. psoSrc->pvScan0,
  570. psoSrc->lDelta,
  571. prclSrc,
  572. prclClip))
  573. {
  574. return(TRUE);
  575. }
  576. }
  577. else if (pco->iDComplexity == DC_RECT)
  578. {
  579. prclClip = &pco->rclBounds;
  580. goto StretchSingleClipRect;
  581. }
  582. else
  583. {
  584. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  585. do {
  586. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  587. c = cIntersect(prclDst, ce.arcl, ce.c);
  588. if (c != 0)
  589. {
  590. for (i = 0; i < c; i++)
  591. {
  592. if (!bBankedStretch(ppdev,
  593. NULL,
  594. ppdev->lDelta,
  595. prclDst,
  596. psoSrc->pvScan0,
  597. psoSrc->lDelta,
  598. prclSrc,
  599. &ce.arcl[i]))
  600. {
  601. goto Punt_It;
  602. }
  603. }
  604. }
  605. } while (bMore);
  606. return(TRUE);
  607. }
  608. }
  609. }
  610. }
  611. }
  612. Punt_It:
  613. // GDI is nice enough to handle the cases where 'psoDst' and/or 'psoSrc'
  614. // are device-managed surfaces, but it ain't gonna be fast...
  615. return(EngStretchBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca, pptlHTOrg,
  616. prclDst, prclSrc, pptlMsk, iMode));
  617. }