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.

1053 lines
38 KiB

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