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.

1380 lines
50 KiB

  1. /******************************************************************************\
  2. *
  3. * $Workfile: FILLPATH.C $
  4. *
  5. * Contains the DrvFillPath routine.
  6. *
  7. * Copyright (c) 1992-1995 Microsoft Corporation
  8. * Copyright (c) 1996 Cirrus Logic, Inc.
  9. *
  10. * $Log: X:/log/laguna/nt35/displays/cl546x/FILLPATH.C $
  11. *
  12. * Rev 1.14 Mar 04 1998 15:24:00 frido
  13. * Added new shadow macros.
  14. *
  15. * Rev 1.13 Nov 03 1997 15:26:36 frido
  16. * Added REQUIRE macros.
  17. *
  18. * Rev 1.12 08 Apr 1997 12:24:28 einkauf
  19. *
  20. * add SYNC_W_3D to coordinate MCD/2D HW access
  21. *
  22. * Rev 1.11 21 Mar 1997 11:41:44 noelv
  23. *
  24. * Combined do_flag and sw_test_flag into point_switch
  25. *
  26. * Rev 1.10 17 Dec 1996 17:04:26 SueS
  27. * Added test for writing to log file based on cursor at (0,0). Added
  28. * more information to the log file.
  29. *
  30. * Rev 1.9 26 Nov 1996 10:46:10 noelv
  31. * Changed DBG LEVEL.
  32. *
  33. * Rev 1.8 26 Nov 1996 10:24:10 SueS
  34. * Changed WriteLogFile parameters for buffering.
  35. *
  36. * Rev 1.7 13 Nov 1996 15:58:52 SueS
  37. * Changed WriteFile calls to WriteLogFile.
  38. *
  39. * Rev 1.6 06 Sep 1996 14:46:24 noelv
  40. *
  41. * Updated NULL driver code for 4.0
  42. *
  43. * Rev 1.5 20 Aug 1996 11:03:32 noelv
  44. * Bugfix release from Frido 8-19-96
  45. *
  46. * Rev 1.2 17 Aug 1996 15:32:30 frido
  47. * #1244 - Fixed brush rotation for off-screen bitmaps.
  48. * Added new comment header.
  49. * Cleaned up some code.
  50. *
  51. \******************************************************************************/
  52. #include "precomp.h"
  53. BOOL CacheMono(PPDEV ppdev, PRBRUSH pRbrush);
  54. BOOL Cache4BPP(PPDEV ppdev, PRBRUSH pRbrush);
  55. BOOL CacheDither(PPDEV ppdev, PRBRUSH pRbrush);
  56. BOOL CacheBrush(PPDEV ppdev, PRBRUSH pRbrush);
  57. // We have to be careful of arithmetic overflow in a number of places.
  58. // Fortunately, the compiler is guaranteed to natively support 64-bit signed
  59. // LONGLONGs and 64-bit unsigned DWORDLONGs.
  60. //
  61. // Int32x32To64(a, b) is a macro defined in 'winnt.h' that multiplies two
  62. // 32-bit LONGs to produce a 64-bit LONGLONG result. I use it because it is
  63. // much faster than 64x64 multiplies.
  64. #define UInt64Div32To32(a, b) \
  65. ((((DWORDLONG)(a)) > ULONG_MAX) ? \
  66. (ULONG)((DWORDLONG)(a) / (ULONG)(b)) : \
  67. (ULONG)((ULONG)(a) / (ULONG)(b)))
  68. #define TAKING_ALLOC_STATS 0
  69. #define NUM_BUFFER_POINTS 96 // Maximum number of points in a path for
  70. // which we'll attempt to join all the path
  71. // records so that the path may still be
  72. // drawn by FastFill
  73. #if TAKING_ALLOC_STATS
  74. ULONG BufferHitInFillpath = 0;
  75. ULONG BufferMissInFillpath = 0;
  76. #endif
  77. #if LOG_CALLS
  78. VOID LogFillPath(ULONG acc, PPDEV ppdev, SURFOBJ* pso);
  79. #else
  80. #define LogFillPath(acc, ppdev, pso)
  81. #endif
  82. // Describe a single non-horizontal edge of a path to fill.
  83. typedef struct _EDGE {
  84. PVOID pNext;
  85. INT iScansLeft;
  86. INT X;
  87. INT Y;
  88. INT iErrorTerm;
  89. INT iErrorAdjustUp;
  90. INT iErrorAdjustDown;
  91. INT iXWhole;
  92. INT iXDirection;
  93. INT iWindingDirection;
  94. } EDGE, *PEDGE;
  95. // Maximum number of rects we'll fill per call to the fill code.
  96. #define MAX_PATH_RECTS 50
  97. #define RECT_BYTES (MAX_PATH_RECTS * sizeof(RECTL))
  98. #define EDGE_BYTES (TMP_BUFFER_SIZE - RECT_BYTES)
  99. #define MAX_EDGES (EDGE_BYTES/sizeof(EDGE))
  100. #define FILLPATH_DBG_LEVEL 1
  101. // MIX translation table. Translates a mix 1-16, into an old style ROP 0-255.
  102. extern BYTE gaMix[];
  103. VOID AdvanceAETEdges(EDGE* pAETHead);
  104. VOID XSortAETEdges(EDGE* pAETHead);
  105. VOID MoveNewEdges(EDGE* pGETHead, EDGE* pAETHead, INT iCurrentY);
  106. EDGE* AddEdgeToGET(EDGE* pGETHead, EDGE* pFreeEdge, POINTFIX* ppfxEdgeStart,
  107. POINTFIX* ppfxEdgeEnd, RECTL* pClipRect);
  108. BOOL ConstructGET(EDGE* pGETHead, EDGE* pFreeEdges, PATHOBJ* ppo,
  109. PATHDATA* pd, BOOL bMore, RECTL* pClipRect);
  110. VOID AdjustErrorTerm(INT* pErrorTerm, INT iErrorAdjustUp,
  111. INT iErrorAdjustDown, INT yJump, INT* pXStart,
  112. INT iXDirection);
  113. extern BYTE Rop2ToRop3[];
  114. BYTE gajRop[] =
  115. {
  116. 0x00, 0xff, 0xb2, 0x4d, 0xd4, 0x2b, 0x66, 0x99,
  117. 0x90, 0x6f, 0x22, 0xdd, 0x44, 0xbb, 0xf6, 0x09,
  118. 0xe8, 0x17, 0x5a, 0xa5, 0x3c, 0xc3, 0x8e, 0x71,
  119. 0x78, 0x87, 0xca, 0x35, 0xac, 0x53, 0x1e, 0xe1,
  120. 0xa0, 0x5f, 0x12, 0xed, 0x74, 0x8b, 0xc6, 0x39,
  121. 0x30, 0xcf, 0x82, 0x7d, 0xe4, 0x1b, 0x56, 0xa9,
  122. 0x48, 0xb7, 0xfa, 0x05, 0x9c, 0x63, 0x2e, 0xd1,
  123. 0xd8, 0x27, 0x6a, 0x95, 0x0c, 0xf3, 0xbe, 0x41,
  124. 0xc0, 0x3f, 0x72, 0x8d, 0x14, 0xeb, 0xa6, 0x59,
  125. 0x50, 0xaf, 0xe2, 0x1d, 0x84, 0x7b, 0x36, 0xc9,
  126. 0x28, 0xd7, 0x9a, 0x65, 0xfc, 0x03, 0x4e, 0xb1,
  127. 0xb8, 0x47, 0x0a, 0xf5, 0x6c, 0x93, 0xde, 0x21,
  128. 0x60, 0x9f, 0xd2, 0x2d, 0xb4, 0x4b, 0x06, 0xf9,
  129. 0xf0, 0x0f, 0x42, 0xbd, 0x24, 0xdb, 0x96, 0x69,
  130. 0x88, 0x77, 0x3a, 0xc5, 0x5c, 0xa3, 0xee, 0x11,
  131. 0x18, 0xe7, 0xaa, 0x55, 0xcc, 0x33, 0x7e, 0x81,
  132. 0x80, 0x7f, 0x32, 0xcd, 0x54, 0xab, 0xe6, 0x19,
  133. 0x10, 0xef, 0xa2, 0x5d, 0xc4, 0x3b, 0x76, 0x89,
  134. 0x68, 0x97, 0xda, 0x25, 0xbc, 0x43, 0x0e, 0xf1,
  135. 0xf8, 0x07, 0x4a, 0xb5, 0x2c, 0xd3, 0x9e, 0x61,
  136. 0x20, 0xdf, 0x92, 0x6d, 0xf4, 0x0b, 0x46, 0xb9,
  137. 0xb0, 0x4f, 0x02, 0xfd, 0x64, 0x9b, 0xd6, 0x29,
  138. 0xc8, 0x37, 0x7a, 0x85, 0x1c, 0xe3, 0xae, 0x51,
  139. 0x58, 0xa7, 0xea, 0x15, 0x8c, 0x73, 0x3e, 0xc1,
  140. 0x40, 0xbf, 0xf2, 0x0d, 0x94, 0x6b, 0x26, 0xd9,
  141. 0xd0, 0x2f, 0x62, 0x9d, 0x04, 0xfb, 0xb6, 0x49,
  142. 0xa8, 0x57, 0x1a, 0xe5, 0x7c, 0x83, 0xce, 0x31,
  143. 0x38, 0xc7, 0x8a, 0x75, 0xec, 0x13, 0x5e, 0xa1,
  144. 0xe0, 0x1f, 0x52, 0xad, 0x34, 0xcb, 0x86, 0x79,
  145. 0x70, 0x8f, 0xc2, 0x3d, 0xa4, 0x5b, 0x16, 0xe9,
  146. 0x08, 0xf7, 0xba, 0x45, 0xdc, 0x23, 0x6e, 0x91,
  147. 0x98, 0x67, 0x2a, 0xd5, 0x4c, 0xb3, 0xfe, 0x01
  148. };
  149. /******************************Public*Routine******************************\
  150. * DrvFillPath
  151. *
  152. * Fill the specified path with the specified brush and ROP. This routine
  153. * detects single convex polygons, and will call to separate faster convex
  154. * polygon code for those cases. This routine also detects polygons that
  155. * are really rectangles, and handles those separately as well.
  156. *
  157. * Note: Multiple polygons in a path cannot be treated as being disjoint;
  158. * the fill must consider all the points in the path. That is, if the
  159. * path contains multiple polygons, you cannot simply draw one polygon
  160. * after the other (unless they don't overlap).
  161. *
  162. * Note: This function is optional, but is recommended for good performance.
  163. * To get GDI to call this function, not only do you have to
  164. * HOOK_FILLPATH, you have to set GCAPS_ALTERNATEFILL and/or
  165. * GCAPS_WINDINGFILL.
  166. *
  167. \**************************************************************************/
  168. BOOL DrvFillPath(
  169. SURFOBJ* pso,
  170. PATHOBJ* ppo,
  171. CLIPOBJ* pco,
  172. BRUSHOBJ* pbo,
  173. POINTL* pptlBrush,
  174. MIX mix,
  175. FLONG flOptions)
  176. {
  177. BYTE jClipping; // clipping type
  178. EDGE *pCurrentEdge;
  179. EDGE AETHead; // dummy head/tail node & sentinel for Active Edge Table
  180. EDGE *pAETHead; // pointer to AETHead
  181. EDGE GETHead; // dummy head/tail node & sentinel for Global Edge Table
  182. EDGE *pGETHead; // pointer to GETHead
  183. EDGE *pFreeEdges; // pointer to memory free for use to store edges
  184. ULONG ulNumRects; // # of rectangles to draw currently in rectangle list
  185. RECTL *prclRects; // pointer to start of rectangle draw list
  186. INT iCurrentY; // scan line for which we're currently scanning out the
  187. // fill
  188. ULONG uRop; // Hardware foreground mix value
  189. ULONG uRopb; // Hardware background mix value
  190. ULONG avec; // A-vector notation for ternary rop
  191. ULONG iSolidColor; // Copy of pbo->iSolidColor
  192. FNFILL *pfnFill; // Points to appropriate fill routine
  193. BOOL bRealizeTransparent; // Need a transparent realization for Rop
  194. BOOL bSolid;
  195. BOOL bMore;
  196. PATHDATA pd;
  197. RECTL ClipRect;
  198. PDEV *ppdev;
  199. BOOL bRetVal=FALSE; // FALSE until proven TRUE
  200. BOOL bMemAlloced=FALSE; // FALSE until proven TRUE
  201. FLONG flFirstRecord;
  202. POINTFIX* pptfxTmp;
  203. ULONG cptfxTmp;
  204. POINTFIX aptfxBuf[NUM_BUFFER_POINTS];
  205. ULONG ulBltDef = 0x1000;
  206. #if NULL_PATH
  207. {
  208. if (pointer_switch) return(TRUE);
  209. }
  210. #endif
  211. DISPDBG((FILLPATH_DBG_LEVEL,"DrvFillPath\n"));
  212. // Set up the clipping
  213. if (pco == (CLIPOBJ *) NULL) {
  214. // No CLIPOBJ provided, so we don't have to worry about clipping
  215. jClipping = DC_TRIVIAL;
  216. } else {
  217. // Use the CLIPOBJ-provided clipping
  218. jClipping = pco->iDComplexity;
  219. }
  220. if (jClipping != DC_TRIVIAL) {
  221. if (jClipping != DC_RECT) {
  222. DISPDBG((FILLPATH_DBG_LEVEL,"Complex Clipping Early Out\n"));
  223. #if LOG_CALLS
  224. ppdev = (PDEV*) pso->dhpdev;
  225. LogFillPath(2, ppdev, NULL);
  226. #endif
  227. goto ReturnFalse; // there is complex clipping; let GDI fill the path
  228. }
  229. // Clip to the clip rectangle
  230. ClipRect = pco->rclBounds;
  231. } else {
  232. // So the y-clipping code doesn't do any clipping
  233. // /16 so we don't blow the values out when we scale up to GIQ
  234. ClipRect.top = (LONG_MIN + 1) / 16; // +1 to avoid compiler problem
  235. ClipRect.bottom = LONG_MAX / 16;
  236. }
  237. // There's nothing to do if there are only one or two points
  238. if (ppo->cCurves <= 2) {
  239. DISPDBG((FILLPATH_DBG_LEVEL,"Nothing to do out\n"));
  240. #if LOG_CALLS
  241. ppdev = (PDEV*) pso->dhpdev;
  242. LogFillPath(0, ppdev, pso);
  243. #endif
  244. goto ReturnTrue;
  245. }
  246. // Pass the surface off to GDI if it's a device bitmap that we've
  247. // converted to a DIB:
  248. // This is where to put device bit maps
  249. ppdev = (PDEV*) pso->dhpdev;
  250. SYNC_W_3D(ppdev);
  251. if (pso->iType == STYPE_DEVBITMAP)
  252. {
  253. PDSURF pdsurf = (PDSURF) pso->dhsurf;
  254. if ( pdsurf->pso && !bCreateScreenFromDib(ppdev, pdsurf) )
  255. {
  256. LogFillPath(4, ppdev, NULL);
  257. return(EngFillPath(pdsurf->pso, ppo, pco, pbo, pptlBrush, mix,
  258. flOptions));
  259. }
  260. ppdev->ptlOffset = pdsurf->ptl;
  261. }
  262. else
  263. {
  264. ppdev->ptlOffset.x = ppdev->ptlOffset.y = 0;
  265. }
  266. pfnFill = vMmFillSolid;
  267. uRop = Rop2ToRop3[mix & 0xF];
  268. uRopb = Rop2ToRop3[(mix >> 8) & 0xF];
  269. bSolid = ((pbo == NULL) || (pbo->iSolidColor != -1));
  270. //
  271. // Make it simple and punt this one until later
  272. //
  273. avec = gajRop[uRop];
  274. if ((uRop != uRopb) && !bSolid)
  275. {
  276. DISPDBG((FILLPATH_DBG_LEVEL, "ROPs it Fore=%x Back=%x ROP3=%x\n", uRop, uRopb, ROP3MIX(uRop, uRopb)));
  277. uRop = ROP3MIX(uRop, uRopb);
  278. avec = gajRop[uRop];
  279. if (avec & AVEC_NEED_SOURCE)
  280. {
  281. // Use the implicit mask in the brush object.
  282. // Note pre-align mask (as if "anchored")
  283. if (!bSetMask(ppdev, pbo, pptlBrush, &ulBltDef))
  284. {
  285. DISPDBG((FILLPATH_DBG_LEVEL, "Set Mask Failed"));
  286. LogFillPath(5, ppdev, NULL);
  287. return FALSE;
  288. }
  289. }
  290. }
  291. iSolidColor = 0; // Assume we won't need a pattern
  292. bRealizeTransparent = FALSE;
  293. if (avec & AVEC_NEED_PATTERN)
  294. {
  295. iSolidColor = pbo->iSolidColor;
  296. if (pbo->iSolidColor == -1)
  297. {
  298. bRealizeTransparent = (uRop != uRopb);
  299. if (pbo->pvRbrush == NULL)
  300. {
  301. pbo->pvRbrush = BRUSHOBJ_pvGetRbrush(pbo);
  302. if (pbo->pvRbrush == NULL)
  303. {
  304. DISPDBG((FILLPATH_DBG_LEVEL,"Could Not Get Brush\n"));
  305. LogFillPath(6, ppdev, NULL);
  306. return(FALSE);
  307. }
  308. }
  309. pfnFill = vMmFillPatFast;
  310. }
  311. else
  312. ulBltDef |= (BD_OP2 * IS_SOLID); // Or in 0x0007
  313. }
  314. if (avec & AVEC_NEED_DEST)
  315. ulBltDef |= (BD_OP0 * IS_VRAM); // Or in 0x0100
  316. // Enumerate path here first time to check for special
  317. // cases (rectangles and monotone polygons)
  318. // It is too difficult to determine interaction between
  319. // multiple paths, if there is more than one, skip this
  320. bMore = PATHOBJ_bEnum(ppo, &pd);
  321. if (jClipping == DC_TRIVIAL)
  322. {
  323. // Try going through the fast non-complex fill code. We'll have
  324. // to realize the brush first if we're going to handle a pattern:
  325. if (iSolidColor == -1)
  326. {
  327. #ifdef S3
  328. #if !FASTFILL_PATTERNS
  329. goto SkipFastFill;
  330. #else
  331. // We handle patterns in 'pfnFastFill' only if we can use the S3
  332. // hardware patterns.
  333. if (!(ppdev->flCaps & CAPS_HW_PATTERNS))
  334. goto SkipFastFill;
  335. // Note: prb->pbe will be NULL and prb->ptlBrushOrg.x will be -1 the
  336. // first time an RBRUSH is used. So we have to check the
  337. // alignment *before* dereferencing prb->pbe...
  338. if ((rbc.prb->ptlBrushOrg.x != pptlBrush->x + ppdev->xOffset) ||
  339. (rbc.prb->ptlBrushOrg.y != pptlBrush->y + ppdev->yOffset) ||
  340. (rbc.prb->apbe[IBOARD(ppdev)]->prbVerify != rbc.prb) ||
  341. (rbc.prb->bTransparent != bRealizeTransparent))
  342. {
  343. vMmFastPatRealize(ppdev, pbo, pptlBrush,
  344. bRealizeTransparent);
  345. }
  346. #endif
  347. #endif
  348. // Realize the brush
  349. if (!SetBrush(ppdev, &ulBltDef, pbo, pptlBrush))
  350. {
  351. DISPDBG((FILLPATH_DBG_LEVEL,"Could Not Set Brush\n"));
  352. LogFillPath(6, ppdev, NULL);
  353. return FALSE;
  354. }
  355. }
  356. if (bMore)
  357. {
  358. // FastFill only knows how to take a single contiguous buffer
  359. // of points. Unfortunately, GDI sometimes hands us paths
  360. // that are split over multiple path data records. Convex
  361. // figures such as Ellipses, Pies and RoundRects are almost
  362. // always given in multiple records. Since probably 90% of
  363. // multiple record paths could still be done by FastFill, for
  364. // those cases we simply copy the points into a contiguous
  365. // buffer...
  366. // First make sure that the entire path would fit in the
  367. // temporary buffer, and make sure the path isn't comprised
  368. // of more than one subpath:
  369. if ((ppo->cCurves >= NUM_BUFFER_POINTS) ||
  370. (pd.flags & PD_ENDSUBPATH))
  371. goto SkipFastFill;
  372. pptfxTmp = &aptfxBuf[0];
  373. RtlCopyMemory(pptfxTmp, pd.pptfx, sizeof(POINTFIX) * pd.count);
  374. pptfxTmp += pd.count;
  375. cptfxTmp = pd.count;
  376. flFirstRecord = pd.flags; // Remember PD_BEGINSUBPATH flag
  377. do {
  378. bMore = PATHOBJ_bEnum(ppo, &pd);
  379. RtlCopyMemory(pptfxTmp, pd.pptfx, sizeof(POINTFIX) * pd.count);
  380. cptfxTmp += pd.count;
  381. pptfxTmp += pd.count;
  382. } while (!(pd.flags & PD_ENDSUBPATH));
  383. // Fake up the path data record:
  384. pd.pptfx = &aptfxBuf[0];
  385. pd.count = cptfxTmp;
  386. pd.flags |= flFirstRecord;
  387. // If there's more than one subpath, we can't call FastFill:
  388. if (bMore)
  389. goto SkipFastFill;
  390. }
  391. ppdev->uBLTDEF = ulBltDef;
  392. if (bMmFastFill(ppdev, pd.count, pd.pptfx, uRop,
  393. uRopb, iSolidColor, pbo))
  394. {
  395. LogFillPath(0, ppdev, pso);
  396. return(TRUE);
  397. }
  398. }
  399. SkipFastFill:
  400. // Set up working storage in the temporary buffer
  401. prclRects = (RECTL*) ppdev->pvTmpBuffer; // storage for list of rectangles to draw
  402. if (!bMore) {
  403. RECTL *rectangle;
  404. INT cPoints = pd.count;
  405. // The count can't be less than three, because we got all the edges
  406. // in this subpath, and above we checked that there were at least
  407. // three edges
  408. // If the count is four, check to see if the polygon is really a
  409. // rectangle since we can really speed that up. We'll also check for
  410. // five with the first and last points the same, because under Win 3.1,
  411. // it was required to close polygons
  412. if ((cPoints == 4) ||
  413. ((cPoints == 5) &&
  414. (pd.pptfx[0].x == pd.pptfx[4].x) &&
  415. (pd.pptfx[0].y == pd.pptfx[4].y))) {
  416. rectangle = prclRects;
  417. /* we have to start somewhere so assume that most
  418. applications specify the top left point first
  419. we want to check that the first two points are
  420. either vertically or horizontally aligned. if
  421. they are then we check that the last point [3]
  422. is either horizontally or vertically aligned,
  423. and finally that the 3rd point [2] is aligned
  424. with both the first point and the last point */
  425. #define FIX_SHIFT 4L
  426. #define FIX_MASK (- (1 << FIX_SHIFT))
  427. rectangle->top = pd.pptfx[0].y - 1 & FIX_MASK;
  428. rectangle->left = pd.pptfx[0].x - 1 & FIX_MASK;
  429. rectangle->right = pd.pptfx[1].x - 1 & FIX_MASK;
  430. if (rectangle->left ^ rectangle->right) {
  431. if (rectangle->top ^ (pd.pptfx[1].y - 1 & FIX_MASK))
  432. goto not_rectangle;
  433. if (rectangle->left ^ (pd.pptfx[3].x - 1 & FIX_MASK))
  434. goto not_rectangle;
  435. if (rectangle->right ^ (pd.pptfx[2].x - 1 & FIX_MASK))
  436. goto not_rectangle;
  437. rectangle->bottom = pd.pptfx[2].y - 1 & FIX_MASK;
  438. if (rectangle->bottom ^ (pd.pptfx[3].y - 1 & FIX_MASK))
  439. goto not_rectangle;
  440. }
  441. else {
  442. if (rectangle->top ^ (pd.pptfx[3].y - 1 & FIX_MASK))
  443. goto not_rectangle;
  444. rectangle->bottom = pd.pptfx[1].y - 1 & FIX_MASK;
  445. if (rectangle->bottom ^ (pd.pptfx[2].y - 1 & FIX_MASK))
  446. goto not_rectangle;
  447. rectangle->right = pd.pptfx[2].x - 1 & FIX_MASK;
  448. if (rectangle->right ^ (pd.pptfx[3].x - 1 & FIX_MASK))
  449. goto not_rectangle;
  450. }
  451. /* if the left is greater than the right then
  452. swap them so the blt code doesn't wig out */
  453. if (rectangle->left > rectangle->right) {
  454. FIX temp;
  455. temp = rectangle->left;
  456. rectangle->left = rectangle->right;
  457. rectangle->right = temp;
  458. }
  459. else {
  460. /* if left == right there's nothing to draw */
  461. if (rectangle->left == rectangle->right)
  462. {
  463. LogFillPath(0, ppdev, pso);
  464. goto ReturnTrue;
  465. }
  466. }
  467. /* shift the values to get pixel coordinates */
  468. rectangle->left = (rectangle->left >> FIX_SHIFT) + 1;
  469. rectangle->right = (rectangle->right >> FIX_SHIFT) + 1;
  470. if (rectangle->top > rectangle->bottom) {
  471. FIX temp;
  472. temp = rectangle->top;
  473. rectangle->top = rectangle->bottom;
  474. rectangle->bottom = temp;
  475. }
  476. else {
  477. if (rectangle->top == rectangle->bottom)
  478. {
  479. LogFillPath(0, ppdev, pso);
  480. goto ReturnTrue;
  481. }
  482. }
  483. /* shift the values to get pixel coordinates */
  484. rectangle->top = (rectangle->top >> FIX_SHIFT) + 1;
  485. rectangle->bottom = (rectangle->bottom >> FIX_SHIFT) + 1;
  486. // Finally, check for clipping
  487. if (jClipping == DC_RECT) {
  488. // Clip to the clip rectangle
  489. if (!bIntersect(rectangle, &ClipRect, rectangle))
  490. {
  491. // Totally clipped, nothing to do
  492. LogFillPath(0, ppdev, pso);
  493. goto ReturnTrue;
  494. }
  495. }
  496. /* if we get here then the polygon is a rectangle,
  497. set count to 1 and goto bottom to draw it */
  498. ulNumRects = 1;
  499. goto draw_remaining_rectangles;
  500. }
  501. not_rectangle:
  502. ;
  503. }
  504. // Do we have enough memory for all the edges?
  505. // LATER does cCurves include closure?
  506. if (ppo->cCurves > MAX_EDGES) {
  507. #if TAKING_ALLOC_STATS
  508. BufferMissInFillpath++;
  509. #endif
  510. //
  511. // try to allocate enough memory
  512. //
  513. #ifdef WINNT_VER40
  514. pFreeEdges = (EDGE *) MEM_ALLOC(0, (ppo->cCurves * sizeof(EDGE)), ALLOC_TAG);
  515. #else
  516. pFreeEdges = (EDGE *) MEM_ALLOC(LMEM_FIXED, (ppo->cCurves * sizeof(EDGE)));
  517. #endif
  518. if (pFreeEdges == NULL)
  519. {
  520. LogFillPath(1, ppdev, NULL);
  521. goto ReturnFalse; // too many edges; let GDI fill the path
  522. }
  523. else
  524. {
  525. bMemAlloced = TRUE;
  526. }
  527. }
  528. else {
  529. #if TAKING_ALLOC_STATS
  530. BufferHitInFillpath++;
  531. #endif
  532. pFreeEdges = (EDGE*) ((BYTE*) ppdev->pvTmpBuffer + RECT_BYTES);
  533. // use our handy temporary buffer (it's big enough)
  534. }
  535. // Initialize an empty list of rectangles to fill
  536. ulNumRects = 0;
  537. // Enumerate the path edges and build a Global Edge Table (GET) from them
  538. // in YX-sorted order.
  539. pGETHead = &GETHead;
  540. if (!ConstructGET(pGETHead, pFreeEdges, ppo, &pd, bMore, &ClipRect))
  541. {
  542. LogFillPath(7, ppdev, NULL);
  543. goto ReturnFalse; // outside GDI's 2**27 range
  544. }
  545. // Create an empty AET with the head node also a tail sentinel
  546. pAETHead = &AETHead;
  547. AETHead.pNext = pAETHead; // mark that the AET is empty
  548. AETHead.X = 0x7FFFFFFF; // this is greater than any valid X value, so
  549. // searches will always terminate
  550. // Top scan of polygon is the top of the first edge we come to
  551. iCurrentY = ((EDGE *)GETHead.pNext)->Y;
  552. // Loop through all the scans in the polygon, adding edges from the GET to
  553. // the Active Edge Table (AET) as we come to their starts, and scanning out
  554. // the AET at each scan into a rectangle list. Each time it fills up, the
  555. // rectangle list is passed to the filling routine, and then once again at
  556. // the end if any rectangles remain undrawn. We continue so long as there
  557. // are edges to be scanned out
  558. while (1) {
  559. // Advance the edges in the AET one scan, discarding any that have
  560. // reached the end (if there are any edges in the AET)
  561. if (AETHead.pNext != pAETHead) {
  562. AdvanceAETEdges(pAETHead);
  563. }
  564. // If the AET is empty, done if the GET is empty, else jump ahead to
  565. // the next edge in the GET; if the AET isn't empty, re-sort the AET
  566. if (AETHead.pNext == pAETHead) {
  567. if (GETHead.pNext == pGETHead) {
  568. // Done if there are no edges in either the AET or the GET
  569. break;
  570. }
  571. // There are no edges in the AET, so jump ahead to the next edge in
  572. // the GET
  573. iCurrentY = ((EDGE *)GETHead.pNext)->Y;
  574. } else {
  575. // Re-sort the edges in the AET by X coordinate, if there are at
  576. // least two edges in the AET (there could be one edge if the
  577. // balancing edge hasn't yet been added from the GET)
  578. if (((EDGE *)AETHead.pNext)->pNext != pAETHead) {
  579. XSortAETEdges(pAETHead);
  580. }
  581. }
  582. // Move any new edges that start on this scan from the GET to the AET;
  583. // bother calling only if there's at least one edge to add
  584. if (((EDGE *)GETHead.pNext)->Y == iCurrentY) {
  585. MoveNewEdges(pGETHead, pAETHead, iCurrentY);
  586. }
  587. // Scan the AET into rectangles to fill (there's always at least one
  588. // edge pair in the AET)
  589. pCurrentEdge = AETHead.pNext; // point to the first edge
  590. do {
  591. INT iLeftEdge;
  592. // The left edge of any given edge pair is easy to find; it's just
  593. // wherever we happen to be currently
  594. iLeftEdge = pCurrentEdge->X;
  595. // Find the matching right edge according to the current fill rule
  596. if ((flOptions & FP_WINDINGMODE) != 0) {
  597. INT iWindingCount;
  598. // Do winding fill; scan across until we've found equal numbers
  599. // of up and down edges
  600. iWindingCount = pCurrentEdge->iWindingDirection;
  601. do {
  602. pCurrentEdge = pCurrentEdge->pNext;
  603. iWindingCount += pCurrentEdge->iWindingDirection;
  604. } while (iWindingCount != 0);
  605. } else {
  606. // Odd-even fill; the next edge is the matching right edge
  607. pCurrentEdge = pCurrentEdge->pNext;
  608. }
  609. // See if the resulting span encompasses at least one pixel, and
  610. // add it to the list of rectangles to draw if so
  611. if (iLeftEdge < pCurrentEdge->X) {
  612. // We've got an edge pair to add to the list to be filled; see
  613. // if there's room for one more rectangle
  614. if (ulNumRects >= MAX_PATH_RECTS) {
  615. // No more room; draw the rectangles in the list and reset
  616. // it to empty
  617. ppdev->uBLTDEF = ulBltDef;
  618. (*pfnFill)(ppdev, ulNumRects, prclRects, uRop,
  619. uRopb, pbo, pptlBrush);
  620. // Reset the list to empty
  621. ulNumRects = 0;
  622. }
  623. // Add the rectangle representing the current edge pair
  624. if (jClipping == DC_RECT) {
  625. // Clipped
  626. // Clip to left
  627. prclRects[ulNumRects].left = max(iLeftEdge, ClipRect.left);
  628. // Clip to right
  629. prclRects[ulNumRects].right =
  630. min(pCurrentEdge->X, ClipRect.right);
  631. // Draw only if not fully clipped
  632. if (prclRects[ulNumRects].left <
  633. prclRects[ulNumRects].right) {
  634. prclRects[ulNumRects].top = iCurrentY;
  635. prclRects[ulNumRects].bottom = iCurrentY+1;
  636. ulNumRects++;
  637. }
  638. }
  639. else
  640. {
  641. // Unclipped
  642. prclRects[ulNumRects].top = iCurrentY;
  643. prclRects[ulNumRects].bottom = iCurrentY+1;
  644. prclRects[ulNumRects].left = iLeftEdge;
  645. prclRects[ulNumRects].right = pCurrentEdge->X;
  646. ulNumRects++;
  647. }
  648. }
  649. } while ((pCurrentEdge = pCurrentEdge->pNext) != pAETHead);
  650. iCurrentY++; // next scan
  651. }
  652. /* draw the remaining rectangles, if there are any */
  653. draw_remaining_rectangles:
  654. if (ulNumRects > 0) {
  655. ppdev->uBLTDEF = ulBltDef;
  656. (*pfnFill)(ppdev, ulNumRects, prclRects, uRop, uRopb,
  657. pbo, pptlBrush);
  658. }
  659. LogFillPath(0, ppdev, pso);
  660. ReturnTrue:
  661. bRetVal = TRUE; // done successfully
  662. ReturnFalse:
  663. // bRetVal is originally false. If you jumped to ReturnFalse from somewhere,
  664. // then it will remain false, and be returned.
  665. if (bMemAlloced)
  666. {
  667. //
  668. // we did allocate memory, so release it
  669. //
  670. MEMORY_FREE (pFreeEdges);
  671. }
  672. return(bRetVal);
  673. }
  674. // Advance the edges in the AET to the next scan, dropping any for which we've
  675. // done all scans. Assumes there is at least one edge in the AET.
  676. VOID AdvanceAETEdges(EDGE *pAETHead)
  677. {
  678. EDGE *pLastEdge, *pCurrentEdge;
  679. pLastEdge = pAETHead;
  680. pCurrentEdge = pLastEdge->pNext;
  681. do {
  682. // Count down this edge's remaining scans
  683. if (--pCurrentEdge->iScansLeft == 0) {
  684. // We've done all scans for this edge; drop this edge from the AET
  685. pLastEdge->pNext = pCurrentEdge->pNext;
  686. } else {
  687. // Advance the edge's X coordinate for a 1-scan Y advance
  688. // Advance by the minimum amount
  689. pCurrentEdge->X += pCurrentEdge->iXWhole;
  690. // Advance the error term and see if we got one extra pixel this
  691. // time
  692. pCurrentEdge->iErrorTerm += pCurrentEdge->iErrorAdjustUp;
  693. if (pCurrentEdge->iErrorTerm >= 0) {
  694. // The error term turned over, so adjust the error term and
  695. // advance the extra pixel
  696. pCurrentEdge->iErrorTerm -= pCurrentEdge->iErrorAdjustDown;
  697. pCurrentEdge->X += pCurrentEdge->iXDirection;
  698. }
  699. pLastEdge = pCurrentEdge;
  700. }
  701. } while ((pCurrentEdge = pLastEdge->pNext) != pAETHead);
  702. }
  703. // X-sort the AET, because the edges may have moved around relative to
  704. // one another when we advanced them. We'll use a multipass bubble
  705. // sort, which is actually okay for this application because edges
  706. // rarely move relative to one another, so we usually do just one pass.
  707. // Also, this makes it easy to keep just a singly-linked list. Assumes there
  708. // are at least two edges in the AET.
  709. VOID XSortAETEdges(EDGE *pAETHead)
  710. {
  711. BOOL bEdgesSwapped;
  712. EDGE *pLastEdge, *pCurrentEdge, *pNextEdge;
  713. do {
  714. bEdgesSwapped = FALSE;
  715. pLastEdge = pAETHead;
  716. pCurrentEdge = pLastEdge->pNext;
  717. pNextEdge = pCurrentEdge->pNext;
  718. do {
  719. if (pNextEdge->X < pCurrentEdge->X) {
  720. // Next edge is to the left of the current edge; swap them
  721. pLastEdge->pNext = pNextEdge;
  722. pCurrentEdge->pNext = pNextEdge->pNext;
  723. pNextEdge->pNext = pCurrentEdge;
  724. bEdgesSwapped = TRUE;
  725. pCurrentEdge = pNextEdge; // continue sorting before the edge
  726. // we just swapped; it might move
  727. // farther yet
  728. }
  729. pLastEdge = pCurrentEdge;
  730. pCurrentEdge = pLastEdge->pNext;
  731. } while ((pNextEdge = pCurrentEdge->pNext) != pAETHead);
  732. } while (bEdgesSwapped);
  733. }
  734. // Moves all edges that start on the current scan from the GET to the AET in
  735. // X-sorted order. Parameters are pointer to head of GET and pointer to dummy
  736. // edge at head of AET, plus current scan line. Assumes there's at least one
  737. // edge to be moved.
  738. VOID MoveNewEdges(EDGE *pGETHead, EDGE *pAETHead, INT iCurrentY)
  739. {
  740. EDGE *pCurrentEdge = pAETHead;
  741. EDGE *pGETNext = pGETHead->pNext;
  742. do {
  743. // Scan through the AET until the X-sorted insertion point for this
  744. // edge is found. We can continue from where the last search left
  745. // off because the edges in the GET are in X sorted order, as is
  746. // the AET. The search always terminates because the AET sentinel
  747. // is greater than any valid X
  748. while (pGETNext->X > ((EDGE *)pCurrentEdge->pNext)->X) {
  749. pCurrentEdge = pCurrentEdge->pNext;
  750. }
  751. // We've found the insertion point; add the GET edge to the AET, and
  752. // remove it from the GET
  753. pGETHead->pNext = pGETNext->pNext;
  754. pGETNext->pNext = pCurrentEdge->pNext;
  755. pCurrentEdge->pNext = pGETNext;
  756. pCurrentEdge = pGETNext; // continue insertion search for the next
  757. // GET edge after the edge we just added
  758. pGETNext = pGETHead->pNext;
  759. } while (pGETNext->Y == iCurrentY);
  760. }
  761. // Build the Global Edge Table from the path. There must be enough memory in
  762. // the free edge area to hold all edges. The GET is constructed in Y-X order,
  763. // and has a head/tail/sentinel node at pGETHead.
  764. BOOL ConstructGET(
  765. EDGE *pGETHead,
  766. EDGE *pFreeEdges,
  767. PATHOBJ *ppo,
  768. PATHDATA *pd,
  769. BOOL bMore,
  770. RECTL *pClipRect)
  771. {
  772. POINTFIX pfxPathStart; // point that started the current subpath
  773. POINTFIX pfxPathPrevious; // point before the current point in a subpath;
  774. // starts the current edge
  775. /* Create an empty GET with the head node also a tail sentinel */
  776. pGETHead->pNext = pGETHead; // mark that the GET is empty
  777. pGETHead->Y = 0x7FFFFFFF; // this is greater than any valid Y value, so
  778. // searches will always terminate
  779. /* PATHOBJ_vEnumStart is implicitly performed by engine
  780. already and first path is enumerated by the caller */
  781. next_subpath:
  782. /* Make sure the PATHDATA is not empty (is this necessary) */
  783. if (pd->count != 0) {
  784. /* If first point starts a subpath, remember it as such
  785. and go on to the next point, so we can get an edge */
  786. if (pd->flags & PD_BEGINSUBPATH) {
  787. /* the first point starts the subpath; remember it */
  788. pfxPathStart = *pd->pptfx; /* the subpath starts here */
  789. pfxPathPrevious = *pd->pptfx; /* this points starts the next edge */
  790. pd->pptfx++; /* advance to the next point */
  791. pd->count--; /* count off this point */
  792. }
  793. /* add edges in PATHDATA to GET, in Y-X sorted order */
  794. while (pd->count--) {
  795. if ((pFreeEdges =
  796. AddEdgeToGET(pGETHead, pFreeEdges, &pfxPathPrevious, pd->pptfx,
  797. pClipRect)) == NULL) {
  798. goto ReturnFalse;
  799. }
  800. pfxPathPrevious = *pd->pptfx; /* current point becomes previous */
  801. pd->pptfx++; /* advance to the next point */
  802. }
  803. /* If last point ends the subpath, insert the edge that
  804. connects to first point (is this built in already?) */
  805. if (pd->flags & PD_ENDSUBPATH) {
  806. if ((pFreeEdges = AddEdgeToGET(pGETHead, pFreeEdges, &pfxPathPrevious,
  807. &pfxPathStart, pClipRect)) == NULL) {
  808. goto ReturnFalse;
  809. }
  810. }
  811. }
  812. /* the initial loop conditions preclude a do, while or for */
  813. if (bMore) {
  814. bMore = PATHOBJ_bEnum(ppo, pd);
  815. goto next_subpath;
  816. }
  817. return(TRUE); // done successfully
  818. ReturnFalse:
  819. return(FALSE); // failed
  820. }
  821. // Adds the edge described by the two passed-in points to the Global Edge
  822. // Table, if the edge spans at least one pixel vertically.
  823. EDGE * AddEdgeToGET(EDGE *pGETHead, EDGE *pFreeEdge,
  824. POINTFIX *ppfxEdgeStart, POINTFIX *ppfxEdgeEnd, RECTL *pClipRect)
  825. {
  826. INT iYStart, iYEnd, iXStart, iXEnd, iYHeight, iXWidth;
  827. INT yJump, yTop;
  828. // Set the winding-rule direction of the edge, and put the endpoints in
  829. // top-to-bottom order
  830. iYHeight = ppfxEdgeEnd->y - ppfxEdgeStart->y;
  831. if (iYHeight == 0) {
  832. return(pFreeEdge); // zero height; ignore this edge
  833. } else if (iYHeight >= 0) {
  834. iXStart = ppfxEdgeStart->x;
  835. iYStart = ppfxEdgeStart->y;
  836. iXEnd = ppfxEdgeEnd->x;
  837. iYEnd = ppfxEdgeEnd->y;
  838. pFreeEdge->iWindingDirection = 1;
  839. } else {
  840. iYHeight = -iYHeight;
  841. iXEnd = ppfxEdgeStart->x;
  842. iYEnd = ppfxEdgeStart->y;
  843. iXStart = ppfxEdgeEnd->x;
  844. iYStart = ppfxEdgeEnd->y;
  845. pFreeEdge->iWindingDirection = -1;
  846. }
  847. if (iYHeight & 0x80000000) {
  848. return(NULL); // too large; outside 2**27 GDI range
  849. }
  850. // Set the error term and adjustment factors, all in GIQ coordinates for
  851. // now
  852. iXWidth = iXEnd - iXStart;
  853. if (iXWidth >= 0) {
  854. // Left to right, so we change X as soon as we move at all
  855. pFreeEdge->iXDirection = 1;
  856. pFreeEdge->iErrorTerm = -1;
  857. } else {
  858. // Right to left, so we don't change X until we've moved a full GIQ
  859. // coordinate
  860. iXWidth = -iXWidth;
  861. pFreeEdge->iXDirection = -1;
  862. pFreeEdge->iErrorTerm = -iYHeight;
  863. }
  864. if (iXWidth & 0x80000000) {
  865. return(NULL); // too large; outside 2**27 GDI range
  866. }
  867. if (iXWidth >= iYHeight) {
  868. // Calculate base run length (minimum distance advanced in X for a 1-
  869. // scan advance in Y)
  870. pFreeEdge->iXWhole = iXWidth / iYHeight;
  871. // Add sign back into base run length if going right to left
  872. if (pFreeEdge->iXDirection == -1) {
  873. pFreeEdge->iXWhole = -pFreeEdge->iXWhole;
  874. }
  875. pFreeEdge->iErrorAdjustUp = iXWidth % iYHeight;
  876. } else {
  877. // Base run length is 0, because line is closer to vertical than
  878. // horizontal
  879. pFreeEdge->iXWhole = 0;
  880. pFreeEdge->iErrorAdjustUp = iXWidth;
  881. }
  882. pFreeEdge->iErrorAdjustDown = iYHeight;
  883. // Calculate the number of pixels spanned by this edge, accounting for
  884. // clipping
  885. // Top true pixel scan in GIQ coordinates
  886. // Shifting to divide and multiply by 16 is okay because the clip rect
  887. // always contains positive numbers
  888. yTop = max(pClipRect->top << 4, (iYStart + 15) & ~0x0F);
  889. pFreeEdge->Y = yTop >> 4; // initial scan line on which to fill edge
  890. // Calculate # of scans to actually fill, accounting for clipping
  891. if ((pFreeEdge->iScansLeft = min(pClipRect->bottom, ((iYEnd + 15) >> 4))
  892. - pFreeEdge->Y) <= 0) {
  893. return(pFreeEdge); // no pixels at all are spanned, so we can
  894. // ignore this edge
  895. }
  896. // If the edge doesn't start on a pixel scan (that is, it starts at a
  897. // fractional GIQ coordinate), advance it to the first pixel scan it
  898. // intersects. Ditto if there's top clipping. Also clip to the bottom if
  899. // needed
  900. if (iYStart != yTop) {
  901. // Jump ahead by the Y distance in GIQ coordinates to the first pixel
  902. // to draw
  903. yJump = yTop - iYStart;
  904. // Advance x the minimum amount for the number of scans traversed
  905. iXStart += pFreeEdge->iXWhole * yJump;
  906. AdjustErrorTerm(&pFreeEdge->iErrorTerm, pFreeEdge->iErrorAdjustUp,
  907. pFreeEdge->iErrorAdjustDown, yJump, &iXStart,
  908. pFreeEdge->iXDirection);
  909. }
  910. // Turn the calculations into pixel rather than GIQ calculations
  911. // Move the X coordinate to the nearest pixel, and adjust the error term
  912. // accordingly
  913. // Dividing by 16 with a shift is okay because X is always positive
  914. pFreeEdge->X = (iXStart + 15) >> 4; // convert from GIQ to pixel coordinates
  915. // LATER adjust only if needed (if prestepped above)?
  916. if (pFreeEdge->iXDirection == 1) {
  917. // Left to right
  918. pFreeEdge->iErrorTerm -= pFreeEdge->iErrorAdjustDown *
  919. (((iXStart + 15) & ~0x0F) - iXStart);
  920. } else {
  921. // Right to left
  922. pFreeEdge->iErrorTerm -= pFreeEdge->iErrorAdjustDown *
  923. ((iXStart - 1) & 0x0F);
  924. }
  925. // Scale the error term down 16 times to switch from GIQ to pixels.
  926. // Shifts work to do the multiplying because these values are always
  927. // non-negative
  928. pFreeEdge->iErrorTerm >>= 4;
  929. // Insert the edge into the GET in YX-sorted order. The search always ends
  930. // because the GET has a sentinel with a greater-than-possible Y value
  931. while ((pFreeEdge->Y > ((EDGE *)pGETHead->pNext)->Y) ||
  932. ((pFreeEdge->Y == ((EDGE *)pGETHead->pNext)->Y) &&
  933. (pFreeEdge->X > ((EDGE *)pGETHead->pNext)->X))) {
  934. pGETHead = pGETHead->pNext;
  935. }
  936. pFreeEdge->pNext = pGETHead->pNext; // link the edge into the GET
  937. pGETHead->pNext = pFreeEdge;
  938. return(++pFreeEdge); // point to the next edge storage location for next
  939. // time
  940. }
  941. // Adjust the error term for a skip ahead in y. This is in ASM because there's
  942. // a multiply/divide that may involve a larger than 32-bit value.
  943. void AdjustErrorTerm(INT *pErrorTerm, INT iErrorAdjustUp, INT iErrorAdjustDown,
  944. INT yJump, INT *pXStart, INT iXDirection)
  945. {
  946. #if defined(_X86_) || defined(i386)
  947. // Adjust the error term up by the number of y coordinates we'll skip
  948. //*pErrorTerm += iErrorAdjustUp * yJump;
  949. _asm mov ebx,pErrorTerm
  950. _asm mov eax,iErrorAdjustUp
  951. _asm mul yJump
  952. _asm add eax,[ebx]
  953. _asm adc edx,-1 // the error term starts out negative
  954. // See if the error term turned over even once while skipping
  955. //if (*pErrorTerm >= 0) {
  956. _asm js short NoErrorTurnover
  957. // # of times we'll turn over the error term and step an extra x
  958. // coordinate while skipping
  959. // NumAdjustDowns = (*pErrorTerm / iErrorAdjustDown) + 1;
  960. _asm div iErrorAdjustDown
  961. _asm inc eax
  962. // Note that EDX is the remainder; (EDX - iErrorAdjustDown) is where
  963. // the error term ends up ultimately
  964. // Advance x appropriately for the # of times the error term
  965. // turned over
  966. // if (iXDirection == 1) {
  967. // *pXStart += NumAdjustDowns;
  968. // } else {
  969. // *pXStart -= NumAdjustDowns;
  970. // }
  971. _asm mov ecx,pXStart
  972. _asm cmp iXDirection,1
  973. _asm jz short GoingRight
  974. _asm neg eax
  975. GoingRight:
  976. _asm add [ecx],eax
  977. // Adjust the error term down to its proper post-skip value
  978. // *pErrorTerm -= iErrorAdjustDown * NumAdjustDowns;
  979. _asm sub edx,iErrorAdjustDown
  980. _asm mov eax,edx // put into EAX for storing to pErrorTerm next
  981. // }
  982. NoErrorTurnover:
  983. _asm mov [ebx],eax
  984. #else
  985. LONGLONG llErrorTerm;
  986. INT NumAdjustDowns;
  987. llErrorTerm = *pErrorTerm;
  988. // Adjust the error term up by the number of y coordinates we'll skip
  989. llErrorTerm += Int32x32To64(iErrorAdjustUp,yJump);
  990. // See if the error term turned over even once while skipping
  991. if (llErrorTerm >= 0) {
  992. // # of times we'll turn over the error term and step an extra x
  993. // coordinate while skipping
  994. NumAdjustDowns = (UInt64Div32To32(llErrorTerm,iErrorAdjustDown)) + 1;
  995. // Advance x appropriately for the # of times the error term
  996. // turned over
  997. if (iXDirection == 1) {
  998. *pXStart += NumAdjustDowns;
  999. } else {
  1000. *pXStart -= NumAdjustDowns;
  1001. }
  1002. // Adjust the error term down to its proper post-skip value
  1003. llErrorTerm -= iErrorAdjustDown * NumAdjustDowns;
  1004. }
  1005. *pErrorTerm = (INT) llErrorTerm;
  1006. #endif
  1007. }
  1008. //--------------------------------------------------------------------------//
  1009. // //
  1010. // bSetMask() //
  1011. // Used by DrvFillPath //
  1012. // to setup the chip to use the current mask. //
  1013. // We don't set the BLTDEF register directly here. We set a local copy, //
  1014. // which the calling routine will further modify befor writing it to //
  1015. // the chip. //
  1016. // //
  1017. //--------------------------------------------------------------------------//
  1018. BOOL bSetMask(
  1019. PPDEV ppdev,
  1020. BRUSHOBJ *pbo,
  1021. POINTL *pptlBrush,
  1022. ULONG *bltdef)
  1023. {
  1024. PRBRUSH pRbrush = 0;
  1025. USHORT patoff_x, patoff_y;
  1026. DISPDBG((FILLPATH_DBG_LEVEL, "bSetMask - Entry\n"));
  1027. // Guard against a solid brush (pen) in case the caller didn't
  1028. if ((pbo ==NULL) || (pbo->iSolidColor != -1))
  1029. {
  1030. RIP("bSetMask - solid mask!\n");
  1031. *bltdef |= BD_OP1_IS_SRAM_MONO;
  1032. REQUIRE(4);
  1033. LL_FGCOLOR(0xFFFFFFFF, 2); // totally
  1034. LL_BGCOLOR(0xFFFFFFFF, 2); // foreground
  1035. return (TRUE);
  1036. }
  1037. else if (pbo->pvRbrush != NULL)
  1038. {
  1039. pRbrush = pbo->pvRbrush;
  1040. }
  1041. else
  1042. {
  1043. pRbrush = BRUSHOBJ_pvGetRbrush(pbo);
  1044. // Fail if we do not handle the brush.
  1045. if (pRbrush == NULL)
  1046. {
  1047. DISPDBG((FILLPATH_DBG_LEVEL, "pRbrush is NULL\n"));
  1048. return (FALSE);
  1049. }
  1050. }
  1051. //
  1052. // Set pattern offset.
  1053. // NT specifies patttern offset as which pixel on the screen to align
  1054. // with pattern(0,0). Laguna specifies pattern offset as which pixel
  1055. // of the pattern to align with screen(0,0). Only the lowest three
  1056. // bits are significant, so we can ignore any overflow when converting.
  1057. // Also, even though PATOFF is a reg_16, we can't do byte wide writes
  1058. // to it. We have to write both PATOFF.pt.X and PATOFF.pt.Y in a single
  1059. // 16 bit write.
  1060. //
  1061. #if 1 //#1244
  1062. patoff_x = (USHORT)(-(pptlBrush->x + ppdev->ptlOffset.x) & 7);
  1063. patoff_y = (USHORT)(-(pptlBrush->y + ppdev->ptlOffset.y) & 7);
  1064. #else
  1065. patoff_x = 8 - (BYTE)(pptlBrush->x & 0x07);
  1066. patoff_y = 8 - (BYTE)(pptlBrush->y & 0x07);
  1067. #endif
  1068. REQUIRE(1);
  1069. LL16 (grPATOFF.w, ((patoff_y << 8) | patoff_x ));
  1070. //
  1071. // What kind of brush is it?
  1072. //
  1073. if (pRbrush->iType == BRUSH_MONO) // Monochrome brush.
  1074. {
  1075. DISPDBG((FILLPATH_DBG_LEVEL, "bSetMask: Using monochrome brush.\n"));
  1076. #define mb ((MC_ENTRY*)(((BYTE*)ppdev->Mtable) + pRbrush->cache_slot))
  1077. if (mb->iUniq != pRbrush->iUniq)
  1078. {
  1079. CacheMono(ppdev, pRbrush);
  1080. }
  1081. // Load the fg and bg color registers.
  1082. REQUIRE(6);
  1083. LL_FGCOLOR(0xFFFFFFFF, 0);
  1084. LL_BGCOLOR(0x00000000, 0);
  1085. LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
  1086. *bltdef |= 0x00D0;
  1087. return(TRUE);
  1088. }
  1089. else if (pRbrush->iType == BRUSH_4BPP) // 4-bpp brush.
  1090. {
  1091. DISPDBG((FILLPATH_DBG_LEVEL, "bSetMask: Using 4-bpp brush.\n"));
  1092. #define xb ((XC_ENTRY*)(((BYTE*)ppdev->Xtable) + pRbrush->cache_slot))
  1093. if (xb->iUniq != pRbrush->iUniq)
  1094. {
  1095. Cache4BPP(ppdev, pRbrush);
  1096. }
  1097. REQUIRE(2);
  1098. LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
  1099. *bltdef |= 0x0090;
  1100. return(TRUE);
  1101. }
  1102. else if (pRbrush->iType == BRUSH_DITHER) // Dither brush.
  1103. {
  1104. DISPDBG((FILLPATH_DBG_LEVEL, "bSetMask: Using dither brush.\n"));
  1105. #define db ((DC_ENTRY*)(((BYTE*)ppdev->Dtable) + pRbrush->cache_slot))
  1106. if (db->ulColor != pRbrush->iUniq)
  1107. {
  1108. CacheDither(ppdev, pRbrush);
  1109. }
  1110. REQUIRE(2);
  1111. LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
  1112. *bltdef |= 0x0090;
  1113. return(TRUE);
  1114. }
  1115. else // Color brush.
  1116. {
  1117. DISPDBG((FILLPATH_DBG_LEVEL, "bSetMask: Using color brush.\n"));
  1118. #define cb ((BC_ENTRY*)(((BYTE*)ppdev->Ctable) + pRbrush->cache_slot))
  1119. if (cb->brushID != pRbrush)
  1120. {
  1121. CacheBrush(ppdev, pRbrush);
  1122. }
  1123. REQUIRE(2);
  1124. LL32(grOP2_opMRDRAM, pRbrush->cache_xy);
  1125. *bltdef |= 0x0090;
  1126. return(TRUE);
  1127. }
  1128. DISPDBG((FILLPATH_DBG_LEVEL, "SetMask Ret False\n"));
  1129. return FALSE;
  1130. }
  1131. #if LOG_CALLS
  1132. extern long lg_i;
  1133. extern char lg_buf[256];
  1134. void LogFillPath(
  1135. ULONG acc,
  1136. PPDEV ppdev,
  1137. SURFOBJ *pso
  1138. )
  1139. {
  1140. #if ENABLE_LOG_SWITCH
  1141. if (pointer_switch == 0) return;
  1142. #endif
  1143. lg_i = sprintf(lg_buf,"DrvFillPath: ");
  1144. WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
  1145. // Did we realize it? If not, why?
  1146. switch (acc)
  1147. {
  1148. case 0: lg_i = sprintf(lg_buf,"(ACCL) Id=%p", pso); break;
  1149. case 1: lg_i = sprintf(lg_buf,"(Punted - Too many edges) "); break;
  1150. case 2: lg_i = sprintf(lg_buf,"(Punted - Complex clipping) "); break;
  1151. case 3: lg_i = sprintf(lg_buf,"(Punted - S3) "); break;
  1152. case 4: lg_i = sprintf(lg_buf,"(Punted - DevBmp on host) "); break;
  1153. case 5: lg_i = sprintf(lg_buf,"(Punted - Failed mask) "); break;
  1154. case 6: lg_i = sprintf(lg_buf,"(Punted - Failed brush) "); break;
  1155. case 7: lg_i = sprintf(lg_buf,"(Punted - Edge table failed) "); break;
  1156. default: lg_i = sprintf(lg_buf,"(STATUS UNKNOWN) "); break;
  1157. }
  1158. WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
  1159. lg_i = sprintf(lg_buf,"\r\n");
  1160. WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
  1161. }
  1162. #endif