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.

1710 lines
47 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * One-pixel-wide solid aliased lines
  8. *
  9. * Abstract:
  10. *
  11. * Draws aliased solid-color lines which are one pixel wide.
  12. * Supports clipping against complex clipping regions.
  13. *
  14. * History:
  15. *
  16. * 03/31/1999 AMatos
  17. * Created it.
  18. * 08/17/1999 AGodfrey
  19. * Separated aliased from antialiased.
  20. *
  21. \**************************************************************************/
  22. #include "precomp.hpp"
  23. #pragma optimize("a",on)
  24. //------------------------------------------------------------------------
  25. // Global array that stores all the different options of drawing functions.
  26. // If the order of the functions change, the offset constants must also
  27. // change.
  28. //------------------------------------------------------------------------
  29. #define FUNC_X_MAJOR 0
  30. #define FUNC_Y_MAJOR 1
  31. #define FUNC_CLIP_OFFSET 2
  32. typedef VOID (OnePixelLineDDAAliased::*DDAFunc)(DpScanBuffer*);
  33. static DDAFunc gDrawFunctions[] = {
  34. OnePixelLineDDAAliased::DrawXMajor,
  35. OnePixelLineDDAAliased::DrawYMajor,
  36. OnePixelLineDDAAliased::DrawXMajorClip,
  37. OnePixelLineDDAAliased::DrawYMajorClip,
  38. };
  39. //------------------------------------------------------------------------
  40. // Constants used for manipulating fixed point and doing all the bitwise
  41. // operations on the aliased and antialiased DDA. I know some of these
  42. // are already defined elsewhere, but I do it again here as it might be nice to
  43. // keep this independent of the rest of gdiplus.
  44. //------------------------------------------------------------------------
  45. // Fixed point
  46. #define RealToFix GpRealToFix4
  47. #define FBITS 4
  48. #define FMASK 0xf
  49. #define FINVMASK 0xfffffff0
  50. #define FSIZE 16
  51. #define FHALF 8
  52. #define FHALFMASK 7
  53. /**************************************************************************\
  54. *
  55. * Function Description:
  56. *
  57. * Does all the DDA setup that is common to aliased and antialiased
  58. * lines.
  59. *
  60. * Arguments:
  61. *
  62. * [IN] point1 - end point
  63. * [IN] point2 - end point
  64. * [IN] drawLast - FALSE if the line is to be end-exclusive
  65. * Return Value:
  66. *
  67. * Returns TRUE if the drawing should continue, meaning the line
  68. * has non-zero length.
  69. *
  70. * Created:
  71. *
  72. * 03/31/1999 AMatos
  73. *
  74. \**************************************************************************/
  75. BOOL
  76. OnePixelLineDDAAliased::SetupCommon(
  77. GpPointF *point1,
  78. GpPointF *point2,
  79. BOOL drawLast,
  80. INT width
  81. )
  82. {
  83. MaximumWidth = width;
  84. // Turn the points into fixed 28.4
  85. INT x1 = RealToFix(point1->X);
  86. INT x2 = RealToFix(point2->X);
  87. REAL rDeltaX = point2->X - point1->X;
  88. REAL rDeltaY = point2->Y - point1->Y;
  89. if( rDeltaX == 0 && rDeltaY == 0 )
  90. {
  91. return FALSE;
  92. }
  93. INT xDir = 1;
  94. if(rDeltaX < 0)
  95. {
  96. rDeltaX = -rDeltaX;
  97. xDir = -1;
  98. }
  99. INT y1 = RealToFix(point1->Y);
  100. INT y2 = RealToFix(point2->Y);
  101. INT yDir = 1;
  102. if( rDeltaY < 0)
  103. {
  104. rDeltaY = -rDeltaY;
  105. yDir = -1;
  106. }
  107. Flipped = FALSE;
  108. if( rDeltaY >= rDeltaX )
  109. {
  110. // y-major
  111. // Invert the endpoints if necessary
  112. if(yDir == -1)
  113. {
  114. INT tmp = y1;
  115. y1 = y2;
  116. y2 = tmp;
  117. tmp = x1;
  118. x1 = x2;
  119. x2 = tmp;
  120. xDir = -xDir;
  121. Flipped = TRUE;
  122. }
  123. // Determine the Slope
  124. Slope = xDir*rDeltaX/rDeltaY;
  125. // Initialize the Start and End points
  126. IsXMajor = FALSE;
  127. MajorStart = y1;
  128. MajorEnd = y2;
  129. MinorStart = x1;
  130. MinorEnd = x2;
  131. MinorDir = xDir;
  132. // Mark that we'll use the y-major functions.
  133. DrawFuncIndex = FUNC_Y_MAJOR;
  134. }
  135. else
  136. {
  137. // x-major
  138. // Invert the endpoints if necessary
  139. if(xDir == -1)
  140. {
  141. INT tmp = x1;
  142. x1 = x2;
  143. x2 = tmp;
  144. tmp = y1;
  145. y1 = y2;
  146. y2 = tmp;
  147. yDir = -yDir;
  148. Flipped = TRUE;
  149. }
  150. Slope = yDir*rDeltaY/rDeltaX;
  151. // Initialize the rest
  152. IsXMajor = TRUE;
  153. MajorStart = x1;
  154. MajorEnd = x2;
  155. MinorStart = y1;
  156. MinorEnd = y2;
  157. MinorDir = yDir;
  158. // Mark that we'll use the x-major functions.
  159. DrawFuncIndex = FUNC_X_MAJOR;
  160. }
  161. // Initialize the Deltas. In fixed point.
  162. DMajor = MajorEnd - MajorStart;
  163. DMinor = (MinorEnd - MinorStart)*MinorDir;
  164. // Mark if we're drawing end-exclusive
  165. IsEndExclusive = !drawLast;
  166. return TRUE;
  167. }
  168. //------------------------------------------------------------------------
  169. // Functions specific to the aliased lines
  170. //------------------------------------------------------------------------
  171. /**************************************************************************\
  172. *
  173. * Function Description:
  174. *
  175. * Does the part of the DDA setup that is specific for aliased lines.
  176. *
  177. * Basically it uses the diamond rule to find the integer endpoints
  178. * based on the fixed point values and substitutes these for the
  179. * integer results coordinates. Also calculates the error values.
  180. *
  181. * Arguments:
  182. *
  183. * Return Value:
  184. *
  185. * Returns FALSE if the drawing should not continue, meaning the line
  186. * has a length of less than 1, and should not be drawn by the GIQ rule.
  187. *
  188. * Created:
  189. *
  190. * 03/31/1999 AMatos
  191. *
  192. \**************************************************************************/
  193. BOOL
  194. OnePixelLineDDAAliased::SetupAliased()
  195. {
  196. // Do the GIQ rule to determine which pixel to start at.
  197. BOOL SlopeIsOne = (DMajor == DMinor);
  198. BOOL SlopeIsPosOne = SlopeIsOne && (1 == MinorDir);
  199. // These will store the integer values.
  200. INT major, minor;
  201. INT majorEnd, minorEnd;
  202. // Find the rounded values in fixed point. The rounding
  203. // rules when a coordinate is halfway between two
  204. // integers is given by the GIQ rule.
  205. minor = (MinorStart + FHALFMASK) & FINVMASK;
  206. minorEnd = (MinorEnd + FHALFMASK) & FINVMASK;
  207. BOOL isEndIn, isStartIn;
  208. if(IsXMajor)
  209. {
  210. if(SlopeIsPosOne)
  211. {
  212. major = (MajorStart + FHALF) & FINVMASK;
  213. majorEnd = (MajorEnd + FHALF) & FINVMASK;
  214. }
  215. else
  216. {
  217. major = (MajorStart + FHALFMASK) & FINVMASK;
  218. majorEnd = (MajorEnd + FHALFMASK) & FINVMASK;
  219. }
  220. isStartIn = IsInDiamond(MajorStart - major, MinorStart - minor,
  221. SlopeIsOne, SlopeIsPosOne);
  222. isEndIn = IsInDiamond(MajorEnd - majorEnd, MinorEnd - minorEnd,
  223. SlopeIsOne, SlopeIsPosOne);
  224. }
  225. else
  226. {
  227. major = (MajorStart + FHALFMASK) & FINVMASK;
  228. majorEnd = (MajorEnd + FHALFMASK) & FINVMASK;
  229. isStartIn = IsInDiamond(MinorStart - minor, MajorStart - major,
  230. FALSE, FALSE);
  231. isEndIn = IsInDiamond(MinorEnd - minorEnd, MajorEnd - majorEnd,
  232. FALSE, FALSE);
  233. }
  234. // Determine if we need to advance the initial point.
  235. if(!(Flipped && IsEndExclusive))
  236. {
  237. if(((MajorStart & FMASK) <= FHALF) && !isStartIn)
  238. {
  239. major += FSIZE;
  240. }
  241. }
  242. else
  243. {
  244. if(isStartIn || ((MajorStart & FMASK) <= FHALF))
  245. {
  246. major += FSIZE;
  247. }
  248. }
  249. // Adjust the initial minor coordinate accodingly
  250. minor = GpFloor(MinorStart + (major - MajorStart)*Slope);
  251. // Bring the initial major coordinate to integer
  252. major = major >> FBITS;
  253. // Do the same for the end point.
  254. if(!Flipped && IsEndExclusive)
  255. {
  256. if(((MajorEnd & FMASK) > FHALF) || isEndIn)
  257. {
  258. majorEnd -= FSIZE;
  259. }
  260. }
  261. else
  262. {
  263. if(!isEndIn && ((MajorEnd & FMASK) > FHALF))
  264. {
  265. majorEnd -= FSIZE;
  266. }
  267. }
  268. minorEnd = GpFloor(MinorEnd + (majorEnd - MajorEnd)*Slope);
  269. majorEnd = majorEnd >> FBITS;
  270. // If End is smaller than Start, that means we have a line that
  271. // is smaller than a pixel and bu the diamond rule it should
  272. // not be drawn.
  273. if(majorEnd < major)
  274. {
  275. return FALSE;
  276. }
  277. // Get the error correction values.
  278. ErrorUp = DMinor << 1;
  279. ErrorDown = DMajor << 1;
  280. INT MinorInt;
  281. // Take out the fractions from the DDA. GDI's rounding
  282. // doesn't depend on direction, so for compatability
  283. // round down as GDI does when LINEADJUST281816 is
  284. // defined (see Office 10 bug 281816). Otherwise the rounding
  285. // rule for the minor coordinate depends on the direction
  286. // we are going.
  287. #ifdef LINEADJUST281816
  288. MinorInt = (minor + FHALFMASK) & FINVMASK;
  289. minorEnd = (minorEnd + FHALFMASK) >> FBITS;
  290. #else
  291. if(MinorDir == 1)
  292. {
  293. MinorInt = (minor + FHALF) & FINVMASK;
  294. minorEnd = (minorEnd + FHALF) >> FBITS;
  295. }
  296. else
  297. {
  298. MinorInt = (minor + FHALFMASK) & FINVMASK;
  299. minorEnd = (minorEnd + FHALFMASK) >> FBITS;
  300. }
  301. #endif
  302. // Calculate the initial error based on our fractional
  303. // position in fixed point and convert to integer.
  304. Error = -ErrorDown*(FHALF + MinorDir*(MinorInt - minor));
  305. minor = MinorInt >> FBITS;
  306. Error >>= FBITS;
  307. // Update the class variables
  308. MinorStart = minor;
  309. MinorEnd = minorEnd;
  310. MajorStart = major;
  311. MajorEnd = majorEnd;
  312. return TRUE;
  313. }
  314. /**************************************************************************\
  315. *
  316. * Function Description:
  317. *
  318. * Draws a y major line. Does not support clipping, it assumes that
  319. * it is completely inside any clipping area.
  320. *
  321. * Arguments:
  322. *
  323. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  324. * Return Value:
  325. *
  326. *
  327. * Created:
  328. *
  329. * 03/31/1999 AMatos
  330. *
  331. \**************************************************************************/
  332. VOID
  333. OnePixelLineDDAAliased::DrawYMajor(
  334. DpScanBuffer *scan
  335. )
  336. {
  337. // Do the DDA loop for the case where there is no complex
  338. // clipping region.
  339. ARGB *buffer;
  340. INT numPixels = MajorEnd - MajorStart;
  341. while(numPixels >= 0)
  342. {
  343. buffer = scan->NextBuffer(MinorStart, MajorStart, 1);
  344. *buffer = Color;
  345. MajorStart++;
  346. Error += ErrorUp;
  347. if( Error > 0 )
  348. {
  349. MinorStart += MinorDir;
  350. Error -= ErrorDown;
  351. }
  352. numPixels--;
  353. }
  354. }
  355. /**************************************************************************\
  356. *
  357. * Function Description:
  358. *
  359. * Draws a x major line. Does not support clipping, it assumes that
  360. * it is completely inside any clipping area.
  361. *
  362. * Arguments:
  363. *
  364. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  365. * Return Value:
  366. *
  367. *
  368. * Created:
  369. *
  370. * 03/31/1999 AMatos
  371. *
  372. \**************************************************************************/
  373. VOID
  374. OnePixelLineDDAAliased::DrawXMajor(
  375. DpScanBuffer *scan
  376. )
  377. {
  378. INT numPixels = MajorEnd - MajorStart + 1;
  379. ARGB *buffer;
  380. INT width = 0;
  381. const INT maxWidth = MaximumWidth;
  382. // Run the DDA. First accumulate the width, and when
  383. // the scanline changes write the whole scanline at
  384. // once.
  385. buffer = scan->NextBuffer(MajorStart, MinorStart, maxWidth);
  386. while(numPixels--)
  387. {
  388. MajorStart++;
  389. *buffer++ = Color;
  390. width++;
  391. Error += ErrorUp;
  392. if( Error > 0 && numPixels)
  393. {
  394. MinorStart += MinorDir;
  395. Error -= ErrorDown;
  396. scan->UpdateWidth(width);
  397. buffer = scan->NextBuffer(MajorStart, MinorStart, maxWidth);
  398. width = 0;
  399. }
  400. }
  401. scan->UpdateWidth(width);
  402. }
  403. /**************************************************************************\
  404. *
  405. * Function Description:
  406. *
  407. * Draws a y major line taking clipping into account. It uses the member
  408. * variables MajorIn, MajorOut, MinorIn, MinorOut of the class as the
  409. * clip rectangle. It advances untill the line is in the clip rectangle and
  410. * draws untill it gets out or the end point is reached. In the first case,
  411. * it leaves the DDA in a state so that it can be called again with another
  412. * clipping rectangle.
  413. *
  414. * Arguments:
  415. *
  416. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  417. * Return Value:
  418. *
  419. *
  420. * Created:
  421. *
  422. * 03/31/1999 AMatos
  423. *
  424. \**************************************************************************/
  425. VOID
  426. OnePixelLineDDAAliased::DrawYMajorClip(
  427. DpScanBuffer *scan
  428. )
  429. {
  430. INT saveMajor2 = MajorEnd;
  431. INT saveMinor2 = MinorEnd;
  432. // Do the DDA if all the clipping left the line
  433. // valid.
  434. if(StepUpAliasedClip())
  435. {
  436. // The length given by the minor coord. Whichever length
  437. // comes to 0 first, minor or major, we stop.
  438. INT minorDiff = (MinorEnd - MinorStart)*MinorDir;
  439. ARGB *buffer;
  440. INT numPixels = MajorEnd - MajorStart;
  441. while((minorDiff >= 0) && (numPixels >= 0))
  442. {
  443. buffer = scan->NextBuffer(MinorStart, MajorStart, 1);
  444. *buffer = Color;
  445. MajorStart++;
  446. Error += ErrorUp;
  447. if( Error > 0 )
  448. {
  449. MinorStart += MinorDir;
  450. Error -= ErrorDown;
  451. minorDiff--;
  452. }
  453. numPixels--;
  454. }
  455. }
  456. // Restore the saved end values
  457. MajorEnd = saveMajor2;
  458. MinorEnd = saveMinor2;
  459. }
  460. /**************************************************************************\
  461. *
  462. * Function Description:
  463. *
  464. * Draws a x major line taking clipping into account. It uses the member
  465. * variables MajorIn, MajorOut, MinorIn, MinorOut of the class as the
  466. * clip rectangle. It advances untill the line is in the clip rectangle and
  467. * draws untill it gets out or the end point is reached. In the first case,
  468. * it leaves the DDA in a state so that it can be called again with another
  469. * clipping rectangle.
  470. *
  471. * Arguments:
  472. *
  473. * [IN] DpScanBuffer - The scan buffer for accessing the surface.
  474. * Return Value:
  475. *
  476. *
  477. * Created:
  478. *
  479. * 03/31/1999 AMatos
  480. *
  481. \**************************************************************************/
  482. VOID
  483. OnePixelLineDDAAliased::DrawXMajorClip(
  484. DpScanBuffer *scan
  485. )
  486. {
  487. INT saveMajor2 = MajorEnd;
  488. INT saveMinor2 = MinorEnd;
  489. const INT maxWidth = MaximumWidth;
  490. if(StepUpAliasedClip())
  491. {
  492. INT minorDiff = (MinorEnd - MinorStart)*MinorDir;
  493. INT numPixels = MajorEnd - MajorStart + 1;
  494. ARGB *buffer;
  495. INT width = 0;
  496. // Run the DDA for the case where there is no
  497. // complex clipping region, which is a lot easier.
  498. buffer = scan->NextBuffer(MajorStart, MinorStart, maxWidth);
  499. while(numPixels--)
  500. {
  501. MajorStart++;
  502. width++;
  503. *buffer++ = Color;
  504. Error += ErrorUp;
  505. if( Error > 0 && numPixels)
  506. {
  507. MinorStart += MinorDir;
  508. Error -= ErrorDown;
  509. minorDiff--;
  510. scan->UpdateWidth(width);
  511. // If all of the scanlines in the minor direction have
  512. // been filled, then quit now.
  513. if(minorDiff < 0)
  514. {
  515. break;
  516. }
  517. buffer = scan->NextBuffer(MajorStart, MinorStart, maxWidth);
  518. width = 0;
  519. }
  520. }
  521. scan->UpdateWidth(width);
  522. }
  523. MajorEnd = saveMajor2;
  524. MinorEnd = saveMinor2;
  525. }
  526. /**************************************************************************\
  527. *
  528. * Function Description:
  529. *
  530. * Steps the DDA until the start point is at the edge of the
  531. * clipping rectangle. Also, correct the end values so that
  532. * they stop at the end of the rectangle. The caller must save
  533. * these values to restore at the end of the loop.
  534. *
  535. * Arguments:
  536. *
  537. * Return Value:
  538. *
  539. *
  540. *
  541. * Created:
  542. *
  543. * 03/31/1999 AMatos
  544. *
  545. \**************************************************************************/
  546. BOOL
  547. OnePixelLineDDAAliased::StepUpAliasedClip()
  548. {
  549. // Step up on the DDA untill the major coordinate
  550. // is aligned with the rectangles edge
  551. while(MajorStart < MajorIn)
  552. {
  553. MajorStart++;
  554. Error += ErrorUp;
  555. if( Error > 0 )
  556. {
  557. MinorStart += MinorDir;
  558. Error -= ErrorDown;
  559. }
  560. }
  561. // If the minor coordinate is still out, step up untill
  562. // this one is also aligned. In doing that we might pass
  563. // the on the major coordinate, in which case we are done
  564. // and there is no intersection.
  565. INT minorDiff = (MinorIn - MinorStart)*MinorDir;
  566. while(minorDiff > 0 && MajorStart <= MajorOut)
  567. {
  568. MajorStart++;
  569. Error += ErrorUp;
  570. if( Error > 0 )
  571. {
  572. MinorStart += MinorDir;
  573. minorDiff--;
  574. Error -= ErrorDown;
  575. }
  576. }
  577. minorDiff = (MinorEnd - MinorOut)*MinorDir;
  578. if(minorDiff > 0)
  579. {
  580. if((MinorStart - MinorOut)*MinorDir > 0)
  581. {
  582. return FALSE;
  583. }
  584. MinorEnd = MinorOut;
  585. }
  586. if(MajorOut < MajorEnd)
  587. {
  588. MajorEnd = MajorOut;
  589. }
  590. // Return if the line is still valid.
  591. return(MajorStart <= MajorEnd);
  592. }
  593. //--------------------------------------------------------------------
  594. // Auxiliary functions
  595. //--------------------------------------------------------------------
  596. /**************************************************************************\
  597. *
  598. * Function Description:
  599. *
  600. * Clips the line against a rectangle. It assumes that the line endpoints
  601. * are stored in the class in floating point format. This sets an
  602. * order in which this function can be called. It must be after the
  603. * SetupCommon function and before the specific setups for antialiasing
  604. * and aliasing. This is a pain, but it's better than requirering on of
  605. * these to have to know about clipping. The clipping here is done by
  606. * using the Slope and InvSlope members of the class to advance the
  607. * endpoints to the rectangle edges. Thus the function also assumes that
  608. * Slope and InvSlope have been calculated.
  609. *
  610. * Arguments:
  611. *
  612. * [IN] clipRect - The rectangle to clip against
  613. * Return Value:
  614. *
  615. *
  616. * Created:
  617. *
  618. * 03/31/1999 AMatos
  619. *
  620. \**************************************************************************/
  621. BOOL
  622. OnePixelLineDDAAliased::ClipRectangle(
  623. const GpRect* clipRect
  624. )
  625. {
  626. INT clipBottom, clipTop, clipLeft, clipRight;
  627. // Set the major and minor edges of the clipping
  628. // region, converting to fixed point 28.4. Note that
  629. // we don't convert to the pixel center, but to a
  630. // that goes all the way up to the pixel edges. This
  631. // makes a difference for antialiasing. We don't go all
  632. // the way to the edge since some rounding rules could
  633. // endup lighting the next pixel outside of the clipping
  634. // area. That's why we add/subtract 7 instead of 8 for the
  635. // bottom and right, since these are exclusive.
  636. // For the left and top, subtract 8 (1/2 pixel), since here
  637. // we are inclusive.
  638. INT majorMin = (clipRect->GetLeft() << FBITS) - FHALF;
  639. INT majorMax = ((clipRect->GetRight() - 1) << FBITS) + FHALFMASK;
  640. INT minorMax = ((clipRect->GetBottom() - 1) << FBITS) + FHALFMASK;
  641. INT minorMin = (clipRect->GetTop() << FBITS) - FHALF;
  642. if(!IsXMajor)
  643. {
  644. INT tmp;
  645. tmp = majorMin;
  646. majorMin = minorMin;
  647. minorMin = tmp;
  648. tmp = majorMax;
  649. majorMax = minorMax;
  650. minorMax = tmp;
  651. }
  652. // First clip in the major coordinate
  653. BOOL minOut, maxOut;
  654. minOut = MajorStart < majorMin;
  655. maxOut = MajorEnd > majorMax;
  656. if( minOut || maxOut )
  657. {
  658. if(MajorStart > majorMax || MajorEnd < majorMin)
  659. {
  660. return FALSE;
  661. }
  662. if(minOut)
  663. {
  664. MinorStart += GpFloor((majorMin - MajorStart)*Slope);
  665. MajorStart = majorMin;
  666. }
  667. if(maxOut)
  668. {
  669. MinorEnd += GpFloor((majorMax - MajorEnd)*Slope);
  670. MajorEnd = majorMax;
  671. // If we clipped the last point, we don't need to be IsEndExclusive
  672. // anymore, as the last point now is not the line's last
  673. // point but some in the middle.
  674. IsEndExclusive = FALSE;
  675. }
  676. }
  677. // Now clip the minor coordinate
  678. INT *pMajor1, *pMinor1, *pMajor2, *pMinor2;
  679. if(MinorDir == 1)
  680. {
  681. pMajor1 = &MajorStart;
  682. pMajor2 = &MajorEnd;
  683. pMinor1 = &MinorStart;
  684. pMinor2 = &MinorEnd;
  685. }
  686. else
  687. {
  688. pMajor1 = &MajorEnd;
  689. pMajor2 = &MajorStart;
  690. pMinor1 = &MinorEnd;
  691. pMinor2 = &MinorStart;
  692. }
  693. minOut = *pMinor1 < minorMin;
  694. maxOut = *pMinor2 > minorMax;
  695. if(minOut || maxOut)
  696. {
  697. if(*pMinor1 > minorMax || *pMinor2 < minorMin)
  698. {
  699. return FALSE;
  700. }
  701. if(minOut)
  702. {
  703. *pMajor1 += GpFloor((minorMin - *pMinor1)*InvSlope);
  704. *pMinor1 = minorMin;
  705. }
  706. if(maxOut)
  707. {
  708. *pMajor2 += GpFloor((minorMax - *pMinor2)*InvSlope);
  709. *pMinor2 = minorMax;
  710. // If we clipped the last point, we don't need to be endExclusive
  711. // anymore, as the last point now is not the line's last
  712. // point but some in the middle.
  713. IsEndExclusive = FALSE;
  714. }
  715. }
  716. return(TRUE);
  717. }
  718. /**************************************************************************\
  719. *
  720. * Function Description:
  721. *
  722. * Given the fractional parts of a coordinate in fixed point, this
  723. * function returns if the coordinate is inside the diamond at the
  724. * nearest integer position.
  725. *
  726. * Arguments:
  727. *
  728. * [IN] xFrac - Fractional part of the x coordinate
  729. * [IN] yFrac - Fractional part of the y coordinate
  730. * [IN] SlopeIsOne - TRUE if the line has Slope +/- 1
  731. * [IN] SlopeIsPosOne - TRUE if the line has Slope +1
  732. * Return Value:
  733. *
  734. * TRUE if the coordinate is inside the diamond
  735. *
  736. * Created:
  737. *
  738. * 03/31/1999 AMatos
  739. *
  740. \**************************************************************************/
  741. BOOL
  742. OnePixelLineDDAAliased::IsInDiamond(
  743. INT xFrac,
  744. INT yFrac,
  745. BOOL SlopeIsOne,
  746. BOOL SlopeIsPosOne
  747. )
  748. {
  749. // Get the fractional parts of the fix points, and the
  750. // sum of their absolute values.
  751. INT fracSum = 0;
  752. if(xFrac > 0)
  753. {
  754. fracSum += xFrac;
  755. }
  756. else
  757. {
  758. fracSum -= xFrac;
  759. }
  760. if(yFrac > 0)
  761. {
  762. fracSum += yFrac;
  763. }
  764. else
  765. {
  766. fracSum -= yFrac;
  767. }
  768. // Return true if the point is inside the diamond.
  769. if(fracSum < FHALF)
  770. {
  771. return TRUE;
  772. }
  773. // Check the cases where we are at the two vertices of the
  774. // diamond which are considered inside.
  775. if(yFrac == 0)
  776. {
  777. if((SlopeIsPosOne && xFrac == -FHALF) ||
  778. (!SlopeIsPosOne && xFrac == FHALF))
  779. {
  780. return TRUE;
  781. }
  782. }
  783. if((xFrac == 0) && (yFrac == FHALF))
  784. {
  785. return TRUE;
  786. }
  787. // Check for the cases where we are at the edges of the
  788. // diamond with a Slope of one.
  789. if (SlopeIsOne && (fracSum == FHALF))
  790. {
  791. if (SlopeIsPosOne && (xFrac < 0) && (yFrac > 0))
  792. {
  793. return TRUE;
  794. }
  795. if (!SlopeIsPosOne && (xFrac > 0) && (yFrac > 0))
  796. {
  797. return TRUE;
  798. }
  799. }
  800. return FALSE;
  801. }
  802. typedef GpStatus DrawSolidLineFunc(
  803. DpScanBuffer *scan,
  804. const GpRect *clipRect,
  805. const DpClipRegion* clipRegionIn,
  806. GpPointF *point1,
  807. GpPointF *point2,
  808. ARGB inColor,
  809. BOOL drawLast
  810. );
  811. DrawSolidLineFunc DrawSolidLineOnePixelAliased;
  812. DrawSolidLineFunc DrawSolidLineOnePixelAntiAliased;
  813. /**************************************************************************\
  814. *
  815. * Function Description:
  816. *
  817. * Called back by the path enumeration function, this draws a list
  818. * of lines.
  819. *
  820. * Return Value:
  821. *
  822. * GpStatus - Ok or failure status
  823. *
  824. * Created:
  825. *
  826. * 03/31/2000 andrewgo
  827. *
  828. \**************************************************************************/
  829. struct EpSolidStrokeOnePixelContext
  830. {
  831. DrawSolidLineFunc *DrawLineFunction;
  832. DpScanBuffer *Scan;
  833. GpRect *ClipBoundsPointer;
  834. DpClipRegion *ClipRegion;
  835. ARGB Argb;
  836. BOOL DrawLast; // TRUE if draw last pixel in subpaths
  837. };
  838. BOOL
  839. DrawSolidStrokeOnePixel(
  840. VOID *voidContext,
  841. POINT *point, // 28.4 format, an arary of size 'count'
  842. INT vertexCount,
  843. PathEnumerateTermination lastSubpath
  844. )
  845. {
  846. EpSolidStrokeOnePixelContext *context
  847. = static_cast<EpSolidStrokeOnePixelContext*>(voidContext);
  848. ASSERT(vertexCount >= 2);
  849. for (INT i = vertexCount - 1; i != 0; i--, point++)
  850. {
  851. PointF pointOne(TOREAL((point)->x) / 16, TOREAL((point)->y) / 16);
  852. PointF pointTwo(TOREAL((point + 1)->x) / 16, TOREAL((point + 1)->y) / 16) ;
  853. // Note that we're always drawing the last pixel, which is
  854. // fine when we're 100% opaque, because we'll be re-drawing
  855. // the same pixel for consecutive joined lines (it's a little
  856. // more work, but the cost is small and is actually comparable
  857. // to the overhead of deciding whether to do the last pixel
  858. // or not).
  859. //
  860. // This is the wrong thing to do for non-opaque lines, because
  861. // of the redraw issue. But we shouldn't be coming through
  862. // here for the non-opaque case anyway, since any self-overlaps
  863. // of the lines will cause pixel overdraw, which produces the
  864. // 'wrong' result (or at least different from the 'right' result
  865. // as defined by the widener code).
  866. (context->DrawLineFunction)(
  867. context->Scan,
  868. context->ClipBoundsPointer,
  869. context->ClipRegion,
  870. &pointOne,
  871. &pointTwo,
  872. context->Argb,
  873. (lastSubpath==PathEnumerateCloseSubpath) || context->DrawLast
  874. );
  875. }
  876. return(TRUE);
  877. }
  878. /**************************************************************************\
  879. *
  880. * Function Description:
  881. *
  882. * Draws a one-pixel wide path with a solid color.
  883. *
  884. * Arguments:
  885. *
  886. * [IN] context - the context (matrix and clipping)
  887. * [IN] surface - the surface to fill
  888. * [IN] drawBounds - the surface bounds
  889. * [IN] path - the path to fill
  890. * [IN] pen - the pen to use
  891. * [IN] drawLast - TRUE if last pixels in subpaths are to be drawn.
  892. *
  893. * Return Value:
  894. *
  895. * GpStatus - Ok or failure status
  896. *
  897. * Created:
  898. *
  899. * 03/31/1999 AMatos
  900. *
  901. \**************************************************************************/
  902. GpStatus
  903. DpDriver::SolidStrokePathOnePixel(
  904. DpContext *context,
  905. DpBitmap *surface,
  906. const GpRect *drawBounds,
  907. const DpPath *path,
  908. const DpPen *pen,
  909. BOOL drawLast
  910. )
  911. {
  912. GpBrush *brush = GpBrush::GetBrush(pen->Brush);
  913. ASSERT(pen->Brush->Type == BrushTypeSolidColor);
  914. ASSERT(pen->Brush->SolidColor.IsOpaque());
  915. // Antialiased lines are usually drawn using aarasterizer.cpp
  916. // rather than aaline.cpp. If aaline.cpp is to be used, define
  917. // AAONEPIXELLINE_SUPPORT
  918. #ifdef AAONEPIXELLINE_SUPPORT
  919. DrawSolidLineFunc *drawLineFunc = context->AntiAliasMode
  920. ? DrawSolidLineOnePixelAntiAliased
  921. : DrawSolidLineOnePixelAliased;
  922. #else
  923. ASSERT(context->AntiAliasMode == 0);
  924. DrawSolidLineFunc *drawLineFunc = DrawSolidLineOnePixelAliased;
  925. #endif
  926. // Determine if alpha blending is necessary
  927. BOOL noTransparentPixels;
  928. noTransparentPixels = (!context->AntiAliasMode) &&
  929. (brush->IsOpaque());
  930. DpScanBuffer scan(
  931. surface->Scan,
  932. this,
  933. context,
  934. surface,
  935. noTransparentPixels);
  936. if (!scan.IsValid())
  937. {
  938. return(GenericError);
  939. }
  940. GpSolidFill * solidBrush = static_cast<GpSolidFill *>(brush);
  941. ARGB argb = solidBrush->GetColor().GetValue();
  942. DpClipRegion *clipRegion = &context->VisibleClip;
  943. GpRect clipBounds;
  944. GpRect *clipBoundsPointer;
  945. RECT clipRect;
  946. RECT *clipRectPointer;
  947. DpRegion::Visibility visibility;
  948. visibility = clipRegion->GetRectVisibility(
  949. drawBounds->X,
  950. drawBounds->Y,
  951. drawBounds->X + drawBounds->Width,
  952. drawBounds->Y + drawBounds->Height);
  953. if (visibility == DpRegion::TotallyVisible)
  954. {
  955. clipBoundsPointer = NULL;
  956. clipRectPointer = NULL;
  957. clipRegion = NULL;
  958. }
  959. else
  960. {
  961. // !!![andrewgo] Is clipBoundsPointer actually needed?
  962. clipRegion->GetBounds(&clipBounds);
  963. clipBoundsPointer = &clipBounds;
  964. // Scale the clip bounds rectangle by 16 to account for our scaling
  965. // to 28.4 coordinates:
  966. clipRect.left = clipBounds.GetLeft() << 4;
  967. clipRect.top = clipBounds.GetTop() << 4;
  968. clipRect.right = clipBounds.GetRight() << 4;
  969. clipRect.bottom = clipBounds.GetBottom() << 4;
  970. clipRectPointer = &clipRect;
  971. // !!![andrewgo] Why is this needed? Why wasn't this covered in
  972. // GetRectVisibility?
  973. if (clipRegion->IsSimple())
  974. {
  975. clipRegion = NULL;
  976. }
  977. }
  978. EpSolidStrokeOnePixelContext drawContext;
  979. drawContext.DrawLineFunction = drawLineFunc;
  980. drawContext.Scan = &scan;
  981. drawContext.ClipBoundsPointer = clipBoundsPointer;
  982. drawContext.ClipRegion = clipRegion;
  983. drawContext.Argb = argb;
  984. drawContext.DrawLast = drawLast;
  985. // Scale the transform by 16 to get 28.4 units:
  986. GpMatrix transform = context->WorldToDevice;
  987. transform.AppendScale(TOREAL(16), TOREAL(16));
  988. FixedPointPathEnumerate(path,
  989. &transform,
  990. clipRectPointer,
  991. PathEnumerateTypeStroke,
  992. DrawSolidStrokeOnePixel,
  993. &drawContext);
  994. return(Ok);
  995. }
  996. /**************************************************************************\
  997. *
  998. * Function Description:
  999. *
  1000. * Draws a one-pixe-wide line with a solid color. Calls on the
  1001. * OnePixelLineDDAAliased class to do the actual drawing.
  1002. *
  1003. * Arguments:
  1004. *
  1005. * [IN] scan - The DpScanBuffer to access the drawing surface
  1006. * [IN] clipRect - A single rectangle that includes all the clipping
  1007. * region. If there is no clipping, should be set to NULL.
  1008. * [IN] clipRegionIn - A complex clipping region. If the clipping region is
  1009. * simple, this should be NULL, and clipRect will be used.
  1010. * [IN] point1 - line end point
  1011. * [IN] point2 - line end point
  1012. * [IN] inColor - the solid color
  1013. * [IN] drawLast - FALSE if the line is to be end-exclusive.
  1014. *
  1015. * Return Value:
  1016. *
  1017. * GpStatus - Ok or failure status
  1018. *
  1019. * Created:
  1020. *
  1021. * 03/31/1999 AMatos
  1022. *
  1023. \**************************************************************************/
  1024. GpStatus
  1025. DrawSolidLineOnePixelAliased(
  1026. DpScanBuffer *scan,
  1027. const GpRect *clipRect,
  1028. const DpClipRegion* clipRegionIn,
  1029. GpPointF *point1,
  1030. GpPointF *point2,
  1031. ARGB inColor,
  1032. BOOL drawLast
  1033. )
  1034. {
  1035. // Take out the const for now because the Enumeration method
  1036. // is not const.
  1037. DpClipRegion *clipRegion = const_cast<DpClipRegion*>(clipRegionIn);
  1038. // Setup the common part of the DDA
  1039. OnePixelLineDDAAliased dda;
  1040. INT width = scan->GetSurface()->Width;
  1041. if(clipRect)
  1042. {
  1043. // We have a bug in the driver architecture which allows the
  1044. // surface associated with the scan to be smaller than the actual
  1045. // surface in the screen case (EpScanGdiDci).
  1046. // Therefore we need to look at the visible clip bounds also.
  1047. // If it turns out that the visible clip is bigger, our maximum
  1048. // width needs to be expanded.
  1049. // 350997 Aliased line is not clipped to surface
  1050. width = max(width, clipRect->Width);
  1051. }
  1052. if(!dda.SetupCommon(point1, point2, drawLast, width))
  1053. {
  1054. return Ok;
  1055. }
  1056. dda.Color = GpColor::ConvertToPremultiplied(inColor);
  1057. // Now handle the different clipping cases
  1058. if(!clipRect)
  1059. {
  1060. // This is easy, there is no clipping so just draw.
  1061. if(!dda.SetupAliased())
  1062. {
  1063. return Ok;
  1064. }
  1065. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1066. return Ok;
  1067. }
  1068. else
  1069. {
  1070. // The inverse of the Slope might be needed.
  1071. // Can't use the inverse slope if the slope is zero.
  1072. if(dda.Slope==0.0F)
  1073. {
  1074. dda.InvSlope=0.0F;
  1075. }
  1076. else
  1077. {
  1078. dda.InvSlope = (1.0F/dda.Slope);
  1079. }
  1080. // First of all clip against the bounding rectangle
  1081. if(!dda.ClipRectangle(clipRect))
  1082. {
  1083. return Ok;
  1084. }
  1085. // Do the specific setup
  1086. if(!dda.SetupAliased())
  1087. {
  1088. return Ok;
  1089. }
  1090. // For each clip rectangle we store it's limits in
  1091. // an array of four elements. We then index this array using
  1092. // the variables below which depend on the slope and
  1093. // direction of the line in the following way: majorIn is edge crossed
  1094. // to go into the rect in the major direction, majorOut is the edge
  1095. // crossed to go out of the rect in the major direction, and so on.
  1096. // The same for xIn, xOut, yIn, yOut.
  1097. INT majorIn, majorOut, minorIn, minorOut;
  1098. INT xIn, xOut, yIn, yOut;
  1099. // Direction to enumerate the rectangles which depends on the
  1100. // line
  1101. DpClipRegion::Direction enumDirection;
  1102. INT clipBounds[4];
  1103. // We store all our info in terms of major and minor
  1104. // direction, but to deal with cliping rectangles we
  1105. // need to know them in terms of x and y, so calculate
  1106. // xDir, yDir, the advance slope.
  1107. REAL xAdvanceRate;
  1108. INT xDir, yDir;
  1109. INT yEndLine;
  1110. // If the line crosses a span completely, (xStart, yStart)
  1111. // is the position where it enters the span and (xEnd, yEnd)
  1112. // is the position that it leaves. If it starts inside the
  1113. // span, then (xStart, yStart) is the start point
  1114. REAL yStart, xStart, xEnd, yEnd;
  1115. if(dda.IsXMajor)
  1116. {
  1117. // Calculate the in-out indices
  1118. majorIn = xIn = 0;
  1119. majorOut = xOut = 2;
  1120. if(dda.MinorDir == 1)
  1121. {
  1122. minorIn = 1;
  1123. minorOut = 3;
  1124. enumDirection = DpClipRegion::TopLeftToBottomRight;
  1125. }
  1126. else
  1127. {
  1128. minorIn = 3;
  1129. minorOut = 1;
  1130. enumDirection = DpClipRegion::BottomLeftToTopRight;
  1131. }
  1132. yIn = minorIn;
  1133. yOut = minorOut;
  1134. // Make (xStart, yStart) be the initial point
  1135. yStart = (REAL)dda.MinorStart;
  1136. xStart = (REAL)dda.MajorStart;
  1137. // Always advance in positive direction when X is major
  1138. xAdvanceRate = REALABS(dda.InvSlope);
  1139. xDir = 1;
  1140. yDir = dda.MinorDir;
  1141. yEndLine = dda.MinorEnd;
  1142. }
  1143. else
  1144. {
  1145. majorIn = yIn = 1;
  1146. majorOut = yOut = 3;
  1147. if(dda.MinorDir == 1)
  1148. {
  1149. minorIn = 0;
  1150. minorOut = 2;
  1151. enumDirection = DpClipRegion::TopLeftToBottomRight;
  1152. }
  1153. else
  1154. {
  1155. minorIn = 2;
  1156. minorOut = 0;
  1157. enumDirection = DpClipRegion::TopRightToBottomLeft;
  1158. }
  1159. xIn = minorIn;
  1160. xOut = minorOut;
  1161. // Make (xStart, yStart) be the initial point
  1162. yStart = (REAL)dda.MajorStart;
  1163. xStart = (REAL)dda.MinorStart;
  1164. xAdvanceRate = dda.Slope;
  1165. xDir = dda.MinorDir;
  1166. yDir = 1;
  1167. yEndLine = dda.MajorEnd;
  1168. }
  1169. // Update the drawing function to the correct
  1170. // slipping version
  1171. dda.DrawFuncIndex += FUNC_CLIP_OFFSET;
  1172. if(!clipRegion)
  1173. {
  1174. // In this case there is only a single rect, so just
  1175. // draw clipped to that
  1176. // Store the rectangle in an array so we can atribute the
  1177. // right values to the MajorIn, majorOut, etc... variables.
  1178. // Remember that bottom and right are exclusive.
  1179. clipBounds[0] = clipRect->GetLeft();
  1180. clipBounds[1] = clipRect->GetTop();
  1181. clipBounds[2] = clipRect->GetRight() - 1;
  1182. clipBounds[3] = clipRect->GetBottom() - 1;
  1183. dda.MajorIn = clipBounds[majorIn];
  1184. dda.MajorOut = clipBounds[majorOut];
  1185. dda.MinorIn = clipBounds[minorIn];
  1186. dda.MinorOut = clipBounds[minorOut];
  1187. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1188. return Ok;
  1189. }
  1190. else
  1191. {
  1192. BOOL agregating = FALSE;
  1193. INT agregateBounds[4];
  1194. // We have a complex clipping region. So what we'll do
  1195. // is clip against each individual rectangle in the
  1196. // cliping region.
  1197. clipRegion->StartEnumeration(GpFloor(yStart), enumDirection);
  1198. GpRect rect;
  1199. // Get the first rectangle.
  1200. INT numRects = 1;
  1201. clipRegion->Enumerate(&rect, numRects);
  1202. clipBounds[0] = rect.GetLeft();
  1203. clipBounds[1] = rect.GetTop();
  1204. clipBounds[2] = rect.GetRight() - 1;
  1205. clipBounds[3] = rect.GetBottom() - 1;
  1206. // Store the y position into the span
  1207. INT currSpanYMin = clipBounds[yIn];
  1208. // We need some special treatment for the case where the
  1209. // line is horizontal, since is this case it's not going
  1210. // to cross different spans. And it it's not in the current
  1211. // span, it's totally clipped out.
  1212. if(dda.IsXMajor && dda.ErrorUp == 0)
  1213. {
  1214. if(yStart >= clipBounds[1] && yStart <= clipBounds[3])
  1215. {
  1216. xStart = (REAL)dda.MajorStart;
  1217. xEnd = (REAL)dda.MajorEnd;
  1218. }
  1219. else
  1220. {
  1221. return Ok;
  1222. }
  1223. }
  1224. else
  1225. {
  1226. if(yStart < clipBounds[1] || yStart > clipBounds[3])
  1227. {
  1228. xStart = xStart + (clipBounds[yIn] - yStart)*xAdvanceRate;
  1229. yStart = (REAL)clipBounds[yIn];
  1230. }
  1231. // Account for initial DDA error when calculating xEnd so that clipping
  1232. // will track what the DDA is actually drawing.
  1233. xEnd = xStart + ((clipBounds[yOut] - yStart)*yDir - ((REAL)dda.Error / (REAL)dda.ErrorDown))*xAdvanceRate;
  1234. }
  1235. yEnd = (REAL)clipBounds[yOut];
  1236. while(1)
  1237. {
  1238. // Get to the first rectangle on the span that crosses the
  1239. // line
  1240. while((xStart - clipBounds[xOut])*xDir > 0)
  1241. {
  1242. numRects = 1;
  1243. clipRegion->Enumerate(&rect, numRects);
  1244. clipBounds[0] = rect.GetLeft();
  1245. clipBounds[1] = rect.GetTop();
  1246. clipBounds[2] = rect.GetRight() - 1;
  1247. clipBounds[3] = rect.GetBottom() - 1;
  1248. if(numRects != 1)
  1249. {
  1250. goto draw_agregated;
  1251. }
  1252. if(clipBounds[yIn] != currSpanYMin)
  1253. {
  1254. // There may be pending aggregated drawing operations. If so
  1255. // perform them now before doing the next span.
  1256. if (agregating)
  1257. break;
  1258. else
  1259. goto process_next_span;
  1260. }
  1261. }
  1262. // Draw on all the rectangles that intersect the
  1263. // line
  1264. if((xStart - clipBounds[xIn])*xDir > 0 &&
  1265. (clipBounds[xOut] - xEnd)*xDir > 0)
  1266. {
  1267. if(agregating)
  1268. {
  1269. if((clipBounds[xIn] - agregateBounds[xIn])*xDir < 0)
  1270. {
  1271. agregateBounds[xIn] = clipBounds[xIn];
  1272. }
  1273. if((clipBounds[xOut] - agregateBounds[xOut])*xDir > 0)
  1274. {
  1275. agregateBounds[xOut] = clipBounds[xOut];
  1276. }
  1277. agregateBounds[yOut] = clipBounds[yOut];
  1278. }
  1279. else
  1280. {
  1281. agregateBounds[0] = clipBounds[0];
  1282. agregateBounds[1] = clipBounds[1];
  1283. agregateBounds[2] = clipBounds[2];
  1284. agregateBounds[3] = clipBounds[3];
  1285. agregating = TRUE;
  1286. }
  1287. }
  1288. else
  1289. {
  1290. if(agregating)
  1291. {
  1292. dda.MajorIn = agregateBounds[majorIn];
  1293. dda.MajorOut = agregateBounds[majorOut];
  1294. dda.MinorIn = agregateBounds[minorIn];
  1295. dda.MinorOut = agregateBounds[minorOut];
  1296. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1297. agregating = FALSE;
  1298. }
  1299. while((xEnd - clipBounds[xIn])*xDir > 0)
  1300. {
  1301. dda.MajorIn = clipBounds[majorIn];
  1302. dda.MajorOut = clipBounds[majorOut];
  1303. dda.MinorIn = clipBounds[minorIn];
  1304. dda.MinorOut = clipBounds[minorOut];
  1305. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1306. if(dda.MajorStart > dda.MajorEnd)
  1307. {
  1308. return Ok;
  1309. }
  1310. numRects = 1;
  1311. clipRegion->Enumerate(&rect, numRects);
  1312. clipBounds[0] = rect.GetLeft();
  1313. clipBounds[1] = rect.GetTop();
  1314. clipBounds[2] = rect.GetRight() - 1;
  1315. clipBounds[3] = rect.GetBottom() - 1;
  1316. if(numRects != 1)
  1317. {
  1318. goto draw_agregated;
  1319. }
  1320. if(clipBounds[yIn] != currSpanYMin)
  1321. {
  1322. goto process_next_span;
  1323. }
  1324. }
  1325. }
  1326. // Get to the next span
  1327. while(clipBounds[yIn] == currSpanYMin)
  1328. {
  1329. numRects = 1;
  1330. clipRegion->Enumerate(&rect, numRects);
  1331. clipBounds[0] = rect.GetLeft();
  1332. clipBounds[1] = rect.GetTop();
  1333. clipBounds[2] = rect.GetRight() - 1;
  1334. clipBounds[3] = rect.GetBottom() - 1;
  1335. if(numRects != 1)
  1336. {
  1337. goto draw_agregated;
  1338. }
  1339. }
  1340. process_next_span:
  1341. if((clipBounds[yIn] - yEndLine)*yDir > 0)
  1342. {
  1343. // We are done.
  1344. goto draw_agregated;
  1345. }
  1346. if((clipBounds[yIn] - yEnd)*yDir == 1)
  1347. {
  1348. xStart = xEnd;
  1349. }
  1350. else
  1351. {
  1352. if(agregating)
  1353. {
  1354. dda.MajorIn = agregateBounds[majorIn];
  1355. dda.MajorOut = agregateBounds[majorOut];
  1356. dda.MinorIn = agregateBounds[minorIn];
  1357. dda.MinorOut = agregateBounds[minorOut];
  1358. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1359. if(dda.MajorStart > dda.MajorEnd)
  1360. {
  1361. return Ok;
  1362. }
  1363. agregating = FALSE;
  1364. }
  1365. xStart = xStart + (clipBounds[yIn] - yStart)*yDir*xAdvanceRate;
  1366. }
  1367. yStart = (REAL)clipBounds[yIn];
  1368. // Add 1 to make the amount added to xStart proportional to height of
  1369. // the clipping rectangle, since clipBounds are inset by 1.
  1370. xEnd = xStart + ((clipBounds[yOut] - yStart)*yDir + 1)*xAdvanceRate;
  1371. yEnd = (REAL)clipBounds[yOut];
  1372. currSpanYMin = GpFloor(yStart);
  1373. }
  1374. draw_agregated:
  1375. if(agregating)
  1376. {
  1377. dda.MajorIn = agregateBounds[majorIn];
  1378. dda.MajorOut = agregateBounds[majorOut];
  1379. dda.MinorIn = agregateBounds[minorIn];
  1380. dda.MinorOut = agregateBounds[minorOut];
  1381. (dda.*(gDrawFunctions[dda.DrawFuncIndex]))(scan);
  1382. }
  1383. }
  1384. }
  1385. return Ok;
  1386. }
  1387. #pragma optimize("a", off)