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.

1081 lines
36 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: fillpath.c
  8. *
  9. * Content: DrvFillPath support
  10. *
  11. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  12. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
  13. \*****************************************************************************/
  14. //@@BEGIN_DDKSPLIT
  15. // LATER identify convex polygons and special-case?
  16. // LATER identify vertical edges and special-case?
  17. // LATER move pointed-to variables into automatics in search loops
  18. // LATER punt to the engine with segmented framebuffer callbacks
  19. // LATER handle complex clipping
  20. // LATER coalesce rectangles
  21. //@@END_DDKSPLIT
  22. #include "precomp.h"
  23. #include "glint.h"
  24. #define TAKING_ALLOC_STATS 0
  25. #define NUM_BUFFER_POINTS 96 // Maximum number of points in a path
  26. // for which we'll attempt to join
  27. // all the path records so that the
  28. // path may still be drawn by FastFill
  29. #if TAKING_ALLOC_STATS
  30. ULONG BufferHitInFillpath = 0;
  31. ULONG BufferMissInFillpath = 0;
  32. #endif
  33. // Describe a single non-horizontal edge of a path to fill.
  34. typedef struct _EDGE {
  35. PVOID pNext;
  36. INT iScansLeft;
  37. INT X;
  38. INT Y;
  39. INT iErrorTerm;
  40. INT iErrorAdjustUp;
  41. INT iErrorAdjustDown;
  42. INT iXWhole;
  43. INT iXDirection;
  44. INT iWindingDirection;
  45. } EDGE, *PEDGE;
  46. // Maximum number of rects we'll fill per call to
  47. // the fill code
  48. #define MAX_PATH_RECTS 50
  49. #define RECT_BYTES (MAX_PATH_RECTS * sizeof(RECTL))
  50. #define EDGE_BYTES (TMP_BUFFER_SIZE - RECT_BYTES)
  51. #define MAX_EDGES (EDGE_BYTES/sizeof(EDGE))
  52. VOID AdvanceAETEdges(EDGE *pAETHead);
  53. VOID XSortAETEdges(EDGE *pAETHead);
  54. VOID MoveNewEdges(EDGE *pGETHead, EDGE *pAETHead, INT iCurrentY);
  55. EDGE * AddEdgeToGET(EDGE *pGETHead, EDGE *pFreeEdge, POINTFIX *ppfxEdgeStart,
  56. POINTFIX *ppfxEdgeEnd, RECTL *pClipRect);
  57. BOOL ConstructGET(EDGE *pGETHead, EDGE *pFreeEdges, PATHOBJ *ppo,
  58. PATHDATA *pd, BOOL bMore, RECTL *pClipRect);
  59. void AdjustErrorTerm(INT *pErrorTerm, INT iErrorAdjustUp, INT iErrorAdjustDown,
  60. INT yJump, INT *pXStart, INT iXDirection);
  61. /******************************Public*Routine******************************\
  62. * DrvFillPath
  63. *
  64. * Fill the specified path with the specified brush and ROP.
  65. *
  66. \**************************************************************************/
  67. BOOL DrvFillPath(
  68. SURFOBJ* pso,
  69. PATHOBJ* ppo,
  70. CLIPOBJ* pco,
  71. BRUSHOBJ* pbo,
  72. POINTL* pptlBrush,
  73. MIX mix,
  74. FLONG flOptions)
  75. {
  76. BYTE jClipping; // clipping type
  77. EDGE *pCurrentEdge;
  78. EDGE AETHead; // dummy head/tail node & sentinel for Active Edge Table
  79. EDGE *pAETHead; // pointer to AETHead
  80. EDGE GETHead; // dummy head/tail node & sentinel for Global Edge Table
  81. EDGE *pGETHead; // pointer to GETHead
  82. ULONG ulNumRects; // # of rectangles to draw currently in rectangle list
  83. RECTL *prclRects; // pointer to start of rectangle draw list
  84. INT iCurrentY; // scan line for which we're currently scanning out the
  85. // fill
  86. EDGE *pFreeEdges = NULL; // pointer to memory free for use to store edges
  87. RBRUSH_COLOR rbc; // Realized brush or solid color
  88. ULONG iSolidColor; // Copy of pbo->iSolidColor
  89. GFNFILL *pfnFill; // Points to appropriate fill routine
  90. BOOL bMore;
  91. PATHDATA pd;
  92. RECTL ClipRect;
  93. PDEV *ppdev = (PDEV*) pso->dhpdev;
  94. DSURF *pdsurf;
  95. BOOL bRetVal=FALSE; // FALSE until proven TRUE
  96. BOOL bMemAlloced=FALSE; // FALSE until proven TRUE
  97. FLONG flFirstRecord;
  98. POINTFIX* pptfxTmp;
  99. ULONG cptfxTmp;
  100. POINTFIX aptfxBuf[NUM_BUFFER_POINTS];
  101. ULONG logicop;
  102. ULONG bgLogicop;
  103. GLINT_DECL;
  104. DISPDBG((DBGLVL, "Entering Fill Path"));
  105. // Set up the clipping
  106. if (pco == (CLIPOBJ *) NULL)
  107. {
  108. // No CLIPOBJ provided, so we don't have to worry about clipping
  109. jClipping = DC_TRIVIAL;
  110. }
  111. else
  112. {
  113. // Use the CLIPOBJ-provided clipping
  114. jClipping = pco->iDComplexity;
  115. }
  116. // There's nothing to do if there are only one or two points
  117. if (ppo->cCurves <= 2)
  118. {
  119. goto ReturnTrue;
  120. }
  121. // Pass the surface off to GDI if it's a device bitmap that we've
  122. // converted to a DIB:
  123. pdsurf = (DSURF*) pso->dhsurf;
  124. if (pdsurf->dt & DT_DIB)
  125. {
  126. DISPDBG((DBGLVL, "Passing to GDI"));
  127. return(EngFillPath(pdsurf->pso, ppo, pco, pbo, pptlBrush, mix,
  128. flOptions));
  129. }
  130. REMOVE_SWPOINTER(pso);
  131. VALIDATE_DD_CONTEXT;
  132. // We'll be drawing to the screen or an off-screen DFB; copy the surface's
  133. // offset now so that we won't need to refer to the DSURF again:
  134. //@@BEGIN_DDKSPLIT
  135. #if 1
  136. //@@END_DDKSPLIT
  137. SETUP_PPDEV_OFFSETS(ppdev, pdsurf);
  138. //@@BEGIN_DDKSPLIT
  139. #else
  140. ppdev->DstPixelOrigin = pdsurf->poh->pixOffset;
  141. ppdev->xyOffsetDst = MAKEDWORD_XY( pdsurf->poh->x, pdsurf->poh->y );
  142. ppdev->xOffset = pdsurf->poh->x;
  143. #endif
  144. //@@END_DDKSPLIT
  145. // It is too difficult to determine interaction between
  146. // multiple paths, if there is more than one, skip this
  147. bMore = PATHOBJ_bEnum(ppo, &pd);
  148. pfnFill = ppdev->pgfnFillSolid;
  149. logicop = GlintLogicOpsFromR2[mix & 0xFF];
  150. bgLogicop = GlintLogicOpsFromR2[mix >> 8];
  151. iSolidColor = pbo->iSolidColor;
  152. rbc.iSolidColor = iSolidColor;
  153. if (rbc.iSolidColor == -1)
  154. {
  155. rbc.prb = pbo->pvRbrush;
  156. if (rbc.prb == NULL)
  157. {
  158. DISPDBG((DBGLVL, "Realizing brush"));
  159. rbc.prb = BRUSHOBJ_pvGetRbrush(pbo);
  160. if (rbc.prb == NULL)
  161. {
  162. return(FALSE);
  163. }
  164. DISPDBG((DBGLVL, "Realized brush"));
  165. }
  166. if (rbc.prb->fl & RBRUSH_2COLOR)
  167. {
  168. pfnFill = ppdev->pgfnFillPatMono;
  169. }
  170. else
  171. {
  172. pfnFill = ppdev->pgfnFillPatColor;
  173. }
  174. }
  175. if (bMore)
  176. {
  177. // FastFill only knows how to take a single contiguous buffer
  178. // of points. Unfortunately, GDI sometimes hands us paths
  179. // that are split over multiple path data records. Convex
  180. // figures such as Ellipses, Pies and RoundRects are almost
  181. // always given in multiple records. Since probably 90% of
  182. // multiple record paths could still be done by FastFill, for
  183. // those cases we simply copy the points into a contiguous
  184. // buffer...
  185. // First make sure that the entire path would fit in the
  186. // temporary buffer, and make sure the path isn't comprised
  187. // of more than one subpath:
  188. if ((ppo->cCurves >= NUM_BUFFER_POINTS) ||
  189. (pd.flags & PD_ENDSUBPATH))
  190. {
  191. goto SkipFastFill;
  192. }
  193. pptfxTmp = &aptfxBuf[0];
  194. RtlCopyMemory(pptfxTmp, pd.pptfx, sizeof(POINTFIX) * pd.count);
  195. pptfxTmp += pd.count;
  196. cptfxTmp = pd.count;
  197. flFirstRecord = pd.flags; // Remember PD_BEGINSUBPATH flag
  198. do {
  199. bMore = PATHOBJ_bEnum(ppo, &pd);
  200. RtlCopyMemory(pptfxTmp, pd.pptfx, sizeof(POINTFIX) * pd.count);
  201. cptfxTmp += pd.count;
  202. pptfxTmp += pd.count;
  203. } while (!(pd.flags & PD_ENDSUBPATH));
  204. // Fake up the path data record:
  205. pd.pptfx = &aptfxBuf[0];
  206. pd.count = cptfxTmp;
  207. pd.flags |= flFirstRecord;
  208. // If there's more than one subpath, we can't call FastFill:
  209. DISPDBG((DBGLVL, "More than one subpath!"));
  210. if (bMore)
  211. goto SkipFastFill;
  212. }
  213. if ((*ppdev->pgfnFillPolygon)(ppdev, pd.count, pd.pptfx, iSolidColor,
  214. logicop, bgLogicop, pco, rbc.prb, pptlBrush))
  215. {
  216. DISPDBG((DBGLVL, "Fast Fill Succeeded"));
  217. return(TRUE);
  218. }
  219. SkipFastFill:
  220. DISPDBG((DBGLVL, "Fast Fill Skipped"));
  221. if (jClipping != DC_TRIVIAL)
  222. {
  223. if (jClipping != DC_RECT)
  224. {
  225. DISPDBG((DBGLVL, "Complex Clipping"));
  226. goto ReturnFalse; // there is complex clipping; let GDI fill the path
  227. }
  228. // Clip to the clip rectangle
  229. ClipRect = pco->rclBounds;
  230. }
  231. else
  232. {
  233. // So the y-clipping code doesn't do any clipping
  234. // /16 so we don't blow the values out when we scale up to GIQ
  235. ClipRect.top = (LONG_MIN + 1) / 16; // +1 to avoid compiler problem
  236. ClipRect.bottom = LONG_MAX / 16;
  237. }
  238. // Set up working storage in the temporary buffer
  239. prclRects = (RECTL*) ppdev->pvTmpBuffer; // storage for list of rectangles to draw
  240. if (!bMore)
  241. {
  242. RECTL *rectangle;
  243. INT cPoints = pd.count;
  244. // The count can't be less than three, because we got all the edges
  245. // in this subpath, and above we checked that there were at least
  246. // three edges
  247. // If the count is four, check to see if the polygon is really a
  248. // rectangle since we can really speed that up. We'll also check for
  249. // five with the first and last points the same, because under Win 3.1,
  250. // it was required to close polygons
  251. if ((cPoints == 4) ||
  252. ((cPoints == 5) &&
  253. (pd.pptfx[0].x == pd.pptfx[4].x) &&
  254. (pd.pptfx[0].y == pd.pptfx[4].y))) {
  255. rectangle = prclRects;
  256. // We have to start somewhere so assume that most
  257. // applications specify the top left point first
  258. //
  259. // we want to check that the first two points are
  260. // either vertically or horizontally aligned. if
  261. // they are then we check that the last point [3]
  262. // is either horizontally or vertically aligned,
  263. // and finally that the 3rd point [2] is aligned
  264. // with both the first point and the last point.
  265. #define FIX_SHIFT 4L
  266. #define FIX_MASK (- (1 << FIX_SHIFT))
  267. rectangle->top = pd.pptfx[0].y - 1 & FIX_MASK;
  268. rectangle->left = pd.pptfx[0].x - 1 & FIX_MASK;
  269. rectangle->right = pd.pptfx[1].x - 1 & FIX_MASK;
  270. if (rectangle->left ^ rectangle->right)
  271. {
  272. if (rectangle->top ^ (pd.pptfx[1].y - 1 & FIX_MASK))
  273. goto not_rectangle;
  274. if (rectangle->left ^ (pd.pptfx[3].x - 1 & FIX_MASK))
  275. goto not_rectangle;
  276. if (rectangle->right ^ (pd.pptfx[2].x - 1 & FIX_MASK))
  277. goto not_rectangle;
  278. rectangle->bottom = pd.pptfx[2].y - 1 & FIX_MASK;
  279. if (rectangle->bottom ^ (pd.pptfx[3].y - 1 & FIX_MASK))
  280. goto not_rectangle;
  281. }
  282. else
  283. {
  284. if (rectangle->top ^ (pd.pptfx[3].y - 1 & FIX_MASK))
  285. goto not_rectangle;
  286. rectangle->bottom = pd.pptfx[1].y - 1 & FIX_MASK;
  287. if (rectangle->bottom ^ (pd.pptfx[2].y - 1 & FIX_MASK))
  288. goto not_rectangle;
  289. rectangle->right = pd.pptfx[2].x - 1 & FIX_MASK;
  290. if (rectangle->right ^ (pd.pptfx[3].x - 1 & FIX_MASK))
  291. goto not_rectangle;
  292. }
  293. // if the left is greater than the right then
  294. // swap them so the blt code doesn't wig out
  295. if (rectangle->left > rectangle->right)
  296. {
  297. FIX temp;
  298. temp = rectangle->left;
  299. rectangle->left = rectangle->right;
  300. rectangle->right = temp;
  301. }
  302. else
  303. {
  304. // if left == right there's nothing to draw
  305. if (rectangle->left == rectangle->right)
  306. {
  307. DISPDBG((DBGLVL, "Nothing to draw"));
  308. goto ReturnTrue;
  309. }
  310. }
  311. // shift the values to get pixel coordinates
  312. rectangle->left = (rectangle->left >> FIX_SHIFT) + 1;
  313. rectangle->right = (rectangle->right >> FIX_SHIFT) + 1;
  314. if (rectangle->top > rectangle->bottom)
  315. {
  316. FIX temp;
  317. temp = rectangle->top;
  318. rectangle->top = rectangle->bottom;
  319. rectangle->bottom = temp;
  320. }
  321. else
  322. {
  323. if (rectangle->top == rectangle->bottom)
  324. {
  325. DISPDBG((DBGLVL, "Nothing to draw"));
  326. goto ReturnTrue;
  327. }
  328. }
  329. // shift the values to get pixel coordinates
  330. rectangle->top = (rectangle->top >> FIX_SHIFT) + 1;
  331. rectangle->bottom = (rectangle->bottom >> FIX_SHIFT) + 1;
  332. // Finally, check for clipping
  333. if (jClipping == DC_RECT)
  334. {
  335. // Clip to the clip rectangle
  336. if (!bIntersect(rectangle, &ClipRect, rectangle))
  337. {
  338. // Totally clipped, nothing to do
  339. DISPDBG((DBGLVL, "Nothing to draw"));
  340. goto ReturnTrue;
  341. }
  342. }
  343. // if we get here then the polygon is a rectangle,
  344. // set count to 1 and goto bottom to draw it
  345. ulNumRects = 1;
  346. goto draw_remaining_rectangles;
  347. }
  348. not_rectangle:
  349. ;
  350. }
  351. // Do we have enough memory for all the edges?
  352. // LATER does cCurves include closure?
  353. if (ppo->cCurves > MAX_EDGES)
  354. {
  355. #if TAKING_ALLOC_STATS
  356. BufferMissInFillpath++;
  357. #endif
  358. //
  359. // try to allocate enough memory
  360. //
  361. pFreeEdges = (EDGE *) ENGALLOCMEM(FL_ZERO_MEMORY,
  362. (ppo->cCurves * sizeof(EDGE)),
  363. ALLOC_TAG_GDI(6));
  364. if (pFreeEdges == NULL)
  365. {
  366. DISPDBG((DBGLVL, "Too many edges"));
  367. goto ReturnFalse; // too many edges; let GDI fill the path
  368. }
  369. else
  370. {
  371. bMemAlloced = TRUE;
  372. }
  373. }
  374. else
  375. {
  376. #if TAKING_ALLOC_STATS
  377. BufferHitInFillpath++;
  378. #endif
  379. pFreeEdges = (EDGE*) ((BYTE*) ppdev->pvTmpBuffer + RECT_BYTES);
  380. // use our handy temporary buffer (it's big enough)
  381. }
  382. // Initialize an empty list of rectangles to fill
  383. ulNumRects = 0;
  384. // Enumerate the path edges and build a Global Edge Table (GET) from them
  385. // in YX-sorted order.
  386. pGETHead = &GETHead;
  387. if (!ConstructGET(pGETHead, pFreeEdges, ppo, &pd, bMore, &ClipRect))
  388. {
  389. DISPDBG((DBGLVL, "Outside Range"));
  390. goto ReturnFalse; // outside GDI's 2**27 range
  391. }
  392. // Create an empty AET with the head node also a tail sentinel
  393. pAETHead = &AETHead;
  394. AETHead.pNext = pAETHead; // mark that the AET is empty
  395. AETHead.X = 0x7FFFFFFF; // this is greater than any valid X value, so
  396. // searches will always terminate
  397. // Top scan of polygon is the top of the first edge we come to
  398. iCurrentY = ((EDGE *)GETHead.pNext)->Y;
  399. // Loop through all the scans in the polygon, adding edges from the GET to
  400. // the Active Edge Table (AET) as we come to their starts, and scanning out
  401. // the AET at each scan into a rectangle list. Each time it fills up, the
  402. // rectangle list is passed to the filling routine, and then once again at
  403. // the end if any rectangles remain undrawn. We continue so long as there
  404. // are edges to be scanned out
  405. while (1) {
  406. // Advance the edges in the AET one scan, discarding any that have
  407. // reached the end (if there are any edges in the AET)
  408. if (AETHead.pNext != pAETHead)
  409. {
  410. AdvanceAETEdges(pAETHead);
  411. }
  412. // If the AET is empty, done if the GET is empty, else jump ahead to
  413. // the next edge in the GET; if the AET isn't empty, re-sort the AET
  414. if (AETHead.pNext == pAETHead)
  415. {
  416. if (GETHead.pNext == pGETHead)
  417. {
  418. // Done if there are no edges in either the AET or the GET
  419. break;
  420. }
  421. // There are no edges in the AET, so jump ahead to the next edge in
  422. // the GET
  423. iCurrentY = ((EDGE *)GETHead.pNext)->Y;
  424. }
  425. else
  426. {
  427. // Re-sort the edges in the AET by X coordinate, if there are at
  428. // least two edges in the AET (there could be one edge if the
  429. // balancing edge hasn't yet been added from the GET)
  430. if (((EDGE *)AETHead.pNext)->pNext != pAETHead)
  431. {
  432. XSortAETEdges(pAETHead);
  433. }
  434. }
  435. // Move any new edges that start on this scan from the GET to the AET;
  436. // bother calling only if there's at least one edge to add
  437. if (((EDGE *)GETHead.pNext)->Y == iCurrentY)
  438. {
  439. MoveNewEdges(pGETHead, pAETHead, iCurrentY);
  440. }
  441. // Scan the AET into rectangles to fill (there's always at least one
  442. // edge pair in the AET)
  443. pCurrentEdge = AETHead.pNext; // point to the first edge
  444. do {
  445. INT iLeftEdge;
  446. // The left edge of any given edge pair is easy to find; it's just
  447. // wherever we happen to be currently
  448. iLeftEdge = pCurrentEdge->X;
  449. // Find the matching right edge according to the current fill rule
  450. if ((flOptions & FP_WINDINGMODE) != 0)
  451. {
  452. INT iWindingCount;
  453. // Do winding fill; scan across until we've found equal numbers
  454. // of up and down edges
  455. iWindingCount = pCurrentEdge->iWindingDirection;
  456. do {
  457. pCurrentEdge = pCurrentEdge->pNext;
  458. iWindingCount += pCurrentEdge->iWindingDirection;
  459. } while (iWindingCount != 0);
  460. }
  461. else
  462. {
  463. // Odd-even fill; the next edge is the matching right edge
  464. pCurrentEdge = pCurrentEdge->pNext;
  465. }
  466. // See if the resulting span encompasses at least one pixel, and
  467. // add it to the list of rectangles to draw if so
  468. if (iLeftEdge < pCurrentEdge->X)
  469. {
  470. // We've got an edge pair to add to the list to be filled; see
  471. // if there's room for one more rectangle
  472. if (ulNumRects >= MAX_PATH_RECTS)
  473. {
  474. // No more room; draw the rectangles in the list and reset
  475. // it to empty
  476. (*pfnFill)(ppdev, ulNumRects, prclRects, logicop, bgLogicop,
  477. rbc, pptlBrush);
  478. // Reset the list to empty
  479. ulNumRects = 0;
  480. }
  481. // Add the rectangle representing the current edge pair
  482. if (jClipping == DC_RECT)
  483. {
  484. // Clipped
  485. // Clip to left
  486. prclRects[ulNumRects].left = max(iLeftEdge, ClipRect.left);
  487. // Clip to right
  488. prclRects[ulNumRects].right =
  489. min(pCurrentEdge->X, ClipRect.right);
  490. // Draw only if not fully clipped
  491. if (prclRects[ulNumRects].left <
  492. prclRects[ulNumRects].right)
  493. {
  494. prclRects[ulNumRects].top = iCurrentY;
  495. prclRects[ulNumRects].bottom = iCurrentY+1;
  496. ulNumRects++;
  497. }
  498. }
  499. else
  500. {
  501. // Unclipped
  502. prclRects[ulNumRects].top = iCurrentY;
  503. prclRects[ulNumRects].bottom = iCurrentY+1;
  504. prclRects[ulNumRects].left = iLeftEdge;
  505. prclRects[ulNumRects].right = pCurrentEdge->X;
  506. ulNumRects++;
  507. }
  508. }
  509. } while ((pCurrentEdge = pCurrentEdge->pNext) != pAETHead);
  510. iCurrentY++; // next scan
  511. }
  512. // Draw the remaining rectangles, if there are any.
  513. draw_remaining_rectangles:
  514. if (ulNumRects > 0)
  515. {
  516. (*pfnFill)(ppdev, ulNumRects, prclRects, logicop, bgLogicop,
  517. rbc, pptlBrush);
  518. }
  519. ReturnTrue:
  520. DISPDBG((DBGLVL, "Drawn"));
  521. bRetVal = TRUE; // done successfully
  522. ReturnFalse:
  523. // bRetVal is originally false. If you jumped to ReturnFalse from somewhere,
  524. // then it will remain false, and be returned.
  525. if (bMemAlloced)
  526. {
  527. //
  528. // we did allocate memory, so release it
  529. //
  530. ENGFREEMEM(pFreeEdges);
  531. }
  532. DISPDBG((DBGLVL, "Returning %s", bRetVal ? "True" : "False"));
  533. return(bRetVal);
  534. }
  535. // Advance the edges in the AET to the next scan, dropping any for which we've
  536. // done all scans. Assumes there is at least one edge in the AET.
  537. VOID AdvanceAETEdges(EDGE *pAETHead)
  538. {
  539. EDGE *pLastEdge, *pCurrentEdge;
  540. pLastEdge = pAETHead;
  541. pCurrentEdge = pLastEdge->pNext;
  542. do {
  543. // Count down this edge's remaining scans
  544. if (--pCurrentEdge->iScansLeft == 0)
  545. {
  546. // We've done all scans for this edge; drop this edge from the AET
  547. pLastEdge->pNext = pCurrentEdge->pNext;
  548. }
  549. else
  550. {
  551. // Advance the edge's X coordinate for a 1-scan Y advance
  552. // Advance by the minimum amount
  553. pCurrentEdge->X += pCurrentEdge->iXWhole;
  554. // Advance the error term and see if we got one extra pixel this
  555. // time
  556. pCurrentEdge->iErrorTerm += pCurrentEdge->iErrorAdjustUp;
  557. if (pCurrentEdge->iErrorTerm >= 0)
  558. {
  559. // The error term turned over, so adjust the error term and
  560. // advance the extra pixel
  561. pCurrentEdge->iErrorTerm -= pCurrentEdge->iErrorAdjustDown;
  562. pCurrentEdge->X += pCurrentEdge->iXDirection;
  563. }
  564. pLastEdge = pCurrentEdge;
  565. }
  566. } while ((pCurrentEdge = pLastEdge->pNext) != pAETHead);
  567. }
  568. // X-sort the AET, because the edges may have moved around relative to
  569. // one another when we advanced them. We'll use a multipass bubble
  570. // sort, which is actually okay for this application because edges
  571. // rarely move relative to one another, so we usually do just one pass.
  572. // Also, this makes it easy to keep just a singly-linked list. Assumes there
  573. // are at least two edges in the AET.
  574. VOID XSortAETEdges(EDGE *pAETHead)
  575. {
  576. BOOL bEdgesSwapped;
  577. EDGE *pLastEdge, *pCurrentEdge, *pNextEdge;
  578. do {
  579. bEdgesSwapped = FALSE;
  580. pLastEdge = pAETHead;
  581. pCurrentEdge = pLastEdge->pNext;
  582. pNextEdge = pCurrentEdge->pNext;
  583. do {
  584. if (pNextEdge->X < pCurrentEdge->X)
  585. {
  586. // Next edge is to the left of the current edge; swap them
  587. pLastEdge->pNext = pNextEdge;
  588. pCurrentEdge->pNext = pNextEdge->pNext;
  589. pNextEdge->pNext = pCurrentEdge;
  590. bEdgesSwapped = TRUE;
  591. pCurrentEdge = pNextEdge; // continue sorting before the edge
  592. // we just swapped; it might move
  593. // farther yet
  594. }
  595. pLastEdge = pCurrentEdge;
  596. pCurrentEdge = pLastEdge->pNext;
  597. } while ((pNextEdge = pCurrentEdge->pNext) != pAETHead);
  598. } while (bEdgesSwapped);
  599. }
  600. // Moves all edges that start on the current scan from the GET to the AET in
  601. // X-sorted order. Parameters are pointer to head of GET and pointer to dummy
  602. // edge at head of AET, plus current scan line. Assumes there's at least one
  603. // edge to be moved.
  604. VOID MoveNewEdges(EDGE *pGETHead, EDGE *pAETHead, INT iCurrentY)
  605. {
  606. EDGE *pCurrentEdge = pAETHead;
  607. EDGE *pGETNext = pGETHead->pNext;
  608. do {
  609. // Scan through the AET until the X-sorted insertion point for this
  610. // edge is found. We can continue from where the last search left
  611. // off because the edges in the GET are in X sorted order, as is
  612. // the AET. The search always terminates because the AET sentinel
  613. // is greater than any valid X
  614. while (pGETNext->X > ((EDGE *)pCurrentEdge->pNext)->X)
  615. {
  616. pCurrentEdge = pCurrentEdge->pNext;
  617. }
  618. // We've found the insertion point; add the GET edge to the AET, and
  619. // remove it from the GET
  620. pGETHead->pNext = pGETNext->pNext;
  621. pGETNext->pNext = pCurrentEdge->pNext;
  622. pCurrentEdge->pNext = pGETNext;
  623. pCurrentEdge = pGETNext; // continue insertion search for the next
  624. // GET edge after the edge we just added
  625. pGETNext = pGETHead->pNext;
  626. } while (pGETNext->Y == iCurrentY);
  627. }
  628. // Build the Global Edge Table from the path. There must be enough memory in
  629. // the free edge area to hold all edges. The GET is constructed in Y-X order,
  630. // and has a head/tail/sentinel node at pGETHead.
  631. BOOL ConstructGET(
  632. EDGE *pGETHead,
  633. EDGE *pFreeEdges,
  634. PATHOBJ *ppo,
  635. PATHDATA *pd,
  636. BOOL bMore,
  637. RECTL *pClipRect)
  638. {
  639. POINTFIX pfxPathStart; // point that started the current subpath
  640. POINTFIX pfxPathPrevious; // point before the current point in a subpath;
  641. // starts the current edge
  642. // Create an empty GET with the head node also a tail sentinel
  643. pGETHead->pNext = pGETHead; // mark that the GET is empty
  644. pGETHead->Y = 0x7FFFFFFF; // this is greater than any valid Y value, so
  645. // searches will always terminate
  646. // PATHOBJ_vEnumStart is implicitly performed by engine
  647. // already and first path is enumerated by the caller.
  648. next_subpath:
  649. // Make sure the PATHDATA is not empty (is this necessary)
  650. if (pd->count != 0)
  651. {
  652. // If first point starts a subpath, remember it as such
  653. // and go on to the next point, so we can get an edge
  654. if (pd->flags & PD_BEGINSUBPATH)
  655. {
  656. // the first point starts the subpath; remember it
  657. pfxPathStart = *pd->pptfx; // the subpath starts here
  658. pfxPathPrevious = *pd->pptfx; // this points starts the next edge
  659. pd->pptfx++; // advance to the next point
  660. pd->count--; // count off this point
  661. }
  662. // Add edges in PATHDATA to GET, in Y-X sorted order
  663. while (pd->count--)
  664. {
  665. if ((pFreeEdges =
  666. AddEdgeToGET(pGETHead, pFreeEdges, &pfxPathPrevious, pd->pptfx,
  667. pClipRect)) == NULL)
  668. {
  669. goto ReturnFalse;
  670. }
  671. pfxPathPrevious = *pd->pptfx; // current point becomes previous
  672. pd->pptfx++; // advance to the next point
  673. }
  674. // If last point ends the subpath, insert the edge that
  675. // connects to first point (is this built in already?)
  676. if (pd->flags & PD_ENDSUBPATH)
  677. {
  678. if ((pFreeEdges = AddEdgeToGET(pGETHead, pFreeEdges, &pfxPathPrevious,
  679. &pfxPathStart, pClipRect)) == NULL)
  680. {
  681. goto ReturnFalse;
  682. }
  683. }
  684. }
  685. // The initial loop conditions preclude a do, while or for
  686. if (bMore)
  687. {
  688. bMore = PATHOBJ_bEnum(ppo, pd);
  689. goto next_subpath;
  690. }
  691. return(TRUE); // done successfully
  692. ReturnFalse:
  693. return(FALSE); // failed
  694. }
  695. // Adds the edge described by the two passed-in points to the Global Edge
  696. // Table, if the edge spans at least one pixel vertically.
  697. EDGE * AddEdgeToGET(EDGE *pGETHead, EDGE *pFreeEdge,
  698. POINTFIX *ppfxEdgeStart, POINTFIX *ppfxEdgeEnd, RECTL *pClipRect)
  699. {
  700. INT iYStart, iYEnd, iXStart, iXEnd, iYHeight, iXWidth;
  701. INT yJump, yTop;
  702. // Set the winding-rule direction of the edge, and put the endpoints in
  703. // top-to-bottom order
  704. iYHeight = ppfxEdgeEnd->y - ppfxEdgeStart->y;
  705. if (iYHeight == 0)
  706. {
  707. return(pFreeEdge); // zero height; ignore this edge
  708. }
  709. else if (iYHeight >= 0)
  710. {
  711. iXStart = ppfxEdgeStart->x;
  712. iYStart = ppfxEdgeStart->y;
  713. iXEnd = ppfxEdgeEnd->x;
  714. iYEnd = ppfxEdgeEnd->y;
  715. pFreeEdge->iWindingDirection = 1;
  716. }
  717. else
  718. {
  719. iYHeight = -iYHeight;
  720. iXEnd = ppfxEdgeStart->x;
  721. iYEnd = ppfxEdgeStart->y;
  722. iXStart = ppfxEdgeEnd->x;
  723. iYStart = ppfxEdgeEnd->y;
  724. pFreeEdge->iWindingDirection = -1;
  725. }
  726. if (iYHeight & 0x80000000)
  727. {
  728. return(NULL); // too large; outside 2**27 GDI range
  729. }
  730. // Set the error term and adjustment factors, all in GIQ coordinates for
  731. // now
  732. iXWidth = iXEnd - iXStart;
  733. if (iXWidth >= 0)
  734. {
  735. // Left to right, so we change X as soon as we move at all
  736. pFreeEdge->iXDirection = 1;
  737. pFreeEdge->iErrorTerm = -1;
  738. }
  739. else
  740. {
  741. // Right to left, so we don't change X until we've moved a full GIQ
  742. // coordinate
  743. iXWidth = -iXWidth;
  744. pFreeEdge->iXDirection = -1;
  745. pFreeEdge->iErrorTerm = -iYHeight;
  746. }
  747. if (iXWidth & 0x80000000)
  748. {
  749. return(NULL); // too large; outside 2**27 GDI range
  750. }
  751. if (iXWidth >= iYHeight)
  752. {
  753. // Calculate base run length (minimum distance advanced in X for a 1-
  754. // scan advance in Y)
  755. pFreeEdge->iXWhole = iXWidth / iYHeight;
  756. // Add sign back into base run length if going right to left
  757. if (pFreeEdge->iXDirection == -1)
  758. {
  759. pFreeEdge->iXWhole = -pFreeEdge->iXWhole;
  760. }
  761. pFreeEdge->iErrorAdjustUp = iXWidth % iYHeight;
  762. }
  763. else
  764. {
  765. // Base run length is 0, because line is closer to vertical than
  766. // horizontal
  767. pFreeEdge->iXWhole = 0;
  768. pFreeEdge->iErrorAdjustUp = iXWidth;
  769. }
  770. pFreeEdge->iErrorAdjustDown = iYHeight;
  771. // Calculate the number of pixels spanned by this edge, accounting for
  772. // clipping
  773. // Top true pixel scan in GIQ coordinates
  774. // Shifting to divide and multiply by 16 is okay because the clip rect
  775. // always contains positive numbers
  776. yTop = max(pClipRect->top << 4, (iYStart + 15) & ~0x0F);
  777. pFreeEdge->Y = yTop >> 4; // initial scan line on which to fill edge
  778. // Calculate # of scans to actually fill, accounting for clipping
  779. if ((pFreeEdge->iScansLeft = min(pClipRect->bottom, ((iYEnd + 15) >> 4))
  780. - pFreeEdge->Y) <= 0)
  781. {
  782. return(pFreeEdge); // no pixels at all are spanned, so we can
  783. // ignore this edge
  784. }
  785. // If the edge doesn't start on a pixel scan (that is, it starts at a
  786. // fractional GIQ coordinate), advance it to the first pixel scan it
  787. // intersects. Ditto if there's top clipping. Also clip to the bottom if
  788. // needed
  789. if (iYStart != yTop)
  790. {
  791. // Jump ahead by the Y distance in GIQ coordinates to the first pixel
  792. // to draw
  793. yJump = yTop - iYStart;
  794. // Advance x the minimum amount for the number of scans traversed
  795. iXStart += pFreeEdge->iXWhole * yJump;
  796. AdjustErrorTerm(&pFreeEdge->iErrorTerm, pFreeEdge->iErrorAdjustUp,
  797. pFreeEdge->iErrorAdjustDown, yJump, &iXStart,
  798. pFreeEdge->iXDirection);
  799. }
  800. // Turn the calculations into pixel rather than GIQ calculations
  801. // Move the X coordinate to the nearest pixel, and adjust the error term
  802. // accordingly
  803. // Dividing by 16 with a shift is okay because X is always positive
  804. pFreeEdge->X = (iXStart + 15) >> 4; // convert from GIQ to pixel coordinates
  805. //@@BEGIN_DDKSPLIT
  806. // LATER adjust only if needed (if prestepped above)?
  807. //@@END_DDKSPLIT
  808. if (pFreeEdge->iXDirection == 1)
  809. {
  810. // Left to right
  811. pFreeEdge->iErrorTerm -= pFreeEdge->iErrorAdjustDown *
  812. (((iXStart + 15) & ~0x0F) - iXStart);
  813. }
  814. else
  815. {
  816. // Right to left
  817. pFreeEdge->iErrorTerm -= pFreeEdge->iErrorAdjustDown *
  818. ((iXStart - 1) & 0x0F);
  819. }
  820. // Scale the error term down 16 times to switch from GIQ to pixels.
  821. // Shifts work to do the multiplying because these values are always
  822. // non-negative
  823. pFreeEdge->iErrorTerm >>= 4;
  824. // Insert the edge into the GET in YX-sorted order. The search always ends
  825. // because the GET has a sentinel with a greater-than-possible Y value
  826. while ((pFreeEdge->Y > ((EDGE *)pGETHead->pNext)->Y) ||
  827. ((pFreeEdge->Y == ((EDGE *)pGETHead->pNext)->Y) &&
  828. (pFreeEdge->X > ((EDGE *)pGETHead->pNext)->X)))
  829. {
  830. pGETHead = pGETHead->pNext;
  831. }
  832. pFreeEdge->pNext = pGETHead->pNext; // link the edge into the GET
  833. pGETHead->pNext = pFreeEdge;
  834. return(++pFreeEdge); // point to the next edge storage location for next
  835. // time
  836. }
  837. // Adjust the error term for a skip ahead in y. This is in ASM because there's
  838. // a multiply/divide that may involve a larger than 32-bit value.
  839. void AdjustErrorTerm(INT *pErrorTerm, INT iErrorAdjustUp, INT iErrorAdjustDown,
  840. INT yJump, INT *pXStart, INT iXDirection)
  841. {
  842. #if defined(_X86_) || defined(i386)
  843. // Adjust the error term up by the number of y coordinates we'll skip
  844. //*pErrorTerm += iErrorAdjustUp * yJump;
  845. _asm mov ebx,pErrorTerm
  846. _asm mov eax,iErrorAdjustUp
  847. _asm mul yJump
  848. _asm add eax,[ebx]
  849. _asm adc edx,-1 // the error term starts out negative
  850. // See if the error term turned over even once while skipping
  851. // if (*pErrorTerm >= 0) {
  852. _asm js short NoErrorTurnover
  853. // # of times we'll turn over the error term and step an extra x
  854. // coordinate while skipping
  855. // NumAdjustDowns = (*pErrorTerm / iErrorAdjustDown) + 1;
  856. _asm div iErrorAdjustDown
  857. _asm inc eax
  858. // Note that EDX is the remainder; (EDX - iErrorAdjustDown) is where
  859. // the error term ends up ultimately
  860. // Advance x appropriately for the # of times the error term
  861. // turned over
  862. // if (iXDirection == 1) {
  863. // *pXStart += NumAdjustDowns;
  864. // } else {
  865. // *pXStart -= NumAdjustDowns;
  866. // }
  867. _asm mov ecx,pXStart
  868. _asm cmp iXDirection,1
  869. _asm jz short GoingRight
  870. _asm neg eax
  871. GoingRight:
  872. _asm add [ecx],eax
  873. // Adjust the error term down to its proper post-skip value
  874. // *pErrorTerm -= iErrorAdjustDown * NumAdjustDowns;
  875. _asm sub edx,iErrorAdjustDown
  876. _asm mov eax,edx // put into EAX for storing to pErrorTerm next
  877. // }
  878. NoErrorTurnover:
  879. _asm mov [ebx],eax
  880. #else
  881. // LONGLONGS are 64 bit integers (We hope!) as the multiply could
  882. // overflow 32 bit integers. If 64 bit ints are unsupported, the
  883. // LONGLONG will end up as a double. Hopefully there will be no
  884. // noticable difference in accuracy.
  885. LONGLONG NumAdjustDowns;
  886. LONGLONG tmpError = *pErrorTerm;
  887. // Adjust the error term up by the number of y coordinates we'll skip
  888. tmpError += (LONGLONG)iErrorAdjustUp * (LONGLONG)yJump;
  889. // See if the error term turned over even once while skipping
  890. if (tmpError >= 0)
  891. {
  892. // # of times we'll turn over the error term and step an extra x
  893. // coordinate while skipping
  894. NumAdjustDowns = (tmpError / (LONGLONG)iErrorAdjustDown) + 1;
  895. // Advance x appropriately for the # of times the error term
  896. // turned over
  897. if (iXDirection == 1)
  898. {
  899. *pXStart += (LONG) NumAdjustDowns;
  900. }
  901. else
  902. {
  903. *pXStart -= (LONG) NumAdjustDowns;
  904. }
  905. // Adjust the error term down to its proper post-skip value
  906. tmpError -= (LONGLONG)iErrorAdjustDown * NumAdjustDowns;
  907. }
  908. *pErrorTerm = (LONG)tmpError;
  909. #endif // X86
  910. }