Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2130 lines
63 KiB

  1. /*************************************************************************\
  2. * Module Name: Lines.c
  3. *
  4. * Contains most of the required GDI line support. Supports drawing
  5. * lines in short 'strips' when clipping is complex or coordinates
  6. * are too large to be drawn by the line hardware.
  7. *
  8. * Copyright (c) 1990-1995 Microsoft Corporation
  9. \**************************************************************************/
  10. #include "precomp.h"
  11. ///////////////////////////////////////////////////////////////////////
  12. // We have to be careful of arithmetic overflow in a number of places.
  13. // Fortunately, the compiler is guaranteed to natively support 64-bit
  14. // signed LONGLONGs and 64-bit unsigned DWORDLONGs.
  15. //
  16. // UUInt32x32To64(a, b) is a macro defined in 'winnt.h' that multiplies
  17. // two 32-bit ULONGs to produce a 64-bit DWORDLONG result.
  18. //
  19. // UInt64By32To32 is our own macro to divide a 64-bit DWORDLONG by
  20. // a 32-bit ULONG to produce a 32-bit ULONG result.
  21. //
  22. // UInt64Mod32To32 is our own macro to modulus a 64-bit DWORDLONG by
  23. // a 32-bit ULONG to produce a 32-bit ULONG result.
  24. //
  25. // 64 bit divides are usually very expensive. Since it's very rare
  26. // that we'll get lines where the upper 32 bits of the 64 bit result
  27. // are used, we can almost always use 32-bit ULONG divides. We still
  28. // must correctly handle the larger cases:
  29. #define UInt64Div32To32(a, b) \
  30. ((((DWORDLONG)(a)) > ULONG_MAX) ? \
  31. (ULONG)((DWORDLONG)(a) / (ULONG)(b)) : \
  32. (ULONG)((ULONG)(a) / (ULONG)(b)))
  33. #define UInt64Mod32To32(a, b) \
  34. ((((DWORDLONG)(a)) > ULONG_MAX) ? \
  35. (ULONG)((DWORDLONG)(a) % (ULONG)(b)) : \
  36. (ULONG)((ULONG)(a) % (ULONG)(b)))
  37. #define SWAPL(x,y,t) {t = x; x = y; y = t;}
  38. FLONG gaflRound[] = {
  39. FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // no flips
  40. FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // FL_FLIP_D
  41. FL_H_ROUND_DOWN, // FL_FLIP_V
  42. FL_V_ROUND_DOWN, // FL_FLIP_V | FL_FLIP_D
  43. FL_V_ROUND_DOWN, // FL_FLIP_SLOPE_ONE
  44. 0xbaadf00d, // FL_FLIP_SLOPE_ONE | FL_FLIP_D
  45. FL_H_ROUND_DOWN, // FL_FLIP_SLOPE_ONE | FL_FLIP_V
  46. 0xbaadf00d // FL_FLIP_SLOPE_ONE | FL_FLIP_V | FL_FLIP_D
  47. };
  48. /******************************Public*Routine******************************\
  49. * BOOL bLines(ppdev, pptfxFirst, pptfxBuf, cptfx, pls,
  50. * prclClip, apfn[], flStart)
  51. *
  52. * Computes the DDA for the line and gets ready to draw it. Puts the
  53. * pixel data into an array of strips, and calls a strip routine to
  54. * do the actual drawing.
  55. *
  56. \**************************************************************************/
  57. BOOL bLines(
  58. PDEV* ppdev,
  59. POINTFIX* pptfxFirst, // Start of first line
  60. POINTFIX* pptfxBuf, // Pointer to buffer of all remaining lines
  61. RUN* prun, // Pointer to runs if doing complex clipping
  62. ULONG cptfx, // Number of points in pptfxBuf or number of runs
  63. // in prun
  64. LINESTATE* pls, // Colour and style info
  65. RECTL* prclClip, // Pointer to clip rectangle if doing simple clipping
  66. PFNSTRIP* apfn, // Array of strip functions
  67. FLONG flStart, // Flags for each line, which is a combination of:
  68. // FL_SIMPLE_CLIP
  69. // FL_COMPLEX_CLIP
  70. // FL_STYLED
  71. // FL_LAST_PEL_INCLUSIVE
  72. // - Should be set only for all integer lines,
  73. // and can't be used with FL_COMPLEX_CLIP
  74. ULONG ulHwMix)
  75. {
  76. ULONG M0;
  77. ULONG dM;
  78. ULONG N0;
  79. ULONG dN;
  80. ULONG dN_Original;
  81. FLONG fl;
  82. LONG x;
  83. LONG y;
  84. LONGLONG llBeta;
  85. LONGLONG llGamma;
  86. LONGLONG dl;
  87. LONGLONG ll;
  88. ULONG ulDelta;
  89. ULONG x0;
  90. ULONG y0;
  91. ULONG x1;
  92. ULONG cStylePels; // Major length of line in pixels for styling
  93. ULONG xStart;
  94. POINTL ptlStart;
  95. STRIP strip;
  96. PFNSTRIP pfn;
  97. LONG cPels;
  98. LONG* plStrip;
  99. LONG* plStripEnd;
  100. LONG cStripsInNextRun;
  101. POINTFIX* pptfxBufEnd = pptfxBuf + cptfx; // Last point in path record
  102. STYLEPOS spThis; // Style pos for this line
  103. BYTE* pjBase;
  104. pjBase = ppdev->pjBase;
  105. do {
  106. /***********************************************************************\
  107. * Start the DDA calculations. *
  108. \***********************************************************************/
  109. M0 = (LONG) pptfxFirst->x;
  110. dM = (LONG) pptfxBuf->x;
  111. N0 = (LONG) pptfxFirst->y;
  112. dN = (LONG) pptfxBuf->y;
  113. fl = flStart;
  114. // Check for non-clipped, non-styled integer endpoint lines
  115. if ((fl & (FL_CLIP | FL_STYLED)) == 0)
  116. {
  117. // Special-case integer end-point lines:
  118. if (((M0 | dM | N0 | dN) & (F - 1)) == 0)
  119. {
  120. LONG x0;
  121. LONG y0;
  122. LONG x1;
  123. LONG y1;
  124. x0 = M0 >> FLOG2;
  125. x1 = dM >> FLOG2;
  126. y0 = N0 >> FLOG2;
  127. y1 = dN >> FLOG2;
  128. // Unfortunately, we can only use the Weitek's point-
  129. // to-point capability for perfectly horizontal and
  130. // vertical lines, because for other lines the tie-
  131. // breaker rule comes into play, and the Weitek has
  132. // exactly the wrong tie-breaker convention.
  133. if (y0 == y1)
  134. {
  135. // Horizontal integer line. Do last-pel exclusion:
  136. if (x0 < x1)
  137. x1--;
  138. else if (x0 > x1)
  139. x1++;
  140. else
  141. goto Next_Line; // Zero-pel line
  142. CP_METALINE(ppdev, pjBase, x0, y0);
  143. CP_METALINE(ppdev, pjBase, x1, y1);
  144. CP_START_QUAD_WAIT(ppdev, pjBase);
  145. goto Next_Line;
  146. }
  147. else if (x0 == x1)
  148. {
  149. // Vertical integer line. Do last-pel exclusion:
  150. if (y0 < y1)
  151. y1--;
  152. else
  153. y1++;
  154. CP_METALINE(ppdev, pjBase, x0, y0);
  155. CP_METALINE(ppdev, pjBase, x1, y1);
  156. CP_START_QUAD_WAIT(ppdev, pjBase);
  157. goto Next_Line;
  158. }
  159. }
  160. }
  161. if ((LONG) M0 > (LONG) dM)
  162. {
  163. // Ensure that we run left-to-right:
  164. register ULONG ulTmp;
  165. SWAPL(M0, dM, ulTmp);
  166. SWAPL(N0, dN, ulTmp);
  167. fl |= FL_FLIP_H;
  168. }
  169. // Compute the delta dx. The DDI says we can never have a valid delta
  170. // with a magnitued more than 2^31 - 1, but GDI never actually checks
  171. // its transforms. So we have to check for this case to avoid overflow:
  172. dM -= M0;
  173. if ((LONG) dM < 0)
  174. {
  175. goto Next_Line;
  176. }
  177. if ((LONG) dN < (LONG) N0)
  178. {
  179. // Line runs from bottom to top, so flip across y = 0:
  180. N0 = -(LONG) N0;
  181. dN = -(LONG) dN;
  182. fl |= FL_FLIP_V;
  183. }
  184. dN -= N0;
  185. if ((LONG) dN < 0)
  186. {
  187. goto Next_Line;
  188. }
  189. // We now have a line running left-to-right, top-to-bottom from (M0, N0)
  190. // to (M0 + dM, N0 + dN):
  191. if (dN >= dM)
  192. {
  193. if (dN == dM)
  194. {
  195. // Have to special case slopes of one:
  196. fl |= FL_FLIP_SLOPE_ONE;
  197. }
  198. else
  199. {
  200. // Since line has slope greater than 1, flip across x = y:
  201. register ULONG ulTmp;
  202. SWAPL(dM, dN, ulTmp);
  203. SWAPL(M0, N0, ulTmp);
  204. fl |= FL_FLIP_D;
  205. }
  206. }
  207. fl |= gaflRound[(fl & FL_ROUND_MASK) >> FL_ROUND_SHIFT];
  208. x = LFLOOR((LONG) M0);
  209. y = LFLOOR((LONG) N0);
  210. M0 = FXFRAC(M0);
  211. N0 = FXFRAC(N0);
  212. // Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]:
  213. llGamma = UInt32x32To64(dM, N0 + F/2) - UInt32x32To64(M0, dN);
  214. if (fl & FL_V_ROUND_DOWN) // Adjust so y = 1/2 rounds down
  215. {
  216. llGamma--;
  217. }
  218. llGamma >>= FLOG2;
  219. llBeta = ~llGamma;
  220. /***********************************************************************\
  221. * Figure out which pixels are at the ends of the line. *
  222. \***********************************************************************/
  223. // The toughest part of GIQ is determining the start and end pels.
  224. //
  225. // Our approach here is to calculate x0 and x1 (the inclusive start
  226. // and end columns of the line respectively, relative to our normalized
  227. // origin). Then x1 - x0 + 1 is the number of pels in the line. The
  228. // start point is easily calculated by plugging x0 into our line equation
  229. // (which takes care of whether y = 1/2 rounds up or down in value)
  230. // getting y0, and then undoing the normalizing flips to get back
  231. // into device space.
  232. //
  233. // We look at the fractional parts of the coordinates of the start and
  234. // end points, and call them (M0, N0) and (M1, N1) respectively, where
  235. // 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid
  236. // to determine x0:
  237. //
  238. // +-----------------------> +x
  239. // |
  240. // | 0 1
  241. // | 0123456789abcdef
  242. // |
  243. // | 0 ........?xxxxxxx
  244. // | 1 ..........xxxxxx
  245. // | 2 ...........xxxxx
  246. // | 3 ............xxxx
  247. // | 4 .............xxx
  248. // | 5 ..............xx
  249. // | 6 ...............x
  250. // | 7 ................
  251. // | 8 ................
  252. // | 9 ......**........
  253. // | a ........****...x
  254. // | b ............****
  255. // | c .............xxx****
  256. // | d ............xxxx ****
  257. // | e ...........xxxxx ****
  258. // | f ..........xxxxxx
  259. // |
  260. // | 2 3
  261. // v
  262. //
  263. // +y
  264. //
  265. // This grid accounts for the appropriate rounding of GIQ and last-pel
  266. // exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands
  267. // on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
  268. // depending on what flips have been done to normalize the line.
  269. //
  270. // For the end point, if (M1, N1) lands on an 'x', x1 =
  271. // floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 =
  272. // floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
  273. // depending on what flips have been done to normalize the line.
  274. //
  275. // Lines of exactly slope one require a special case for both the start
  276. // and end. For example, if the line ends such that (M1, N1) is (9, 1),
  277. // the line has gone exactly through (8, 0) -- which may be considered
  278. // to be part of 'x' because of rounding! So slopes of exactly slope
  279. // one going through (8, 0) must also be considered as belonging in 'x'.
  280. //
  281. // For lines that go left-to-right, we have the following grid:
  282. //
  283. // +-----------------------> +x
  284. // |
  285. // | 0 1
  286. // | 0123456789abcdef
  287. // |
  288. // | 0 xxxxxxxx?.......
  289. // | 1 xxxxxxx.........
  290. // | 2 xxxxxx..........
  291. // | 3 xxxxx...........
  292. // | 4 xxxx............
  293. // | 5 xxx.............
  294. // | 6 xx..............
  295. // | 7 x...............
  296. // | 8 x...............
  297. // | 9 x.....**........
  298. // | a xx......****....
  299. // | b xxx.........****
  300. // | c xxxx............****
  301. // | d xxxxx........... ****
  302. // | e xxxxxx.......... ****
  303. // | f xxxxxxx.........
  304. // |
  305. // | 2 3
  306. // v
  307. //
  308. // +y
  309. //
  310. // This grid accounts for the appropriate rounding of GIQ and last-pel
  311. // exclusion. If (M0, N0) lands on an 'x', x0 = 0. If (M0, N0) lands
  312. // on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
  313. // depending on what flips have been done to normalize the line.
  314. //
  315. // For the end point, if (M1, N1) lands on an 'x', x1 =
  316. // floor((M0 + dM) / 16) - 1. If (M1, N1) lands on a '.', x1 =
  317. // floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
  318. // depending on what flips have been done to normalize the line.
  319. //
  320. // Lines of exactly slope one must be handled similarly to the right-to-
  321. // left case.
  322. {
  323. // Calculate x0, x1
  324. ULONG N1 = FXFRAC(N0 + dN);
  325. ULONG M1 = FXFRAC(M0 + dM);
  326. x1 = LFLOOR(M0 + dM);
  327. if (fl & FL_LAST_PEL_INCLUSIVE)
  328. {
  329. // It sure is easy to compute the first pel when lines have only
  330. // integer coordinates and are last-pel inclusive:
  331. x0 = 0;
  332. y0 = 0;
  333. // Last-pel inclusive lines that are exactly one pixel long
  334. // have a 'delta-x' and 'delta-y' equal to zero. The problem is
  335. // that our clip code assumes that 'delta-x' is always non-zero
  336. // (since it never happens with last-pel exclusive lines). As
  337. // an inelegant solution, we simply modify 'delta-x' in this
  338. // case -- because the line is exactly one pixel long, changing
  339. // the slope will obviously have no effect on rasterization.
  340. if (x1 == 0)
  341. {
  342. dM = 1;
  343. llGamma = 0;
  344. llBeta = ~llGamma;
  345. }
  346. }
  347. else
  348. {
  349. if (fl & FL_FLIP_H)
  350. {
  351. // ---------------------------------------------------------------
  352. // Line runs right-to-left: <----
  353. // Compute x1:
  354. if (N1 == 0)
  355. {
  356. if (LROUND(M1, fl & FL_H_ROUND_DOWN))
  357. {
  358. x1++;
  359. }
  360. }
  361. else if (abs((LONG) (N1 - F/2)) + M1 > F)
  362. {
  363. x1++;
  364. }
  365. if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
  366. == (FL_FLIP_SLOPE_ONE))
  367. {
  368. // Have to special-case diagonal lines going through our
  369. // the point exactly equidistant between two horizontal
  370. // pixels, if we're supposed to round x=1/2 down:
  371. if ((N1 > 0) && (M1 == N1 + 8))
  372. x1++;
  373. // Don't you love special cases? Is this a rhetorical question?
  374. if ((N0 > 0) && (M0 == N0 + 8))
  375. {
  376. x0 = 2;
  377. ulDelta = dN;
  378. goto right_to_left_compute_y0;
  379. }
  380. }
  381. // Compute x0:
  382. x0 = 1;
  383. ulDelta = 0;
  384. if (N0 == 0)
  385. {
  386. if (LROUND(M0, fl & FL_H_ROUND_DOWN))
  387. {
  388. x0 = 2;
  389. ulDelta = dN;
  390. }
  391. }
  392. else if (abs((LONG) (N0 - F/2)) + M0 > F)
  393. {
  394. x0 = 2;
  395. ulDelta = dN;
  396. }
  397. // Compute y0:
  398. right_to_left_compute_y0:
  399. y0 = 0;
  400. ll = llGamma + (LONGLONG) ulDelta;
  401. if (ll >= (LONGLONG) (2 * dM - dN))
  402. y0 = 2;
  403. else if (ll >= (LONGLONG) (dM - dN))
  404. y0 = 1;
  405. }
  406. else
  407. {
  408. // ---------------------------------------------------------------
  409. // Line runs left-to-right: ---->
  410. // Compute x1:
  411. if (!(fl & FL_LAST_PEL_INCLUSIVE))
  412. x1--;
  413. if (M1 > 0)
  414. {
  415. if (N1 == 0)
  416. {
  417. if (LROUND(M1, fl & FL_H_ROUND_DOWN))
  418. x1++;
  419. }
  420. else if (abs((LONG) (N1 - F/2)) <= (LONG) M1)
  421. {
  422. x1++;
  423. }
  424. }
  425. if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
  426. == (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
  427. {
  428. // Have to special-case diagonal lines going through our
  429. // the point exactly equidistant between two horizontal
  430. // pixels, if we're supposed to round x=1/2 down:
  431. if ((M1 > 0) && (N1 == M1 + 8))
  432. x1--;
  433. if ((M0 > 0) && (N0 == M0 + 8))
  434. {
  435. x0 = 0;
  436. goto left_to_right_compute_y0;
  437. }
  438. }
  439. // Compute x0:
  440. x0 = 0;
  441. if (M0 > 0)
  442. {
  443. if (N0 == 0)
  444. {
  445. if (LROUND(M0, fl & FL_H_ROUND_DOWN))
  446. x0 = 1;
  447. }
  448. else if (abs((LONG) (N0 - F/2)) <= (LONG) M0)
  449. {
  450. x0 = 1;
  451. }
  452. }
  453. // Compute y0:
  454. left_to_right_compute_y0:
  455. y0 = 0;
  456. if (llGamma >= (LONGLONG) (dM - (dN & (-(LONG) x0))))
  457. {
  458. y0 = 1;
  459. }
  460. }
  461. }
  462. }
  463. cStylePels = x1 - x0 + 1;
  464. if ((LONG) cStylePels <= 0)
  465. goto Next_Line;
  466. xStart = x0;
  467. /***********************************************************************\
  468. * Complex clipping. *
  469. \***********************************************************************/
  470. if (fl & FL_COMPLEX_CLIP)
  471. {
  472. dN_Original = dN;
  473. Continue_Complex_Clipping:
  474. if (fl & FL_FLIP_H)
  475. {
  476. // Line runs right-to-left <-----
  477. x0 = xStart + cStylePels - prun->iStop - 1;
  478. x1 = xStart + cStylePels - prun->iStart - 1;
  479. }
  480. else
  481. {
  482. // Line runs left-to-right ----->
  483. x0 = xStart + prun->iStart;
  484. x1 = xStart + prun->iStop;
  485. }
  486. prun++;
  487. // Reset some variables we'll nuke a little later:
  488. dN = dN_Original;
  489. pls->spNext = pls->spComplex;
  490. // No overflow since large integer math is used. Both values
  491. // will be positive:
  492. dl = UInt32x32To64(x0, dN) + llGamma;
  493. // y0 = dl / dM:
  494. y0 = UInt64Div32To32(dl, dM);
  495. ASSERTDD((LONG) y0 >= 0, "y0 weird: Goofed up end pel calc?");
  496. }
  497. /***********************************************************************\
  498. * Simple rectangular clipping. *
  499. \***********************************************************************/
  500. if (fl & FL_SIMPLE_CLIP)
  501. {
  502. ULONG y1;
  503. LONG xRight;
  504. LONG xLeft;
  505. LONG yBottom;
  506. LONG yTop;
  507. // Note that y0 and y1 are actually the lower and upper bounds,
  508. // respectively, of the y coordinates of the line (the line may
  509. // have actually shrunk due to first/last pel clipping).
  510. //
  511. // Also note that x0, y0 are not necessarily zero.
  512. RECTL* prcl = &prclClip[(fl & FL_RECTLCLIP_MASK) >>
  513. FL_RECTLCLIP_SHIFT];
  514. // Normalize to the same point we've normalized for the DDA
  515. // calculations:
  516. xRight = prcl->right - x;
  517. xLeft = prcl->left - x;
  518. yBottom = prcl->bottom - y;
  519. yTop = prcl->top - y;
  520. if (yBottom <= (LONG) y0 ||
  521. xRight <= (LONG) x0 ||
  522. xLeft > (LONG) x1)
  523. {
  524. Totally_Clipped:
  525. if (fl & FL_STYLED)
  526. {
  527. pls->spNext += cStylePels;
  528. if (pls->spNext >= pls->spTotal2)
  529. pls->spNext %= pls->spTotal2;
  530. }
  531. goto Next_Line;
  532. }
  533. if ((LONG) x1 >= xRight)
  534. x1 = xRight - 1;
  535. // We have to know the correct y1, which we haven't bothered to
  536. // calculate up until now. This multiply and divide is quite
  537. // expensive; we could replace it with code similar to that which
  538. // we used for computing y0.
  539. //
  540. // The reason why we need the actual value, and not an upper
  541. // bounds guess like y1 = LFLOOR(dM) + 2 is that we have to be
  542. // careful when calculating x(y) that y0 <= y <= y1, otherwise
  543. // we can overflow on the divide (which, needless to say, is very
  544. // bad).
  545. dl = UInt32x32To64(x1, dN) + llGamma;
  546. // y1 = dl / dM:
  547. y1 = UInt64Div32To32(dl, dM);
  548. if (yTop > (LONG) y1)
  549. goto Totally_Clipped;
  550. if (yBottom <= (LONG) y1)
  551. {
  552. y1 = yBottom;
  553. dl = UInt32x32To64(y1, dM) + llBeta;
  554. // x1 = dl / dN:
  555. x1 = UInt64Div32To32(dl, dN);
  556. }
  557. // At this point, we've taken care of calculating the intercepts
  558. // with the right and bottom edges. Now we work on the left and
  559. // top edges:
  560. if (xLeft > (LONG) x0)
  561. {
  562. x0 = xLeft;
  563. dl = UInt32x32To64(x0, dN) + llGamma;
  564. // y0 = dl / dM;
  565. y0 = UInt64Div32To32(dl, dM);
  566. if (yBottom <= (LONG) y0)
  567. goto Totally_Clipped;
  568. }
  569. if (yTop > (LONG) y0)
  570. {
  571. y0 = yTop;
  572. dl = UInt32x32To64(y0, dM) + llBeta;
  573. // x0 = dl / dN + 1;
  574. x0 = UInt64Div32To32(dl, dN) + 1;
  575. if (xRight <= (LONG) x0)
  576. goto Totally_Clipped;
  577. }
  578. ASSERTDD(x0 <= x1, "Improper rectangle clip");
  579. }
  580. /***********************************************************************\
  581. * Done clipping. Unflip if necessary. *
  582. \***********************************************************************/
  583. ptlStart.x = x + x0;
  584. ptlStart.y = y + y0;
  585. if (fl & FL_FLIP_D)
  586. {
  587. register LONG lTmp;
  588. SWAPL(ptlStart.x, ptlStart.y, lTmp);
  589. }
  590. if (fl & FL_FLIP_V)
  591. {
  592. ptlStart.y = -ptlStart.y;
  593. }
  594. cPels = x1 - x0 + 1;
  595. /***********************************************************************\
  596. * Style calculations. *
  597. \***********************************************************************/
  598. if (fl & FL_STYLED)
  599. {
  600. STYLEPOS sp;
  601. spThis = pls->spNext;
  602. pls->spNext += cStylePels;
  603. {
  604. if (pls->spNext >= pls->spTotal2)
  605. pls->spNext %= pls->spTotal2;
  606. if (fl & FL_FLIP_H)
  607. sp = pls->spNext - x0 + xStart;
  608. else
  609. sp = spThis + x0 - xStart;
  610. ASSERTDD(fl & FL_STYLED, "Oops");
  611. // Normalize our target style position:
  612. if ((sp < 0) || (sp >= pls->spTotal2))
  613. {
  614. sp %= pls->spTotal2;
  615. // The modulus of a negative number is not well-defined
  616. // in C -- if it's negative we'll adjust it so that it's
  617. // back in the range [0, spTotal2):
  618. if (sp < 0)
  619. sp += pls->spTotal2;
  620. }
  621. // Since we always draw the line left-to-right, but styling is
  622. // always done in the direction of the original line, we have
  623. // to figure out where we are in the style array for the left
  624. // edge of this line.
  625. if (fl & FL_FLIP_H)
  626. {
  627. // Line originally ran right-to-left:
  628. sp = -sp;
  629. if (sp < 0)
  630. sp += pls->spTotal2;
  631. pls->ulStyleMask = ~pls->ulStartMask;
  632. pls->pspStart = &pls->aspRtoL[0];
  633. pls->pspEnd = &pls->aspRtoL[pls->cStyle - 1];
  634. }
  635. else
  636. {
  637. // Line originally ran left-to-right:
  638. pls->ulStyleMask = pls->ulStartMask;
  639. pls->pspStart = &pls->aspLtoR[0];
  640. pls->pspEnd = &pls->aspLtoR[pls->cStyle - 1];
  641. }
  642. if (sp >= pls->spTotal)
  643. {
  644. sp -= pls->spTotal;
  645. if (pls->cStyle & 1)
  646. pls->ulStyleMask = ~pls->ulStyleMask;
  647. }
  648. pls->psp = pls->pspStart;
  649. while (sp >= *pls->psp)
  650. sp -= *pls->psp++;
  651. ASSERTDD(pls->psp <= pls->pspEnd,
  652. "Flew off into NeverNeverLand");
  653. pls->spRemaining = *pls->psp - sp;
  654. if ((pls->psp - pls->pspStart) & 1)
  655. pls->ulStyleMask = ~pls->ulStyleMask;
  656. }
  657. }
  658. plStrip = &strip.alStrips[0];
  659. plStripEnd = &strip.alStrips[STRIP_MAX]; // Is exclusive
  660. cStripsInNextRun = 0x7fffffff;
  661. strip.ptlStart = ptlStart;
  662. if (2 * dN > dM &&
  663. !(fl & FL_STYLED))
  664. {
  665. // Do a half flip! Remember that we may doing this on the
  666. // same line multiple times for complex clipping (meaning the
  667. // affected variables should be reset for every clip run):
  668. fl |= FL_FLIP_HALF;
  669. llBeta = llGamma - (LONGLONG) ((LONG) dM);
  670. dN = dM - dN;
  671. y0 = x0 - y0; // Note this may overflow, but that's okay
  672. }
  673. // Now, run the DDA starting at (ptlStart.x, ptlStart.y)!
  674. strip.flFlips = fl;
  675. pfn = apfn[(fl & FL_STRIP_MASK) >> FL_STRIP_SHIFT];
  676. // Now calculate the DDA variables needed to figure out how many pixels
  677. // go in the very first strip:
  678. {
  679. register LONG i;
  680. register ULONG dI;
  681. register ULONG dR;
  682. ULONG r;
  683. if (dN == 0)
  684. i = 0x7fffffff;
  685. else
  686. {
  687. dl = UInt32x32To64(y0 + 1, dM) + llBeta;
  688. ASSERTDD(dl >= 0, "Oops!");
  689. // i = (dl / dN) - x0 + 1;
  690. // r = (dl % dN);
  691. i = UInt64Div32To32(dl, dN);
  692. r = UInt64Mod32To32(dl, dN);
  693. i = i - x0 + 1;
  694. dI = dM / dN;
  695. dR = dM % dN; // 0 <= dR < dN
  696. ASSERTDD(dI > 0, "Weird dI");
  697. }
  698. ASSERTDD(i > 0 && i <= 0x7fffffff, "Weird initial strip length");
  699. ASSERTDD(cPels > 0, "Zero pel line");
  700. /***********************************************************************\
  701. * Run the DDA! *
  702. \***********************************************************************/
  703. while(TRUE)
  704. {
  705. cPels -= i;
  706. if (cPels <= 0)
  707. break;
  708. *plStrip++ = i;
  709. if (plStrip == plStripEnd)
  710. {
  711. strip.cStrips = (LONG)(plStrip - &strip.alStrips[0]);
  712. (*pfn)(ppdev, &strip, pls);
  713. plStrip = &strip.alStrips[0];
  714. }
  715. i = dI;
  716. r += dR;
  717. if (r >= dN)
  718. {
  719. r -= dN;
  720. i++;
  721. }
  722. }
  723. *plStrip++ = cPels + i;
  724. strip.cStrips = (ULONG)(plStrip - &strip.alStrips[0]);
  725. (*pfn)(ppdev, &strip, pls);
  726. }
  727. Next_Line:
  728. if (fl & FL_COMPLEX_CLIP)
  729. {
  730. cptfx--;
  731. if (cptfx != 0)
  732. goto Continue_Complex_Clipping;
  733. break;
  734. }
  735. else
  736. {
  737. pptfxFirst = pptfxBuf;
  738. pptfxBuf++;
  739. }
  740. } while (pptfxBuf < pptfxBufEnd);
  741. return(TRUE);
  742. }
  743. /******************************Public*Routine******************************\
  744. * BOOL bIntegerUnclippedLines
  745. *
  746. * Draws lines using the Weitek's point-to-point capabilities.
  747. * Unfortunately, the Weitek has exactly the wrong rounding convention
  748. * for tie-breakers, and GDI is very picky about this.
  749. *
  750. * Consequently, we can only use the line hardware when we know there
  751. * will be no tie-breakers. Fortunately, this is pretty easy to detect,
  752. * and the odds are that 3 out of 4 lines will not have tie breakers. For
  753. * those cases where there are tie-breakers, we can still usually draw the
  754. * lines using the hardware, this time by doing a one-wide trapezoid.
  755. * Unfortunately, this works for only 6 of the 8 octants, so for the final
  756. * case we punt to our strips routine.
  757. *
  758. * Additional complications include the fact that lines have to be last-pel
  759. * exclusive, and that we try to optimize horizontal and vertical lines.
  760. *
  761. \**************************************************************************/
  762. BOOL bIntegerUnclippedLines(
  763. PDEV* ppdev,
  764. POINTFIX* pptfxFirst,
  765. POINTFIX* pptfxBuf,
  766. RUN* prun,
  767. ULONG cptfx,
  768. LINESTATE* pls,
  769. RECTL* prclClip,
  770. PFNSTRIP* apfn,
  771. FLONG flStart,
  772. ULONG ulHwMix)
  773. {
  774. BYTE* pjBase;
  775. BOOL bClippingSet;
  776. ULONG ulLineMix;
  777. ULONG ulTrapezoidMix;
  778. LONG x0;
  779. LONG y0;
  780. LONG x1;
  781. LONG y1;
  782. LONG xLeft;
  783. LONG xRight;
  784. LONG yTop;
  785. LONG yBottom;
  786. LONG dx;
  787. LONG dy;
  788. LONG lOr;
  789. LONG lBit;
  790. LONG iShift;
  791. LONG xDir;
  792. LONG yDir;
  793. pjBase = ppdev->pjBase;
  794. bClippingSet = FALSE;
  795. if (P9000(ppdev))
  796. {
  797. ulTrapezoidMix = ulHwMix;
  798. ulLineMix = ulTrapezoidMix | P9000_OVERSIZED;
  799. }
  800. else
  801. {
  802. ulTrapezoidMix = ulHwMix & 0xff;
  803. ulLineMix = ulTrapezoidMix | P9100_OVERSIZED;
  804. }
  805. while (TRUE)
  806. {
  807. x0 = pptfxFirst->x;
  808. y0 = pptfxFirst->y;
  809. x1 = pptfxBuf->x;
  810. y1 = pptfxBuf->y;
  811. // First, check to see if the line is has all-integer coordinates:
  812. if (((x0 | y0 | x1 | y1) & 0xf) != 0)
  813. {
  814. // Ack, this line has non-integer coordinates. The rest of the
  815. // lines in this batch likely have non-integer coordinates
  816. // as well, so punt the entire batch to our strips routine:
  817. if (bClippingSet)
  818. {
  819. CP_WAIT(ppdev, pjBase);
  820. CP_RASTER(ppdev, pjBase, ulLineMix);
  821. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  822. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  823. }
  824. return(bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
  825. prclClip, apfn, flStart, ulHwMix));
  826. }
  827. else
  828. {
  829. x0 >>= 4;
  830. x1 >>= 4;
  831. y0 >>= 4;
  832. y1 >>= 4;
  833. if ((y0 == y1) && (!bClippingSet))
  834. {
  835. // We special case horizontal lines:
  836. if (x0 < x1)
  837. x1--;
  838. else if (x0 > x1)
  839. x1++;
  840. else
  841. goto Next_Line; // Zero-length line
  842. CP_METALINE(ppdev, pjBase, x0, y0);
  843. CP_METALINE(ppdev, pjBase, x1, y0);
  844. CP_START_QUAD_WAIT(ppdev, pjBase);
  845. goto Next_Line;
  846. }
  847. else if (y0 < y1)
  848. {
  849. yTop = y0;
  850. yBottom = y1;
  851. }
  852. else
  853. {
  854. yBottom = y0;
  855. yTop = y1;
  856. }
  857. if ((x0 == x1) && (!bClippingSet))
  858. {
  859. // We special case vertical lines:
  860. if (y0 < y1)
  861. y1--;
  862. else
  863. y1++;
  864. CP_METALINE(ppdev, pjBase, x0, y0);
  865. CP_METALINE(ppdev, pjBase, x0, y1);
  866. CP_START_QUAD_WAIT(ppdev, pjBase);
  867. goto Next_Line;
  868. }
  869. else if (x0 < x1)
  870. {
  871. xLeft = x0;
  872. xRight = x1;
  873. }
  874. else
  875. {
  876. xRight = x0;
  877. xLeft = x1;
  878. }
  879. dx = xRight - xLeft;
  880. dy = yBottom - yTop;
  881. if (dx >= dy)
  882. {
  883. if (dx == 0)
  884. goto Next_Line; // Get rid of zero-length line case
  885. // We have an x-major line. Adjust the clip box to
  886. // account for last-pel exclusion:
  887. if (x0 < x1)
  888. xRight--;
  889. else
  890. xLeft++;
  891. lOr = (dx | dy);
  892. lBit = 1;
  893. iShift = 1;
  894. while (!(lOr & lBit))
  895. {
  896. lBit <<= 1;
  897. iShift++;
  898. }
  899. if (dx & lBit)
  900. {
  901. Output_Simple_Line:
  902. CP_METALINE(ppdev, pjBase, x0, y0);
  903. CP_METALINE(ppdev, pjBase, x1, y1);
  904. CP_WAIT(ppdev, pjBase);
  905. CP_RASTER(ppdev, pjBase, ulLineMix);
  906. CP_WMIN(ppdev, pjBase, xLeft, yTop);
  907. CP_WMAX(ppdev, pjBase, xRight, yBottom);
  908. CP_START_QUAD_WAIT(ppdev, pjBase);
  909. bClippingSet = TRUE;
  910. goto Next_Line;
  911. }
  912. else
  913. {
  914. if ((dx ^ dy) > 0)
  915. goto Punt_Line;
  916. // Ick, this x-major line has tie-breaker cases.
  917. xDir = 0;
  918. yDir = 1;
  919. dy >>= iShift;
  920. if (y0 > y1)
  921. {
  922. dy = -dy;
  923. yDir = -1;
  924. }
  925. y0 -= dy;
  926. y1 += dy;
  927. dx >>= iShift;
  928. if (x0 > x1)
  929. dx = -dx;
  930. x0 -= dx;
  931. x1 += dx;
  932. Output_Trapezoid_Line:
  933. CP_METAQUAD(ppdev, pjBase, x0, y0);
  934. CP_METAQUAD(ppdev, pjBase, x1 + xDir, y1 - yDir);
  935. CP_METAQUAD(ppdev, pjBase, x1, y1);
  936. CP_METAQUAD(ppdev, pjBase, x0 - xDir, y0 + yDir);
  937. CP_WAIT(ppdev, pjBase);
  938. CP_RASTER(ppdev, pjBase, ulTrapezoidMix);
  939. CP_WMIN(ppdev, pjBase, xLeft, yTop);
  940. CP_WMAX(ppdev, pjBase, xRight, yBottom);
  941. CP_START_QUAD_WAIT(ppdev, pjBase);
  942. bClippingSet = TRUE;
  943. goto Next_Line;
  944. }
  945. }
  946. else
  947. {
  948. // We have a y-major line. Adjust the clip box to
  949. // account for last-pel exclusion:
  950. if (y0 < y1)
  951. yBottom--;
  952. else
  953. yTop++;
  954. lOr = (dx | dy);
  955. lBit = 1;
  956. iShift = 1;
  957. while (!(lOr & lBit))
  958. {
  959. lBit <<= 1;
  960. iShift++;
  961. }
  962. if (dy & lBit)
  963. {
  964. goto Output_Simple_Line;
  965. }
  966. else
  967. {
  968. // Ick, this y-major line has tie-breaker cases.
  969. yDir = 0;
  970. xDir = 1;
  971. dx >>= iShift;
  972. if (x0 > x1)
  973. {
  974. dx = -dx;
  975. xDir = -1;
  976. }
  977. x0 -= dx;
  978. x1 += dx;
  979. dy >>= iShift;
  980. if (y0 > y1)
  981. dy = -dy;
  982. y0 -= dy;
  983. y1 += dy;
  984. goto Output_Trapezoid_Line;
  985. }
  986. }
  987. }
  988. Punt_Line:
  989. if (bClippingSet)
  990. {
  991. CP_WAIT(ppdev, pjBase);
  992. CP_RASTER(ppdev, pjBase, ulLineMix);
  993. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  994. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  995. bClippingSet = FALSE;
  996. }
  997. bLines(ppdev, pptfxFirst, pptfxBuf, NULL, 1, pls,
  998. prclClip, apfn, flStart, ulHwMix);
  999. Next_Line:
  1000. --cptfx;
  1001. if (cptfx == 0)
  1002. break;
  1003. pptfxFirst = pptfxBuf;
  1004. pptfxBuf++;
  1005. }
  1006. if (bClippingSet)
  1007. {
  1008. CP_WAIT(ppdev, pjBase);
  1009. CP_RASTER(ppdev, pjBase, ulLineMix); // Might need for next batch
  1010. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  1011. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  1012. }
  1013. return(TRUE);
  1014. }
  1015. /******************************Public*Routine******************************\
  1016. * BOOL bIntegerClippedLines
  1017. *
  1018. * Draws lines using the hardware when there is a single clipping rectangle.
  1019. * See 'bIntegerUnclippedLines' above for more details.
  1020. *
  1021. \**************************************************************************/
  1022. BOOL bIntegerClippedLines(
  1023. PDEV* ppdev,
  1024. POINTFIX* pptfxFirst,
  1025. POINTFIX* pptfxBuf,
  1026. RUN* prun,
  1027. ULONG cptfx,
  1028. LINESTATE* pls,
  1029. RECTL* prclClip,
  1030. PFNSTRIP* apfn,
  1031. FLONG flStart,
  1032. ULONG ulHwMix)
  1033. {
  1034. BYTE* pjBase;
  1035. BOOL bClippingSet;
  1036. ULONG ulLineMix;
  1037. ULONG ulTrapezoidMix;
  1038. LONG x0;
  1039. LONG y0;
  1040. LONG x1;
  1041. LONG y1;
  1042. LONG xLeft;
  1043. LONG xRight;
  1044. LONG yTop;
  1045. LONG yBottom;
  1046. LONG dx;
  1047. LONG dy;
  1048. LONG lOr;
  1049. LONG lBit;
  1050. LONG iShift;
  1051. LONG xDir;
  1052. LONG yDir;
  1053. ASSERTDD(flStart & FL_SIMPLE_CLIP, "Expected only simple clipping");
  1054. pjBase = ppdev->pjBase;
  1055. bClippingSet = FALSE;
  1056. if (P9000(ppdev))
  1057. {
  1058. ulTrapezoidMix = ulHwMix;
  1059. ulLineMix = ulTrapezoidMix | P9000_OVERSIZED;
  1060. }
  1061. else
  1062. {
  1063. ulTrapezoidMix = ulHwMix & 0xff;
  1064. ulLineMix = ulTrapezoidMix | P9100_OVERSIZED;
  1065. }
  1066. while (TRUE)
  1067. {
  1068. x0 = pptfxFirst->x;
  1069. y0 = pptfxFirst->y;
  1070. x1 = pptfxBuf->x;
  1071. y1 = pptfxBuf->y;
  1072. // First, check to see if the line is has all-integer coordinates:
  1073. if (((x0 | y0 | x1 | y1) & 0xf) != 0)
  1074. {
  1075. // Ack, this line has non-integer coordinates. The rest of the
  1076. // lines in this batch likely have non-integer coordinates
  1077. // as well, so punt the entire batch to our strips routine:
  1078. if (bClippingSet)
  1079. {
  1080. CP_WAIT(ppdev, pjBase);
  1081. CP_RASTER(ppdev, pjBase, ulLineMix);
  1082. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  1083. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  1084. }
  1085. return(bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
  1086. prclClip, apfn, flStart, ulHwMix));
  1087. }
  1088. else
  1089. {
  1090. x0 >>= 4;
  1091. x1 >>= 4;
  1092. y0 >>= 4;
  1093. y1 >>= 4;
  1094. if (y0 < y1)
  1095. {
  1096. yTop = y0;
  1097. yBottom = y1;
  1098. }
  1099. else
  1100. {
  1101. yBottom = y0;
  1102. yTop = y1;
  1103. }
  1104. if (x0 < x1)
  1105. {
  1106. xLeft = x0;
  1107. xRight = x1;
  1108. }
  1109. else
  1110. {
  1111. xRight = x0;
  1112. xLeft = x1;
  1113. }
  1114. // Do a trivial rejection test, remembering that the bound box
  1115. // we just computed is lower-right inclusive:
  1116. if ((xLeft >= prclClip->right) ||
  1117. (yTop >= prclClip->bottom) ||
  1118. (xRight < prclClip->left) ||
  1119. (yBottom < prclClip->top))
  1120. {
  1121. goto Next_Line;
  1122. }
  1123. else
  1124. {
  1125. dx = xRight - xLeft;
  1126. dy = yBottom - yTop;
  1127. if (dx >= dy)
  1128. {
  1129. if (dx == 0)
  1130. goto Next_Line; // Get rid of zero-length line case
  1131. // We have an x-major line. Adjust the clip box to
  1132. // account for last-pel exclusion:
  1133. if (x0 < x1)
  1134. xRight--;
  1135. else
  1136. xLeft++;
  1137. lOr = (dx | dy);
  1138. lBit = 1;
  1139. iShift = 1;
  1140. while (!(lOr & lBit))
  1141. {
  1142. lBit <<= 1;
  1143. iShift++;
  1144. }
  1145. // The Weitek's clip registers are inclusive, and
  1146. // are expected to be well-ordered:
  1147. xLeft = max(xLeft, prclClip->left);
  1148. yTop = max(yTop, prclClip->top);
  1149. xRight = min(xRight, prclClip->right - 1);
  1150. yBottom = min(yBottom, prclClip->bottom - 1);
  1151. if ((xLeft <= xRight) && (yTop <= yBottom))
  1152. {
  1153. if (dx & lBit)
  1154. {
  1155. Output_Simple_Line:
  1156. CP_METALINE(ppdev, pjBase, x0, y0);
  1157. CP_METALINE(ppdev, pjBase, x1, y1);
  1158. CP_WAIT(ppdev, pjBase);
  1159. CP_RASTER(ppdev, pjBase, ulLineMix);
  1160. CP_WMIN(ppdev, pjBase, xLeft, yTop);
  1161. CP_WMAX(ppdev, pjBase, xRight, yBottom);
  1162. CP_START_QUAD_WAIT(ppdev, pjBase);
  1163. bClippingSet = TRUE;
  1164. goto Next_Line;
  1165. }
  1166. else
  1167. {
  1168. if ((dx ^ dy) > 0)
  1169. goto Punt_Line;
  1170. // Ick, this x-major line has tie-breaker cases.
  1171. xDir = 0;
  1172. yDir = 1;
  1173. dy >>= iShift;
  1174. if (y0 > y1)
  1175. {
  1176. dy = -dy;
  1177. yDir = -1;
  1178. }
  1179. y0 -= dy;
  1180. y1 += dy;
  1181. dx >>= iShift;
  1182. if (x0 > x1)
  1183. dx = -dx;
  1184. x0 -= dx;
  1185. x1 += dx;
  1186. Output_Trapezoid_Line:
  1187. CP_METAQUAD(ppdev, pjBase, x0, y0);
  1188. CP_METAQUAD(ppdev, pjBase, x1 + xDir, y1 - yDir);
  1189. CP_METAQUAD(ppdev, pjBase, x1, y1);
  1190. CP_METAQUAD(ppdev, pjBase, x0 - xDir, y0 + yDir);
  1191. CP_WAIT(ppdev, pjBase);
  1192. CP_RASTER(ppdev, pjBase, ulTrapezoidMix);
  1193. CP_WMIN(ppdev, pjBase, xLeft, yTop);
  1194. CP_WMAX(ppdev, pjBase, xRight, yBottom);
  1195. CP_START_QUAD_WAIT(ppdev, pjBase);
  1196. bClippingSet = TRUE;
  1197. goto Next_Line;
  1198. }
  1199. }
  1200. }
  1201. else
  1202. {
  1203. // We have a y-major line. Adjust the clip box to
  1204. // account for last-pel exclusion:
  1205. if (y0 < y1)
  1206. yBottom--;
  1207. else
  1208. yTop++;
  1209. lOr = (dx | dy);
  1210. lBit = 1;
  1211. iShift = 1;
  1212. while (!(lOr & lBit))
  1213. {
  1214. lBit <<= 1;
  1215. iShift++;
  1216. }
  1217. // The Weitek's clip registers are inclusive, and
  1218. // are expected to be well-ordered:
  1219. xLeft = max(xLeft, prclClip->left);
  1220. yTop = max(yTop, prclClip->top);
  1221. xRight = min(xRight, prclClip->right - 1);
  1222. yBottom = min(yBottom, prclClip->bottom - 1);
  1223. if ((xLeft <= xRight) && (yTop <= yBottom))
  1224. {
  1225. if (dy & lBit)
  1226. {
  1227. goto Output_Simple_Line;
  1228. }
  1229. else
  1230. {
  1231. // Ick, this y-major line has tie-breaker cases.
  1232. yDir = 0;
  1233. xDir = 1;
  1234. dx >>= iShift;
  1235. if (x0 > x1)
  1236. {
  1237. dx = -dx;
  1238. xDir = -1;
  1239. }
  1240. x0 -= dx;
  1241. x1 += dx;
  1242. dy >>= iShift;
  1243. if (y0 > y1)
  1244. dy = -dy;
  1245. y0 -= dy;
  1246. y1 += dy;
  1247. goto Output_Trapezoid_Line;
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. Punt_Line:
  1254. if (bClippingSet)
  1255. {
  1256. CP_WAIT(ppdev, pjBase);
  1257. CP_RASTER(ppdev, pjBase, ulLineMix);
  1258. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  1259. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  1260. bClippingSet = FALSE;
  1261. }
  1262. bLines(ppdev, pptfxFirst, pptfxBuf, NULL, 1, pls,
  1263. prclClip, apfn, flStart, ulHwMix);
  1264. Next_Line:
  1265. --cptfx;
  1266. if (cptfx == 0)
  1267. break;
  1268. pptfxFirst = pptfxBuf;
  1269. pptfxBuf++;
  1270. }
  1271. if (bClippingSet)
  1272. {
  1273. CP_WAIT(ppdev, pjBase);
  1274. CP_RASTER(ppdev, pjBase, ulLineMix); // Might need for next batch
  1275. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  1276. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  1277. }
  1278. return(TRUE);
  1279. }
  1280. /******************************Public*Routine******************************\
  1281. * BOOL bCacheCircle(ppdev, ppo, pco, pbo, bStroke, pla)
  1282. *
  1283. \**************************************************************************/
  1284. BOOL bCacheCircle(
  1285. PDEV* ppdev,
  1286. PATHOBJ* ppo,
  1287. CLIPOBJ* pco,
  1288. BRUSHOBJ* pbo,
  1289. BOOL bStroke, // TRUE if stroke, FALSE if fill
  1290. LINEATTRS* pla) // Used for strokes only
  1291. {
  1292. RECTFX rcfx;
  1293. LONG xCircle;
  1294. LONG yCircle;
  1295. LONG xCached;
  1296. LONG yCached;
  1297. LONG cx;
  1298. LONG cy;
  1299. CIRCLEENTRY* pce;
  1300. LONG i;
  1301. BYTE* pjBase;
  1302. RECTL rclDst;
  1303. POINTL ptlSrc;
  1304. ULONG ulHwMix;
  1305. RECTL rclTmp;
  1306. CLIPENUM ce;
  1307. LONG c;
  1308. LONG bMore;
  1309. LONG iCircleCache;
  1310. SURFOBJ* pso;
  1311. CLIPOBJ co;
  1312. BRUSHOBJ bo;
  1313. if (!(ppdev->flStat & STAT_CIRCLE_CACHE))
  1314. return(FALSE);
  1315. PATHOBJ_vGetBounds(ppo, &rcfx);
  1316. // Normalize bounds to upper-left corner:
  1317. xCircle = rcfx.xLeft & ~0xfL;
  1318. yCircle = rcfx.yTop & ~0xfL;
  1319. rcfx.xLeft -= xCircle;
  1320. rcfx.xRight -= xCircle;
  1321. rcfx.yTop -= yCircle;
  1322. rcfx.yBottom -= yCircle;
  1323. // Convert to pixel units:
  1324. xCircle >>= 4;
  1325. yCircle >>= 4;
  1326. cx = (rcfx.xRight >> 4) + 2;
  1327. cy = (rcfx.yBottom >> 4) + 2;
  1328. if ((cx > CIRCLE_DIMENSION) || (cy > CIRCLE_DIMENSION))
  1329. {
  1330. // This circle is too big to cache, so decline it:
  1331. return(FALSE);
  1332. }
  1333. pjBase = ppdev->pjBase;
  1334. pce = &ppdev->ace[0];
  1335. for (i = TOTAL_CIRCLE_COUNT; i != 0; i--)
  1336. {
  1337. if ((pce->bStroke == bStroke) &&
  1338. (pce->rcfxCircle.xLeft == rcfx.xLeft) &&
  1339. (pce->rcfxCircle.yTop == rcfx.yTop) &&
  1340. (pce->rcfxCircle.xRight == rcfx.xRight) &&
  1341. (pce->rcfxCircle.yBottom == rcfx.yBottom))
  1342. {
  1343. Draw_It:
  1344. // We got a hit! Colour-expand from our off-screen
  1345. // cache to the screen:
  1346. rclDst.left = xCircle;
  1347. rclDst.right = xCircle + cx;
  1348. rclDst.top = yCircle;
  1349. rclDst.bottom = yCircle + cy;
  1350. // 'ptlSrc' has to be in relative coordinates:
  1351. ptlSrc.x = pce->xCached - ppdev->xOffset;
  1352. ptlSrc.y = pce->yCached - ppdev->yOffset;
  1353. CP_WAIT(ppdev, pjBase);
  1354. if (P9000(ppdev))
  1355. {
  1356. CP_FOREGROUND(ppdev, pjBase, pbo->iSolidColor);
  1357. ulHwMix = 0xee22;
  1358. }
  1359. else
  1360. {
  1361. CP_COLOR0(ppdev, pjBase, pbo->iSolidColor);
  1362. ulHwMix = 0xe2e2;
  1363. }
  1364. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1365. {
  1366. ppdev->pfnCopyBlt(ppdev, 1, &rclDst, ulHwMix, &ptlSrc, &rclDst);
  1367. }
  1368. else if (pco->iDComplexity == DC_RECT)
  1369. {
  1370. if (bIntersect(&rclDst, &pco->rclBounds, &rclTmp))
  1371. ppdev->pfnCopyBlt(ppdev, 1, &rclTmp, ulHwMix, &ptlSrc, &rclDst);
  1372. }
  1373. else
  1374. {
  1375. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  1376. do {
  1377. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  1378. c = cIntersect(&rclDst, ce.arcl, ce.c);
  1379. if (c != 0)
  1380. ppdev->pfnCopyBlt(ppdev, c, ce.arcl, ulHwMix, &ptlSrc, &rclDst);
  1381. } while (bMore);
  1382. }
  1383. return(TRUE);
  1384. }
  1385. }
  1386. // Make an entry in our cache:
  1387. iCircleCache = ppdev->iCircleCache;
  1388. if (++iCircleCache >= TOTAL_CIRCLE_COUNT)
  1389. iCircleCache = 0;
  1390. ppdev->iCircleCache = iCircleCache;
  1391. pce = &ppdev->ace[iCircleCache];
  1392. // We must place the circle in off-screen memory with the same dword
  1393. // alignment as the one we've been asked to draw, because we're
  1394. // going to have GDI draw there instead:
  1395. xCached = pce->x + (xCircle & 3);
  1396. yCached = pce->y;
  1397. // Store all the relevant information about the circle:
  1398. pce->xCached = xCached;
  1399. pce->yCached = yCached;
  1400. pce->bStroke = bStroke;
  1401. pce->rcfxCircle.xLeft = rcfx.xLeft;
  1402. pce->rcfxCircle.yTop = rcfx.yTop;
  1403. pce->rcfxCircle.xRight = rcfx.xRight;
  1404. pce->rcfxCircle.yBottom = rcfx.yBottom;
  1405. // Fudge up some parameters for the GDI call:
  1406. pso = ppdev->psoPunt;
  1407. pso->pvScan0 = ppdev->pjScreen
  1408. + ((yCached - yCircle) * ppdev->lDelta)
  1409. + ((xCached - xCircle) * ppdev->cjPel);
  1410. ASSERTDD((((ULONG_PTR) pso->pvScan0) & 0x3) == 0,
  1411. "Surface must have dword alignment");
  1412. co.iDComplexity = DC_TRIVIAL;
  1413. bo.iSolidColor = ppdev->ulWhite;
  1414. // Erase old thing:
  1415. CP_ABS_METARECT(ppdev, pjBase, xCached, yCached);
  1416. CP_ABS_METARECT(ppdev, pjBase, xCached + CIRCLE_DIMENSION,
  1417. yCached + CIRCLE_DIMENSION);
  1418. CP_WAIT(ppdev, pjBase);
  1419. CP_RASTER(ppdev, pjBase, 0); // Same on both P9000 and P9100
  1420. CP_START_QUAD(ppdev, pjBase);
  1421. // Get GDI to draw the circle in our off-screen cache:
  1422. if (bStroke)
  1423. {
  1424. EngStrokePath(pso, ppo, &co, NULL, &bo, NULL, pla, 0x0d0d);
  1425. }
  1426. else
  1427. {
  1428. EngFillPath(pso, ppo, &co, &bo, NULL, 0x0d0d, FP_ALTERNATEMODE);
  1429. }
  1430. goto Draw_It;
  1431. }
  1432. VOID (*gapfnStrip[])(PDEV*, STRIP*, LINESTATE*) = {
  1433. vStripSolidHorizontal,
  1434. vStripSolidVertical,
  1435. vStripSolidDiagonalHorizontal,
  1436. vStripSolidDiagonalVertical,
  1437. vStripStyledHorizontal,
  1438. vStripStyledVertical,
  1439. vStripStyledVertical, // Diagonal goes here
  1440. vStripStyledVertical, // Diagonal goes here
  1441. };
  1442. // Style array for alternate style (alternates one pixel on, one pixel off):
  1443. STYLEPOS gaspAlternateStyle[] = { 1 };
  1444. /******************************Public*Routine******************************\
  1445. * BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix)
  1446. *
  1447. * Strokes the path.
  1448. *
  1449. \**************************************************************************/
  1450. BOOL DrvStrokePath(
  1451. SURFOBJ* pso,
  1452. PATHOBJ* ppo,
  1453. CLIPOBJ* pco,
  1454. XFORMOBJ* pxo,
  1455. BRUSHOBJ* pbo,
  1456. POINTL* pptlBrush,
  1457. LINEATTRS* pla,
  1458. MIX mix)
  1459. {
  1460. STYLEPOS aspLtoR[STYLE_MAX_COUNT];
  1461. STYLEPOS aspRtoL[STYLE_MAX_COUNT];
  1462. LINESTATE ls;
  1463. PFNSTRIP* apfn;
  1464. PFNLINES pfnLines;
  1465. FLONG fl;
  1466. PDEV* ppdev;
  1467. DSURF* pdsurf;
  1468. OH* poh;
  1469. RECTL arclClip[4]; // For rectangular clipping
  1470. BYTE* pjBase;
  1471. RECTL* prclClip;
  1472. ULONG ulHwMix;
  1473. ASSERTDD(((mix >> 8) & 0xff) == (mix & 0xff),
  1474. "GDI gave us an improper mix");
  1475. // Pass the surface off to GDI if it's a device bitmap that we've
  1476. // converted to a DIB:
  1477. pdsurf = (DSURF*) pso->dhsurf;
  1478. if (pdsurf->dt == DT_DIB)
  1479. {
  1480. return(EngStrokePath(pdsurf->pso, ppo, pco, pxo, pbo, pptlBrush,
  1481. pla, mix));
  1482. }
  1483. // We'll be drawing to the screen or an off-screen DFB; copy the surface's
  1484. // offset now so that we won't need to refer to the DSURF again:
  1485. poh = pdsurf->poh;
  1486. ppdev = (PDEV*) pso->dhpdev;
  1487. ppdev->xOffset = poh->x;
  1488. ppdev->yOffset = poh->y;
  1489. // Because we set GCAPS_BEZIERS, we have to watch out for Beziers:
  1490. if (ppo->fl & PO_BEZIERS)
  1491. {
  1492. // We only try to cache solid-styled COPYPEN ellipses:
  1493. if ((ppo->fl & PO_ELLIPSE) &&
  1494. (mix == 0x0d0d) &&
  1495. !(pla->fl & LA_ALTERNATE) &&
  1496. (pla->pstyle == NULL))
  1497. {
  1498. if (bCacheCircle(ppdev, ppo, pco, pbo, TRUE, pla))
  1499. return(TRUE);
  1500. }
  1501. // Get GDI to break the Beziers into lines before calling us
  1502. // again:
  1503. return(FALSE);
  1504. }
  1505. pfnLines = bLines;
  1506. if ((pla->pstyle == NULL) && !(pla->fl & LA_ALTERNATE))
  1507. {
  1508. // We can accelerate solid lines:
  1509. if (pco->iDComplexity == DC_TRIVIAL)
  1510. {
  1511. pfnLines = bIntegerUnclippedLines;
  1512. }
  1513. else if (pco->iDComplexity == DC_RECT)
  1514. {
  1515. RECTFX rcfxBounds;
  1516. // We have to be sure that we don't overflow the hardware registers
  1517. // for current position, line length, or DDA terms. We check
  1518. // here to make sure that the current position and line length
  1519. // values won't overflow:
  1520. PATHOBJ_vGetBounds(ppo, &rcfxBounds);
  1521. if (rcfxBounds.xLeft + (ppdev->xOffset * F)
  1522. >= (MIN_INTEGER_BOUND * F) &&
  1523. rcfxBounds.xRight + (ppdev->xOffset * F)
  1524. <= (MAX_INTEGER_BOUND * F) &&
  1525. rcfxBounds.yTop + (ppdev->yOffset * F)
  1526. >= (MIN_INTEGER_BOUND * F) &&
  1527. rcfxBounds.yBottom + (ppdev->yOffset * F)
  1528. <= (MAX_INTEGER_BOUND * F))
  1529. {
  1530. pfnLines = bIntegerClippedLines;
  1531. }
  1532. }
  1533. }
  1534. pjBase = ppdev->pjBase;
  1535. prclClip = NULL;
  1536. fl = 0;
  1537. // Look after styling initialization:
  1538. if (pla->fl & LA_ALTERNATE)
  1539. {
  1540. ls.cStyle = 1;
  1541. ls.spTotal = 1;
  1542. ls.spTotal2 = 2;
  1543. ls.spRemaining = 1;
  1544. ls.aspRtoL = &gaspAlternateStyle[0];
  1545. ls.aspLtoR = &gaspAlternateStyle[0];
  1546. ls.spNext = HIWORD(pla->elStyleState.l);
  1547. ls.xyDensity = 1;
  1548. fl |= FL_STYLED;
  1549. ls.ulStartMask = 0L;
  1550. }
  1551. else if (pla->pstyle != (FLOAT_LONG*) NULL)
  1552. {
  1553. PFLOAT_LONG pstyle;
  1554. STYLEPOS* pspDown;
  1555. STYLEPOS* pspUp;
  1556. pstyle = &pla->pstyle[pla->cstyle];
  1557. ls.xyDensity = STYLE_DENSITY;
  1558. ls.spTotal = 0;
  1559. while (pstyle-- > pla->pstyle)
  1560. {
  1561. ls.spTotal += pstyle->l;
  1562. }
  1563. ls.spTotal *= STYLE_DENSITY;
  1564. ls.spTotal2 = 2 * ls.spTotal;
  1565. // Compute starting style position (this is guaranteed not to overflow):
  1566. ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY +
  1567. LOWORD(pla->elStyleState.l);
  1568. fl |= FL_STYLED;
  1569. ls.cStyle = pla->cstyle;
  1570. ls.aspRtoL = aspRtoL;
  1571. ls.aspLtoR = aspLtoR;
  1572. if (pla->fl & LA_STARTGAP)
  1573. ls.ulStartMask = 0xffffffffL;
  1574. else
  1575. ls.ulStartMask = 0L;
  1576. pstyle = pla->pstyle;
  1577. pspDown = &ls.aspRtoL[ls.cStyle - 1];
  1578. pspUp = &ls.aspLtoR[0];
  1579. while (pspDown >= &ls.aspRtoL[0])
  1580. {
  1581. *pspDown = pstyle->l * STYLE_DENSITY;
  1582. *pspUp = *pspDown;
  1583. pspUp++;
  1584. pspDown--;
  1585. pstyle++;
  1586. }
  1587. }
  1588. if (pco->iDComplexity == DC_RECT)
  1589. {
  1590. fl |= FL_SIMPLE_CLIP;
  1591. arclClip[0] = pco->rclBounds;
  1592. // FL_FLIP_D:
  1593. arclClip[1].top = pco->rclBounds.left;
  1594. arclClip[1].left = pco->rclBounds.top;
  1595. arclClip[1].bottom = pco->rclBounds.right;
  1596. arclClip[1].right = pco->rclBounds.bottom;
  1597. // FL_FLIP_V:
  1598. arclClip[2].top = -pco->rclBounds.bottom + 1;
  1599. arclClip[2].left = pco->rclBounds.left;
  1600. arclClip[2].bottom = -pco->rclBounds.top + 1;
  1601. arclClip[2].right = pco->rclBounds.right;
  1602. // FL_FLIP_V | FL_FLIP_D:
  1603. arclClip[3].top = pco->rclBounds.left;
  1604. arclClip[3].left = -pco->rclBounds.bottom + 1;
  1605. arclClip[3].bottom = pco->rclBounds.right;
  1606. arclClip[3].right = -pco->rclBounds.top + 1;
  1607. prclClip = arclClip;
  1608. }
  1609. apfn = &gapfnStrip[4 * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT)];
  1610. // Get the device ready:
  1611. ulHwMix = gaRop3FromMix[mix & 0xF];
  1612. ulHwMix = (ulHwMix << 8) | (ulHwMix);
  1613. CP_WAIT(ppdev, pjBase);
  1614. if (P9000(ppdev))
  1615. {
  1616. CP_RASTER(ppdev, pjBase, P9000_OVERSIZED | ulHwMix);
  1617. CP_BACKGROUND(ppdev, pjBase, pbo->iSolidColor);
  1618. }
  1619. else
  1620. {
  1621. CP_RASTER(ppdev, pjBase, P9100_OVERSIZED | (ulHwMix & 0xff));
  1622. CP_COLOR0(ppdev, pjBase, pbo->iSolidColor);
  1623. }
  1624. // Set up to enumerate the path:
  1625. if (pco->iDComplexity != DC_COMPLEX)
  1626. {
  1627. PATHDATA pd;
  1628. BOOL bMore;
  1629. ULONG cptfx;
  1630. POINTFIX ptfxStartFigure;
  1631. POINTFIX ptfxLast;
  1632. POINTFIX* pptfxFirst;
  1633. POINTFIX* pptfxBuf;
  1634. pd.flags = 0;
  1635. do {
  1636. bMore = PATHOBJ_bEnum(ppo, &pd);
  1637. cptfx = pd.count;
  1638. if (cptfx == 0)
  1639. break;
  1640. if (pd.flags & PD_BEGINSUBPATH)
  1641. {
  1642. ptfxStartFigure = *pd.pptfx;
  1643. pptfxFirst = pd.pptfx;
  1644. pptfxBuf = pd.pptfx + 1;
  1645. cptfx--;
  1646. }
  1647. else
  1648. {
  1649. pptfxFirst = &ptfxLast;
  1650. pptfxBuf = pd.pptfx;
  1651. }
  1652. if (pd.flags & PD_RESETSTYLE)
  1653. ls.spNext = 0;
  1654. if (cptfx > 0)
  1655. {
  1656. if (!pfnLines(ppdev,
  1657. pptfxFirst,
  1658. pptfxBuf,
  1659. (RUN*) NULL,
  1660. cptfx,
  1661. &ls,
  1662. prclClip,
  1663. apfn,
  1664. fl,
  1665. ulHwMix))
  1666. {
  1667. return(FALSE);
  1668. }
  1669. }
  1670. ptfxLast = pd.pptfx[pd.count - 1];
  1671. if (pd.flags & PD_CLOSEFIGURE)
  1672. {
  1673. if (!pfnLines(ppdev,
  1674. &ptfxLast,
  1675. &ptfxStartFigure,
  1676. (RUN*) NULL,
  1677. 1,
  1678. &ls,
  1679. prclClip,
  1680. apfn,
  1681. fl,
  1682. ulHwMix))
  1683. {
  1684. return(FALSE);
  1685. }
  1686. }
  1687. } while (bMore);
  1688. if (fl & FL_STYLED)
  1689. {
  1690. // Save the style state:
  1691. ULONG ulHigh;
  1692. ULONG ulLow;
  1693. // Masked styles don't normalize the style state. It's a good
  1694. // thing to do, so let's do it now:
  1695. if ((ULONG) ls.spNext >= (ULONG) ls.spTotal2)
  1696. ls.spNext = (ULONG) ls.spNext % (ULONG) ls.spTotal2;
  1697. ulHigh = ls.spNext / ls.xyDensity;
  1698. ulLow = ls.spNext % ls.xyDensity;
  1699. pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
  1700. }
  1701. }
  1702. else
  1703. {
  1704. // Local state for path enumeration:
  1705. BOOL bMore;
  1706. union {
  1707. BYTE aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
  1708. CLIPLINE cl;
  1709. } cl;
  1710. fl |= FL_COMPLEX_CLIP;
  1711. // We use the clip object when non-simple clipping is involved:
  1712. PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla);
  1713. do {
  1714. bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
  1715. if (cl.cl.c != 0)
  1716. {
  1717. if (fl & FL_STYLED)
  1718. {
  1719. ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity
  1720. + LOWORD(cl.cl.lStyleState);
  1721. }
  1722. if (!pfnLines(ppdev,
  1723. &cl.cl.ptfxA,
  1724. &cl.cl.ptfxB,
  1725. &cl.cl.arun[0],
  1726. cl.cl.c,
  1727. &ls,
  1728. (RECTL*) NULL,
  1729. apfn,
  1730. fl,
  1731. ulHwMix))
  1732. {
  1733. return(FALSE);
  1734. }
  1735. }
  1736. } while (bMore);
  1737. }
  1738. return(TRUE);
  1739. }