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.

1426 lines
41 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: ffillddi.cxx
  3. *
  4. * routines for filling a polygon without building a region.
  5. *
  6. * Created: 12-Oct-1993 09:46:44
  7. * Author: Eric Kutter [erick]
  8. *
  9. * Copyright (c) 1993-1999 Microsoft Corporation
  10. *
  11. \**************************************************************************/
  12. #include "precomp.hxx"
  13. extern ULONG aulShiftFormat[];
  14. extern ULONG aulMulFormat[];
  15. typedef VOID (*PFN_FF)(PRECTL,ULONG,PVOID);
  16. typedef VOID (*PFN_FFROW)(LONG,PROW,ULONG,PVOID);
  17. PFN_PATBLT apfnPatRect[][3] =
  18. {
  19. { NULL, NULL, NULL },
  20. { NULL, NULL, NULL },
  21. { NULL, NULL, NULL },
  22. { vPatCpyRect8, vPatNotRect8, vPatXorRect8 },
  23. { vPatCpyRect8, vPatNotRect8, vPatXorRect8 },
  24. { vPatCpyRect8, vPatNotRect8, vPatXorRect8 },
  25. { vPatCpyRect8, vPatNotRect8, vPatXorRect8 }
  26. };
  27. PFN_PATBLTROW apfnPatRow[][3] =
  28. {
  29. { NULL, NULL, NULL },
  30. { NULL, NULL, NULL },
  31. { NULL, NULL, NULL },
  32. { vPatCpyRow8, vPatNotRow8, vPatXorRow8 },
  33. { vPatCpyRow8, vPatNotRow8, vPatXorRow8 },
  34. { vPatCpyRow8, vPatNotRow8, vPatXorRow8 },
  35. { vPatCpyRow8, vPatNotRow8, vPatXorRow8 }
  36. };
  37. BOOL bEngFastFillEnum(
  38. EPATHOBJ &epo,
  39. PRECTL prclClip,
  40. FLONG flOptions,
  41. PFN_FF pfn,
  42. PFN_FFROW pfnRow,
  43. PVOID pv);
  44. /******************************Public*Routine******************************\
  45. * vPaintPath
  46. *
  47. * fill a path - This dispatches through bEngFastFillEnum which calls
  48. * back to either vPaintPathEnum or vPaintPathEnumRow. vPaintPathEnum
  49. * takes a list of rectangles, vPaintPathEnumRow takes a list of rows.
  50. *
  51. * History:
  52. * 12-Oct-1993 -by- Eric Kutter [erick]
  53. * Wrote it.
  54. \**************************************************************************/
  55. typedef struct _PPAINT_PATH
  56. {
  57. PFN_SOLIDBLT pfn;
  58. PFN_SOLIDBLTROW pfnRow;
  59. LONG lDelta;
  60. ULONG cShift;
  61. ULONG iColor;
  62. PBYTE pjBits;
  63. } PAINT_PATH, *PPAINT_PATH;
  64. VOID vPaintPathEnum(
  65. PRECTL prcl,
  66. ULONG crcl,
  67. PVOID pv)
  68. {
  69. PPAINT_PATH ppp = (PPAINT_PATH)pv;
  70. (*ppp->pfn)(
  71. prcl,
  72. crcl,
  73. ppp->pjBits,
  74. ppp->lDelta,
  75. ppp->iColor,
  76. ppp->cShift);
  77. }
  78. VOID vPaintPathEnumRow(
  79. LONG yTop,
  80. PROW prow,
  81. ULONG cptl,
  82. PVOID pv)
  83. {
  84. PPAINT_PATH ppp = (PPAINT_PATH)pv;
  85. (*ppp->pfnRow)(prow,cptl,yTop,ppp->pjBits,ppp->iColor,ppp->lDelta,ppp->cShift);
  86. }
  87. BOOL bPaintPath(
  88. SURFACE *pSurf,
  89. PATHOBJ *ppo,
  90. PRECTL prclClip,
  91. ULONG iColor,
  92. BOOL bXor,
  93. FLONG flOptions)
  94. {
  95. PAINT_PATH pp;
  96. // Get the shift for the format
  97. pp.cShift = aulShiftFormat[pSurf->iFormat()];
  98. // Promote the color to 32 bits
  99. switch(pSurf->iFormat())
  100. {
  101. case BMF_1BPP:
  102. if (iColor)
  103. iColor = 0xFFFFFFFF;
  104. break;
  105. case BMF_4BPP:
  106. iColor = iColor | (iColor << 4);
  107. case BMF_8BPP:
  108. iColor = iColor | (iColor << 8);
  109. case BMF_16BPP:
  110. iColor = iColor | (iColor << 16);
  111. }
  112. if (bXor)
  113. if (pSurf->iFormat() == BMF_24BPP)
  114. {
  115. pp.pfn = vSolidXorRect24;
  116. pp.pfnRow = vSolidXorRow24;
  117. }
  118. else
  119. {
  120. pp.pfn = vSolidXorRect1;
  121. pp.pfnRow = vSolidXorRow1;
  122. }
  123. else
  124. if (pSurf->iFormat() == BMF_24BPP)
  125. {
  126. pp.pfn = vSolidFillRect24;
  127. pp.pfnRow = vSolidFillRow24;
  128. }
  129. else
  130. {
  131. pp.pfn = vSolidFillRect1;
  132. pp.pfnRow = vSolidFillRow1;
  133. }
  134. pp.pjBits = (PBYTE) pSurf->pvScan0();
  135. pp.iColor = iColor;
  136. pp.lDelta = pSurf->lDelta();
  137. return(bEngFastFillEnum(
  138. *(EPATHOBJ *)ppo,
  139. prclClip,
  140. flOptions,
  141. vPaintPathEnum,
  142. vPaintPathEnumRow,
  143. (PVOID)&pp));
  144. }
  145. /******************************Public*Routine******************************\
  146. * vBrushPath
  147. *
  148. * fill a path with a brush - This dispatches through bEngFastFillEnum which
  149. * calls back to either vBrushPathEnum or vBrushPathEnumRow. vBrushPathEnum
  150. * takes a list of rectangles, vBrushPathEnumRow takes a list of rows.
  151. *
  152. * History:
  153. * 12-Oct-1993 -by- Eric Kutter [erick]
  154. * Wrote it.
  155. \**************************************************************************/
  156. typedef struct _PBRUSH_PATH
  157. {
  158. PFN_PATBLT pfn;
  159. PFN_PATBLTROW pfnRow;
  160. PATBLTFRAME pbf;
  161. } BRUSH_PATH, *PBRUSH_PATH;
  162. VOID vBrushPathEnum(
  163. PRECTL prcl,
  164. ULONG crcl,
  165. PVOID pv)
  166. {
  167. PBRUSH_PATH pbp = (PBRUSH_PATH)pv;
  168. for (UINT i = 0; i < crcl; i++)
  169. {
  170. pbp->pbf.pvObj = (PVOID) prcl++;
  171. (*pbp->pfn)(&pbp->pbf);
  172. }
  173. }
  174. VOID vBrushPathEnumRow(
  175. LONG yTop,
  176. PROW prow,
  177. ULONG cptl,
  178. PVOID pv)
  179. {
  180. PBRUSH_PATH pbp = (PBRUSH_PATH)pv;
  181. pbp->pbf.pvObj = (PVOID) prow;
  182. (*pbp->pfnRow)(&pbp->pbf,yTop,(INT)cptl);
  183. }
  184. BOOL bBrushPath(
  185. SURFACE *pSurf,
  186. PATHOBJ *ppo,
  187. PRECTL prclClip,
  188. BRUSHOBJ *pbo,
  189. POINTL *pptl,
  190. ULONG iMode,
  191. FLONG flOptions)
  192. {
  193. BRUSH_PATH bp;
  194. // Get the multiplier for the format
  195. bp.pbf.cMul = aulMulFormat[pSurf->iFormat()];
  196. bp.pbf.pvTrg = pSurf->pvScan0();
  197. bp.pbf.lDeltaTrg = pSurf->lDelta();
  198. bp.pbf.pvPat = (PVOID) ((EBRUSHOBJ *) pbo)->pengbrush()->pjPat;
  199. bp.pbf.lDeltaPat = ((EBRUSHOBJ *) pbo)->pengbrush()->lDeltaPat;
  200. bp.pbf.cxPat = ((EBRUSHOBJ *) pbo)->pengbrush()->cxPat * bp.pbf.cMul;
  201. bp.pbf.cyPat = ((EBRUSHOBJ *) pbo)->pengbrush()->cyPat;
  202. bp.pbf.xPat = pptl->x * bp.pbf.cMul;
  203. bp.pbf.yPat = pptl->y;
  204. // Weird: The following code checks for xPat<0 and yPat<0, but it
  205. // doesn't check for xPat>=cxPat or yPat>=cyPat. Both cases are probably
  206. // handled lower down the call chain, but I can't be sure. So I've left the
  207. // code here (after correcting it).
  208. if (bp.pbf.xPat < 0)
  209. bp.pbf.xPat = bp.pbf.cxPat-1 - ((-bp.pbf.xPat - 1) % bp.pbf.cxPat);
  210. if (bp.pbf.yPat < 0)
  211. bp.pbf.yPat = bp.pbf.cyPat-1 - ((-bp.pbf.yPat - 1) % bp.pbf.cyPat);
  212. bp.pfn = apfnPatRect[pSurf->iFormat()][iMode];
  213. bp.pfnRow = apfnPatRow[pSurf->iFormat()][iMode];
  214. return(bEngFastFillEnum(
  215. *(EPATHOBJ *)ppo,
  216. prclClip,
  217. flOptions,
  218. vBrushPathEnum,
  219. vBrushPathEnumRow,
  220. (PVOID)&bp));
  221. }
  222. /******************************Public*Routine******************************\
  223. * vBrushPathN_8x8
  224. *
  225. * fill a path with a brush - This dispatches through bEngFastFillEnum which
  226. * calls back to either vBrushPathEnum or vBrushPathEnumRow. vBrushPathEnum
  227. * takes a list of rectangles, vBrushPathEnumRow takes a list of rows.
  228. *
  229. * History:
  230. * 12-Oct-1993 -by- Eric Kutter [erick]
  231. * Wrote it.
  232. \**************************************************************************/
  233. typedef struct _BRUSH_PATH_8x8
  234. {
  235. PFN_PATBLT2 pfn;
  236. PATBLTFRAME pbf;
  237. } BRUSH_PATH_8x8, *PBRUSH_PATH_8x8;
  238. VOID vBrushPath4_8x8Enum(
  239. PRECTL prcl,
  240. ULONG crcl,
  241. PVOID pv)
  242. {
  243. PBRUSH_PATH_8x8 pb8 = (PBRUSH_PATH_8x8)pv;
  244. pb8->pbf.pvObj = (PVOID) prcl;
  245. vPatCpyRect4_8x8(&pb8->pbf, (INT) crcl);
  246. }
  247. VOID vBrushPath8_8x8Enum(
  248. PRECTL prcl,
  249. ULONG crcl,
  250. PVOID pv)
  251. {
  252. PBRUSH_PATH_8x8 pb8 = (PBRUSH_PATH_8x8)pv;
  253. pb8->pbf.pvObj = (PVOID) prcl;
  254. vPatCpyRect8_8x8(&pb8->pbf, (INT) crcl);
  255. }
  256. VOID vBrushPath4_8x8EnumRow(
  257. LONG yTop,
  258. PROW prow,
  259. ULONG cptl,
  260. PVOID pv)
  261. {
  262. PBRUSH_PATH_8x8 pb8 = (PBRUSH_PATH_8x8)pv;
  263. pb8->pbf.pvObj = (PVOID) prow;
  264. vPatCpyRow4_8x8(&pb8->pbf, yTop,(INT) cptl);
  265. }
  266. VOID vBrushPath8_8x8EnumRow(
  267. LONG yTop,
  268. PROW prow,
  269. ULONG cptl,
  270. PVOID pv)
  271. {
  272. PBRUSH_PATH_8x8 pb8 = (PBRUSH_PATH_8x8)pv;
  273. pb8->pbf.pvObj = (PVOID) prow;
  274. vPatCpyRow8_8x8(&pb8->pbf, yTop,(INT) cptl);
  275. }
  276. BOOL bBrushPathN_8x8(
  277. SURFACE *pSurf,
  278. PATHOBJ *ppo,
  279. PRECTL prclClip,
  280. BRUSHOBJ *pbo,
  281. POINTL *pptlBrush,
  282. ULONG iFormat,
  283. FLONG flOptions)
  284. {
  285. BRUSH_PATH_8x8 b8;
  286. PFN_FF pfnFF = vBrushPath4_8x8Enum;
  287. PFN_FFROW pfnFFRow = vBrushPath4_8x8EnumRow;
  288. b8.pbf.pvTrg = pSurf->pvScan0();
  289. b8.pbf.lDeltaTrg = pSurf->lDelta();
  290. b8.pbf.pvPat = (PVOID) ((EBRUSHOBJ *) pbo)->pengbrush()->pjPat;
  291. // Force the X and Y pattern origin coordinates into the ranges 0-7 and 0-7,
  292. // so we don't have to do modulo arithmetic all over again at a lower level
  293. b8.pbf.xPat = pptlBrush->x & 0x07;
  294. b8.pbf.yPat = pptlBrush->y & 0x07;
  295. // if format ius 8BPP then use 8Bpp fill routines
  296. if (iFormat == BMF_8BPP) {
  297. pfnFF = vBrushPath8_8x8Enum;
  298. pfnFFRow = vBrushPath8_8x8EnumRow;
  299. }
  300. return(bEngFastFillEnum(
  301. *(EPATHOBJ *)ppo,
  302. prclClip,
  303. flOptions,
  304. pfnFF,
  305. pfnFFRow,
  306. (PVOID)&b8));
  307. }
  308. /******************************Public*Routine******************************\
  309. * EngFastFill()
  310. *
  311. * Fill a path clipped to at most one rectangle. If the fill is a mode
  312. * that this routine supports, the vBrushPath, bPaintPath, or vBrushPath_8x8
  313. * will be called. This routines setup a filling structure and call
  314. * the path enumeration code. The path enumeration code in turn, calls back
  315. * to a specific filling routine which fills either a list of rectangles
  316. * or a list of rows (left,right pairs). If it is a convex polygon with less
  317. * than 40 points, bFastFill is used, otherwise the slower bFill is used.
  318. *
  319. * returns:
  320. * -1 if unsupported mode for fastfill, should breakup into a region
  321. * true if the fill has been performed.
  322. * false an error occured
  323. *
  324. * History:
  325. * 12-Oct-1993 -by- Eric Kutter [erick]
  326. * Wrote it.
  327. \**************************************************************************/
  328. LONG EngFastFill(
  329. SURFOBJ *pso,
  330. PATHOBJ *ppo,
  331. PRECTL prcl,
  332. BRUSHOBJ *pdbrush,
  333. POINTL *pptlBrush,
  334. MIX mix,
  335. FLONG flOptions)
  336. {
  337. PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
  338. LONG lRes = -1;
  339. ROP4 rop4 = gaMix[(mix >> 8) & 0x0F];
  340. rop4 = rop4 << 8;
  341. rop4 = rop4 | ((ULONG) gaMix[mix & 0x0F]);
  342. if (pso->iType == STYPE_BITMAP)
  343. {
  344. switch (rop4)
  345. {
  346. case 0x0000: // Black
  347. lRes = (LONG)bPaintPath(pSurf, ppo,prcl, 0, FALSE,flOptions);
  348. break;
  349. case 0x0F0F: // Pn
  350. if (pdbrush->iSolidColor != 0xFFFFFFFF)
  351. {
  352. lRes = (LONG)bPaintPath(pSurf,ppo, prcl, ~pdbrush->iSolidColor, FALSE,flOptions);
  353. }
  354. else if (pSurf->iFormat() >= BMF_8BPP)
  355. {
  356. if (pvGetEngRbrush(pdbrush)) // Can we use this brush?
  357. {
  358. if (((EBRUSHOBJ *) pdbrush)->pengbrush()->cxPat >= 4)
  359. {
  360. lRes = (LONG)bBrushPath(pSurf, ppo,prcl, pdbrush, pptlBrush, DPA_PATNOT,flOptions);
  361. }
  362. }
  363. }
  364. break;
  365. case 0x5555: // Dn
  366. lRes = (LONG)bPaintPath(pSurf, ppo,prcl, (ULONG)~0, TRUE,flOptions);
  367. break;
  368. case 0x5A5A: // DPx
  369. if (pdbrush->iSolidColor != 0xFFFFFFFF)
  370. {
  371. lRes = (LONG)bPaintPath(pSurf, ppo,prcl, pdbrush->iSolidColor, TRUE,flOptions);
  372. }
  373. else if (pSurf->iFormat() >= BMF_8BPP)
  374. {
  375. if (pvGetEngRbrush(pdbrush)) // Can we use this brush?
  376. {
  377. if (((EBRUSHOBJ *) pdbrush)->pengbrush()->cxPat >= 4)
  378. {
  379. lRes = (LONG)bBrushPath(pSurf, ppo, prcl, pdbrush, pptlBrush, DPA_PATXOR,flOptions);
  380. }
  381. }
  382. }
  383. break;
  384. case 0xAAAA: // D
  385. lRes = TRUE;
  386. break;
  387. case 0xF0F0: // P
  388. if (pdbrush->iSolidColor != 0xFFFFFFFF)
  389. {
  390. lRes = (LONG)bPaintPath(pSurf, ppo,prcl, pdbrush->iSolidColor, FALSE,flOptions);
  391. }
  392. else if ( (pSurf->iFormat() == BMF_4BPP) ||
  393. (pSurf->iFormat() == BMF_8BPP) )
  394. {
  395. // We only support 8x8 DIB4 patterns with SRCCOPY right now
  396. if (pvGetEngRbrush(pdbrush) != NULL)
  397. {
  398. if ((((EBRUSHOBJ *) pdbrush)->pengbrush()->cxPat == 8) &&
  399. (((EBRUSHOBJ *) pdbrush)->pengbrush()->cyPat == 8))
  400. {
  401. lRes = (LONG)bBrushPathN_8x8(
  402. pSurf,
  403. ppo,
  404. prcl,
  405. pdbrush,
  406. pptlBrush,
  407. pSurf->iFormat(),
  408. flOptions
  409. );
  410. }
  411. }
  412. }
  413. else if (pSurf->iFormat() >= BMF_8BPP)
  414. {
  415. if (pvGetEngRbrush(pdbrush)) // Can we use this brush?
  416. {
  417. if (((EBRUSHOBJ *) pdbrush)->pengbrush()->cxPat >= 4)
  418. {
  419. lRes = (LONG)bBrushPath(pSurf, ppo,prcl, pdbrush, pptlBrush, DPA_PATCOPY, flOptions);
  420. }
  421. }
  422. }
  423. break;
  424. case 0xFFFF: // White
  425. lRes = (LONG)bPaintPath(pSurf, ppo,prcl, (ULONG)~0, FALSE,flOptions);
  426. break;
  427. }
  428. }
  429. return(lRes);
  430. }
  431. /******************************Public*Routine******************************\
  432. * bFastFill()
  433. *
  434. * Fills a convex polygon quickly. Calls pfnRow with lists of adjacent
  435. * rows, pfn if a verticle rectangle is found.
  436. *
  437. * returns:
  438. * true if it is a simple polygon and has been drawn
  439. * false if it is too complex.
  440. *
  441. * History:
  442. * 12-Oct-1993 -by- Eric Kutter [erick]
  443. * initial code stolen from s3 driver.
  444. \**************************************************************************/
  445. BOOL bMsg = FALSE;
  446. BOOL bFastFill(
  447. LONG cEdges, // Includes close figure edge
  448. POINTFIX* pptfxFirst,
  449. PRECTL prclClip,
  450. PFN_FF pfn,
  451. PFN_FFROW pfnRow,
  452. PVOID pv)
  453. {
  454. LONG cyTrapezoid; // Number of scans in current trapezoid
  455. LONG yStart; // y-position of start point in current edge
  456. LONG dM; // Edge delta in FIX units in x direction
  457. LONG dN; // Edge delta in FIX units in y direction
  458. LONG i;
  459. POINTFIX* pptfxLast; // Points to the last point in the polygon array
  460. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  461. POINTFIX* pptfxOld; // Start point in current edge
  462. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  463. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  464. // (doesn't include the closefigure edge)
  465. LONG lQuotient;
  466. LONG lRemainder;
  467. EDGEDATA aed[2]; // DDA terms and stuff
  468. EDGEDATA* ped;
  469. pptfxScan = pptfxFirst;
  470. pptfxTop = pptfxFirst; // Assume for now that the first
  471. // point in path is the topmost
  472. pptfxLast = pptfxFirst + cEdges - 1;
  473. LONG yCurrent;
  474. // 'pptfxScan' will always point to the first point in the current
  475. // edge, and 'cScanEdges' will the number of edges remaining, including
  476. // the current one:
  477. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  478. if ((pptfxScan + 1)->y > pptfxScan->y)
  479. {
  480. // Collect all downs:
  481. do {
  482. if (--cScanEdges == 0)
  483. goto SetUpForFilling;
  484. pptfxScan++;
  485. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  486. // Collect all ups:
  487. do {
  488. if (--cScanEdges == 0)
  489. goto SetUpForFillingCheck;
  490. pptfxScan++;
  491. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  492. // Collect all downs:
  493. pptfxTop = pptfxScan;
  494. do {
  495. if ((pptfxScan + 1)->y > pptfxFirst->y)
  496. break;
  497. if (--cScanEdges == 0)
  498. goto SetUpForFilling;
  499. pptfxScan++;
  500. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  501. return(FALSE);
  502. }
  503. else
  504. {
  505. // Collect all ups:
  506. do {
  507. pptfxTop++; // We increment this now because we
  508. // want it to point to the very last
  509. // point if we early out in the next
  510. // statement...
  511. if (--cScanEdges == 0)
  512. goto SetUpForFilling;
  513. } while ((pptfxTop + 1)->y <= pptfxTop->y);
  514. // Collect all downs:
  515. pptfxScan = pptfxTop;
  516. do {
  517. if (--cScanEdges == 0)
  518. goto SetUpForFilling;
  519. pptfxScan++;
  520. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  521. // Collect all ups:
  522. do {
  523. if ((pptfxScan + 1)->y < pptfxFirst->y)
  524. break;
  525. if (--cScanEdges == 0)
  526. goto SetUpForFilling;
  527. pptfxScan++;
  528. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  529. return(FALSE);
  530. }
  531. SetUpForFillingCheck:
  532. // We check to see if the end of the current edge is higher
  533. // than the top edge we've found so far:
  534. if ((pptfxScan + 1)->y < pptfxTop->y)
  535. pptfxTop = pptfxScan + 1;
  536. SetUpForFilling:
  537. // Make sure we initialize the DDAs appropriately:
  538. #define RIGHT 0
  539. #define LEFT 1
  540. aed[LEFT].cy = 0;
  541. aed[RIGHT].cy = 0;
  542. // For now, guess as to which is the left and which is the right edge:
  543. aed[LEFT].dptfx = -(LONG) sizeof(POINTFIX);
  544. aed[RIGHT].dptfx = sizeof(POINTFIX);
  545. aed[LEFT].pptfx = pptfxTop;
  546. aed[RIGHT].pptfx = pptfxTop;
  547. // setup the rectangles for enumeration
  548. #define MAXROW 40
  549. RECTL rclClip;
  550. ROW arow[MAXROW];
  551. PROW prow = arow;
  552. ULONG crow = 0;
  553. LONG yTop = 0;
  554. yCurrent = (pptfxTop->y + 15) >> 4;
  555. if (prclClip)
  556. {
  557. rclClip = *prclClip;
  558. if (rclClip.top > yCurrent)
  559. yCurrent = rclClip.top;
  560. if (yCurrent >= rclClip.bottom)
  561. return(TRUE);
  562. }
  563. else
  564. {
  565. rclClip.top = NEG_INFINITY;
  566. rclClip.bottom = POS_INFINITY;
  567. }
  568. // if there is clipping, remove all edges above rectangle
  569. if (prclClip)
  570. {
  571. for (LONG iEdge = 1; iEdge >= 0; iEdge--)
  572. {
  573. ped = &aed[iEdge];
  574. for (;;)
  575. {
  576. if (cEdges == 0)
  577. return(TRUE);
  578. // find the next edge
  579. POINTFIX *pptfxNew = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  580. if (pptfxNew < pptfxFirst)
  581. pptfxNew = pptfxLast;
  582. else if (pptfxNew > pptfxLast)
  583. pptfxNew = pptfxFirst;
  584. // we have found one that intersects the rect
  585. if ((pptfxNew->y >> 4) >= rclClip.top)
  586. break;
  587. // the bottom is outside the cliprect, throw it away and get the next
  588. cEdges--;
  589. ped->pptfx = pptfxNew;
  590. };
  591. }
  592. }
  593. // now do the real work. We must loop through all edges.
  594. NextEdge:
  595. // We loop through this routine on a per-trapezoid basis.
  596. for (LONG iEdge = 1; iEdge >= 0; iEdge--)
  597. {
  598. ped = &aed[iEdge];
  599. if (ped->cy == 0)
  600. {
  601. // Need a new DDA:
  602. do {
  603. cEdges--;
  604. if ((cEdges < 0) || (yCurrent >= rclClip.bottom))
  605. {
  606. // flush the batch
  607. if (crow > 0)
  608. (*pfnRow)(yTop,arow,crow,pv);
  609. return(TRUE);
  610. }
  611. // Find the next left edge, accounting for wrapping:
  612. pptfxOld = ped->pptfx;
  613. ped->pptfx = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  614. if (ped->pptfx < pptfxFirst)
  615. ped->pptfx = pptfxLast;
  616. else if (ped->pptfx > pptfxLast)
  617. ped->pptfx = pptfxFirst;
  618. // Have to find the edge that spans yCurrent:
  619. ped->cy = ((ped->pptfx->y + 15) >> 4) - yCurrent;
  620. // With fractional coordinate end points, we may get edges
  621. // that don't cross any scans, in which case we try the
  622. // next one:
  623. } while (ped->cy <= 0);
  624. // 'pptfx' now points to the end point of the edge spanning
  625. // the scan 'yCurrent'.
  626. dN = ped->pptfx->y - pptfxOld->y;
  627. dM = ped->pptfx->x - pptfxOld->x;
  628. ASSERTGDI(dN > 0, "Should be going down only");
  629. // Compute the DDA increment terms:
  630. if (dM < 0)
  631. {
  632. dM = -dM;
  633. if (dM < dN) // Can't be '<='
  634. {
  635. ped->dx = -1;
  636. ped->lErrorUp = dN - dM;
  637. }
  638. else
  639. {
  640. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  641. ped->dx = -lQuotient; // - dM / dN
  642. ped->lErrorUp = lRemainder; // dM % dN
  643. if (ped->lErrorUp > 0)
  644. {
  645. ped->dx--;
  646. ped->lErrorUp = dN - ped->lErrorUp;
  647. }
  648. }
  649. }
  650. else
  651. {
  652. if (dM < dN) // Can't be '<='
  653. {
  654. ped->dx = 0;
  655. ped->lErrorUp = dM;
  656. }
  657. else
  658. {
  659. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  660. ped->dx = lQuotient; // dM / dN
  661. ped->lErrorUp = lRemainder; // dM % dN
  662. }
  663. }
  664. ped->lErrorDown = dN; // DDA limit
  665. ped->lError = -1; // Error is initially zero (add dN - 1 for
  666. // the ceiling, but subtract off dN so that
  667. // we can check the sign instead of comparing
  668. // to dN)
  669. ped->x = pptfxOld->x;
  670. yStart = pptfxOld->y;
  671. if ((yStart & 15) != 0)
  672. {
  673. // Advance to the next integer y coordinate
  674. for (i = 16 - (yStart & 15); i > 0; i--)
  675. {
  676. ped->x += ped->dx;
  677. ped->lError += ped->lErrorUp;
  678. if (ped->lError >= 0)
  679. {
  680. ped->lError -= ped->lErrorDown;
  681. ped->x++;
  682. }
  683. }
  684. }
  685. if ((ped->x & 15) != 0)
  686. {
  687. ped->lError -= ped->lErrorDown * (16 - (ped->x & 15));
  688. ped->x += 15; // We'll want the ceiling in just a bit...
  689. }
  690. // Chop off those fractional bits:
  691. ped->x >>= 4;
  692. ped->lError >>= 4;
  693. // advance to the top
  694. yStart = (yStart + 15) >> 4;
  695. if (yStart < rclClip.top)
  696. {
  697. LONG yDelta = rclClip.top - yStart;
  698. // if x must change, advance to the x by the height of the trap
  699. if (((ped->pptfx->y >> 4) >= rclClip.top) ||
  700. ped->dx || ped->lErrorUp)
  701. {
  702. ped->x += ped->dx * yDelta;
  703. LONGLONG eqerr = Int32x32To64(ped->lErrorUp,yDelta);
  704. eqerr += (LONGLONG) ped->lError;
  705. if (eqerr >= 0)
  706. {
  707. // warning. This divide is extremely expensive
  708. // NTFIXED 269540 02-02-2000 pravins GDI-some long
  709. // wide geometric lines dont show up in dibsections
  710. // We now shift eqerr by 31 bits to the right to see if
  711. // the it cannot be just cast as a LONG.
  712. if (eqerr >> 31)
  713. {
  714. // Cannot cast eqerr as a LONG
  715. ULONG ulRemainder;
  716. eqerr = DIVREM(eqerr,ped->lErrorDown,&ulRemainder);
  717. ped->lError = ulRemainder - ped->lErrorDown;
  718. ped->x += (LONG)eqerr + 1;
  719. }
  720. else
  721. {
  722. // Can cast eqerr as a LONG.
  723. ped->x += (LONG) eqerr / ped->lErrorDown + 1;
  724. ped->lError = (LONG) eqerr % ped->lErrorDown - ped->lErrorDown;
  725. }
  726. }
  727. else
  728. ped->lError = (LONG) eqerr;
  729. }
  730. #if DBG
  731. if (bMsg)
  732. {
  733. DbgPrint("x = %ld, e = %ld, eU = %ld, eD = %ld, cy = %ld, yD = %ld\n",
  734. ped->x,ped->lError,ped->lErrorUp, ped->lErrorDown,ped->cy,yDelta);
  735. DbgPrint("ptfxold.y = 0x%lx, ptfx.y = 0x%lx, yStart = %ld, yCurrent = %ld\n",
  736. pptfxOld->y,ped->pptfx->y,yStart,yCurrent);
  737. }
  738. #endif
  739. }
  740. }
  741. }
  742. cyTrapezoid = min(aed[LEFT].cy, aed[RIGHT].cy); // # of scans in this trap
  743. aed[LEFT].cy -= cyTrapezoid;
  744. aed[RIGHT].cy -= cyTrapezoid;
  745. // make sure we never go off the bottom
  746. if ((yCurrent + cyTrapezoid) > rclClip.bottom)
  747. cyTrapezoid = rclClip.bottom - yCurrent;
  748. // If the left and right edges are vertical, simply output as a rectangle:
  749. if (((aed[LEFT].lErrorUp | aed[RIGHT].lErrorUp) == 0) &&
  750. ((aed[LEFT].dx | aed[RIGHT].dx) == 0) &&
  751. (cyTrapezoid > 2))
  752. {
  753. // must flush any existing rows since rows must be contiguous
  754. if (crow)
  755. {
  756. (*pfnRow)(yTop,arow,crow,pv);
  757. prow = arow;
  758. crow = 0;
  759. }
  760. LONG xL = aed[LEFT].x;
  761. LONG xR = aed[RIGHT].x;
  762. if (xL != xR)
  763. {
  764. if (xL > xR)
  765. {
  766. LONG l = xL;
  767. xL = xR;
  768. xR = l;
  769. }
  770. // check if we are clipped
  771. RECTL rcl;
  772. rcl.top = yCurrent;
  773. rcl.bottom = yCurrent+cyTrapezoid;
  774. if (prclClip)
  775. {
  776. rcl.left = (xL >= rclClip.left) ? xL : rclClip.left;
  777. rcl.right = (xR <= rclClip.right) ? xR : rclClip.right;
  778. if (rcl.left < rcl.right)
  779. (*pfn)(&rcl,1,pv);
  780. }
  781. else
  782. {
  783. rcl.left = xL;
  784. rcl.right = xR;
  785. (*pfn)(&rcl,1,pv);
  786. }
  787. }
  788. yCurrent += cyTrapezoid;
  789. // done with the current trapezoid
  790. goto NextEdge;
  791. }
  792. // make sure we reset yTop when necessary
  793. if (crow == 0)
  794. yTop = yCurrent;
  795. // now run the dda, anytime a row is empty, we need to flush the batch
  796. while (TRUE)
  797. {
  798. LONG lWidth = aed[RIGHT].x - aed[LEFT].x;
  799. if (lWidth > 0)
  800. {
  801. // handle the unclipped case quickly
  802. if (!prclClip)
  803. {
  804. prow->left = aed[LEFT].x;
  805. prow->right = aed[RIGHT].x;
  806. ++crow;
  807. ++prow;
  808. CheckForFlush:
  809. if (crow == MAXROW)
  810. {
  811. // flush the batch
  812. (*pfnRow)(yTop,arow,crow,pv);
  813. prow = arow;
  814. crow = 0;
  815. yTop = yCurrent + 1;
  816. }
  817. ContinueAfterZero:
  818. // Advance the right wall:
  819. aed[RIGHT].x += aed[RIGHT].dx;
  820. aed[RIGHT].lError += aed[RIGHT].lErrorUp;
  821. if (aed[RIGHT].lError >= 0)
  822. {
  823. aed[RIGHT].lError -= aed[RIGHT].lErrorDown;
  824. aed[RIGHT].x++;
  825. }
  826. // Advance the left wall:
  827. aed[LEFT].x += aed[LEFT].dx;
  828. aed[LEFT].lError += aed[LEFT].lErrorUp;
  829. if (aed[LEFT].lError >= 0)
  830. {
  831. aed[LEFT].lError -= aed[LEFT].lErrorDown;
  832. aed[LEFT].x++;
  833. }
  834. cyTrapezoid--;
  835. ++yCurrent;
  836. if (cyTrapezoid == 0)
  837. goto NextEdge;
  838. continue;
  839. }
  840. else
  841. {
  842. // we are clipped. Need to do some real work
  843. prow->left = (aed[LEFT].x >= rclClip.left) ? aed[LEFT].x : rclClip.left;
  844. prow->right = (aed[RIGHT].x <= rclClip.right) ? aed[RIGHT].x : rclClip.right;
  845. if (prow->left < prow->right)
  846. {
  847. ++crow;
  848. ++prow;
  849. goto CheckForFlush;
  850. }
  851. else
  852. {
  853. // NULL scan - we must flush the batch
  854. if (crow)
  855. {
  856. (*pfnRow)(yTop,arow,crow,pv);
  857. prow = arow;
  858. crow = 0;
  859. }
  860. yTop = yCurrent+1;
  861. // check if we are donewith this trapezoid,
  862. // if the trap is fully left or fully right
  863. if (((aed[LEFT].x < rclClip.left) &&
  864. ((aed[LEFT].pptfx->x >> 4) < rclClip.left) &&
  865. ((aed[RIGHT].pptfx->x >> 4) < rclClip.left)) ||
  866. ((aed[LEFT].x >= rclClip.right) &&
  867. ((aed[LEFT].pptfx->x >> 4) >= rclClip.right) &&
  868. ((aed[RIGHT].pptfx->x >> 4) >= rclClip.right)))
  869. {
  870. yCurrent += cyTrapezoid;
  871. goto NextEdge;
  872. }
  873. goto ContinueAfterZero;
  874. }
  875. }
  876. }
  877. else if (lWidth == 0)
  878. {
  879. // NULL scan - we must flush the batch
  880. if (crow)
  881. {
  882. (*pfnRow)(yTop,arow,crow,pv);
  883. prow = arow;
  884. crow = 0;
  885. }
  886. yTop = yCurrent + 1;
  887. goto ContinueAfterZero;
  888. }
  889. else
  890. {
  891. #define SWAP(a, b, tmp) { tmp = a; a = b; b = tmp; }
  892. // We certainly don't want to optimize for this case because we
  893. // should rarely get self-intersecting polygons (if we're slow,
  894. // the app gets what it deserves):
  895. EDGEDATA edTmp;
  896. SWAP(aed[LEFT],aed[RIGHT],edTmp);
  897. continue;
  898. }
  899. }
  900. }
  901. /******************************Public*Routine******************************\
  902. * bFill()
  903. *
  904. * Fill a path the slow way. This handles arbitrary paths, builds up a list
  905. * of rectangles, and calls pfn.
  906. *
  907. * This code is very similar to RGNMEMOBJ::vCreate.
  908. *
  909. * History:
  910. * 07-Oct-1993 -by- Eric Kutter [erick]
  911. * Wrote it.
  912. \**************************************************************************/
  913. BOOL bFill(
  914. EPATHOBJ& po,
  915. PRECTL prclClip,
  916. FLONG flOptions, // ALTERNATE or WINDING
  917. PFN_FF pfn,
  918. PVOID pv)
  919. {
  920. EDGE AETHead; // dummy head/tail node & sentinel for Active Edge Table
  921. EDGE *pAETHead; // pointer to AETHead
  922. EDGE GETHead; // dummy head/tail node & sentinel for Global Edge Table
  923. EDGE *pGETHead; // pointer to GETHead
  924. EDGE aEdge[MAX_POINTS];
  925. // Allocate memory for edge storage.
  926. BOOL bAlloc;
  927. EDGE *pFreeEdges; // pointer to memory free for use to store edges
  928. if (po.cCurves <= MAX_POINTS)
  929. {
  930. pFreeEdges = &aEdge[0];
  931. bAlloc = FALSE;
  932. }
  933. else
  934. {
  935. pFreeEdges = (PEDGE)PALLOCNOZ(sizeof(EDGE) * po.cCurves,'gdeG');
  936. if (pFreeEdges == (PEDGE)NULL)
  937. return(FALSE);
  938. bAlloc = TRUE;
  939. }
  940. // setup the rectangles for enumeration
  941. #define MAXRECT 20
  942. RECTL arcl[MAXRECT];
  943. PRECTL prcl = arcl;
  944. ULONG crcl = 0;
  945. RECTL rclClip;
  946. RECTL rclBounds,*prclBounds;
  947. if (prclClip)
  948. {
  949. rclClip = *prclClip;
  950. // we'll pass this to vConstructGET which will clip edges to the top and
  951. // bottom of the clip rect
  952. rclBounds.top = prclClip->top << 4; //we need GIQ coordinats
  953. rclBounds.bottom = prclClip->bottom << 4;
  954. prclBounds = &rclBounds;
  955. }
  956. else
  957. {
  958. rclClip.top = NEG_INFINITY;
  959. rclClip.bottom = POS_INFINITY;
  960. prclBounds = NULL;
  961. }
  962. // Construct the global edge list.
  963. pGETHead = &GETHead;
  964. vConstructGET(po, pGETHead, pFreeEdges,prclBounds); // bad line coordinates or
  965. LONG yTop = NEG_INFINITY; // scan line for which we're currently scanning
  966. // Create an empty AET with the head node also a tail sentinel
  967. pAETHead = &AETHead;
  968. AETHead.pNext = pAETHead; // mark that the AET is empty
  969. AETHead.Y = 0; // used as a count for number of edges in AET
  970. AETHead.X = 0x7FFFFFFF; // this is greater than any valid X value, so
  971. // searches will always terminate
  972. // Loop through all the scans in the polygon, adding edges from the GET to
  973. // the Active Edge Table (AET) as we come to their starts, and scanning out
  974. // the AET at each scan into a rectangle list. Each time it fills up, the
  975. // rectangle list is passed to the filling routine, and then once again at
  976. // the end if any rectangles remain undrawn. We continue so long as there
  977. // are edges to be scanned out.
  978. while ( 1 )
  979. {
  980. // Advance the edges in the AET one scan, discarding any that have
  981. // reached the end (if there are any edges in the AET)
  982. if (AETHead.pNext != pAETHead)
  983. vAdvanceAETEdges(pAETHead);
  984. // If the AET is empty, done if the GET is empty, else jump ahead to
  985. // the next edge in the GET; if the AET isn't empty, re-sort the AET
  986. if (AETHead.pNext == pAETHead)
  987. {
  988. // Done if there are no edges in either the AET or the GET
  989. if (GETHead.pNext == pGETHead)
  990. break;
  991. // There are no edges in the AET, so jump ahead to the next edge in
  992. // the GET.
  993. yTop = ((EDGE *)GETHead.pNext)->Y;
  994. }
  995. else
  996. {
  997. // Re-sort the edges in the AET by X coordinate, if there are at
  998. // least two edges in the AET (there could be one edge if the
  999. // balancing edge hasn't yet been added from the GET)
  1000. if (((EDGE *)AETHead.pNext)->pNext != pAETHead)
  1001. vXSortAETEdges(pAETHead);
  1002. }
  1003. // Move any new edges that start on this scan from the GET to the AET;
  1004. // bother calling only if there's at least one edge to add
  1005. if (((EDGE *)GETHead.pNext)->Y == yTop)
  1006. vMoveNewEdges(pGETHead, pAETHead, yTop);
  1007. // Scan the AET into region scans (there's always at least one
  1008. // edge pair in the AET)
  1009. EDGE *pCurrentEdge = AETHead.pNext; // point to the first edge
  1010. do {
  1011. // The left edge of any given edge pair is easy to find; it's just
  1012. // wherever we happen to be currently
  1013. LONG iLeftEdge = (int)pCurrentEdge->X;
  1014. // Find the matching right edge according to the current fill rule
  1015. if ((flOptions & FP_WINDINGMODE) != 0)
  1016. {
  1017. LONG lWindingCount;
  1018. // Do winding fill; scan across until we've found equal numbers
  1019. // of up and down edges
  1020. lWindingCount = pCurrentEdge->lWindingDirection;
  1021. do {
  1022. pCurrentEdge = pCurrentEdge->pNext;
  1023. lWindingCount += pCurrentEdge->lWindingDirection;
  1024. } while (lWindingCount != 0);
  1025. }
  1026. else
  1027. {
  1028. // Odd-even fill; the next edge is the matching right edge
  1029. pCurrentEdge = pCurrentEdge->pNext;
  1030. }
  1031. // See if the resulting span encompasses at least one pixel, and
  1032. // add it to the list of rectangles to draw if so
  1033. if (iLeftEdge < pCurrentEdge->X)
  1034. {
  1035. // Add the rectangle representing the current edge pair
  1036. if (prclClip)
  1037. {
  1038. prcl->left = (iLeftEdge >= rclClip.left) ? iLeftEdge : rclClip.left;
  1039. prcl->right = (pCurrentEdge->X <= rclClip.right) ? pCurrentEdge->X : rclClip.right;;
  1040. prcl->top = yTop;
  1041. prcl->bottom = yTop+1;
  1042. if (prcl->left < prcl->right)
  1043. {
  1044. ++crcl;
  1045. ++prcl;
  1046. }
  1047. }
  1048. else
  1049. {
  1050. prcl->left = iLeftEdge;
  1051. prcl->right = pCurrentEdge->X;
  1052. prcl->top = yTop;
  1053. prcl->bottom = yTop+1;
  1054. ++crcl;
  1055. ++prcl;
  1056. }
  1057. if (crcl == MAXRECT)
  1058. {
  1059. // flush the batch
  1060. (*pfn)(arcl,crcl,pv);
  1061. prcl = arcl;
  1062. crcl = 0;
  1063. }
  1064. }
  1065. } while ((pCurrentEdge = pCurrentEdge->pNext) != pAETHead);
  1066. yTop++; // next scan
  1067. }
  1068. // flush the final batch
  1069. if (crcl > 0)
  1070. (*pfn)(arcl,crcl,pv);
  1071. if (bAlloc)
  1072. VFREEMEM(pFreeEdges);
  1073. return(TRUE);
  1074. }
  1075. /******************************Member*Function*****************************\
  1076. * bEngFastFillEnum()
  1077. *
  1078. * fill in the path. If the path only has one sub path and fewer than 40
  1079. * points, try bFastFill. If we can't use bFastFill, do it the slow way
  1080. * through bFill().
  1081. *
  1082. * History:
  1083. * 27-Sep-1993 -by- Eric Kutter [erick]
  1084. * Wrote it.
  1085. \**************************************************************************/
  1086. #define QUICKPOINTS 40
  1087. BOOL bEngFastFillEnum(
  1088. EPATHOBJ &epo,
  1089. PRECTL prclClip,
  1090. FLONG flOptions,
  1091. PFN_FF pfn,
  1092. PFN_FFROW pfnRow,
  1093. PVOID pv)
  1094. {
  1095. PATHDATA pd;
  1096. BOOL bRes = FALSE;
  1097. // check if there is anything to do
  1098. if (epo.cCurves < 2)
  1099. return(TRUE);
  1100. // see if we can do it through fastfill
  1101. epo.vEnumStart();
  1102. if (epo.bEnum(&pd))
  1103. {
  1104. // if this ends the sub path, that means there is more than one sub path.
  1105. // also don't handle if we can't copy points onto stack
  1106. if (!(pd.flags & PD_ENDSUBPATH) && (epo.cCurves <= QUICKPOINTS))
  1107. {
  1108. POINTFIX aptfx[QUICKPOINTS];
  1109. LONG cPoints;
  1110. BOOL bMore;
  1111. RtlCopyMemory(aptfx,pd.pptfx,(SIZE_T)pd.count*sizeof(POINTFIX));
  1112. cPoints = pd.count;
  1113. do {
  1114. bMore = epo.bEnum(&pd);
  1115. if (pd.flags & PD_BEGINSUBPATH)
  1116. {
  1117. cPoints = 0;
  1118. break;
  1119. }
  1120. RtlCopyMemory(aptfx+cPoints,pd.pptfx,(SIZE_T)pd.count*sizeof(POINTFIX));
  1121. cPoints += pd.count;
  1122. } while(bMore);
  1123. ASSERTGDI(cPoints <= QUICKPOINTS,"bFastFillWrapper - too many points\n");
  1124. if (cPoints)
  1125. bRes = bFastFill(cPoints,aptfx,prclClip,pfn,pfnRow,pv);
  1126. }
  1127. }
  1128. else if (pd.count > 1)
  1129. {
  1130. bRes = bFastFill(pd.count,pd.pptfx,prclClip,pfn,pfnRow,pv);
  1131. }
  1132. else
  1133. {
  1134. bRes = TRUE;
  1135. }
  1136. // did we succeed with fast fill?
  1137. if (bRes == FALSE)
  1138. {
  1139. bRes = bFill(epo,prclClip,flOptions,pfn,pv);
  1140. }
  1141. return(bRes);
  1142. }