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.

1682 lines
51 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Rasterizer.cpp
  8. *
  9. * Abstract:
  10. *
  11. * GpRasterizer class implementation (and supporting classes)
  12. *
  13. * Created:
  14. *
  15. * 12/15/1998 DCurtis
  16. *
  17. \**************************************************************************/
  18. #include "precomp.hpp"
  19. /**************************************************************************\
  20. *
  21. * Function Description:
  22. *
  23. * Initialize the vector's DDA info.
  24. * Assumes y1 < y2.
  25. *
  26. * Arguments:
  27. *
  28. * [IN] x1 - starting fixed-point x coordinate of vector
  29. * [IN] y1 - starting fixed-point y coordinate of vector
  30. * [IN] x2 - ending fixed-point x coordinate of vector
  31. * [IN] y2 - ending fixed-point y coordinate of vector
  32. * [IN] direction - VectorGoingUp or VectorGoingDown
  33. *
  34. * Return Value:
  35. *
  36. * NONE
  37. *
  38. * Created:
  39. *
  40. * 12/15/1998 DCurtis
  41. *
  42. \**************************************************************************/
  43. VOID
  44. GpYDda::Init(
  45. FIX4 x1,
  46. FIX4 y1,
  47. FIX4 x2,
  48. FIX4 y2,
  49. GpVectorDirection direction
  50. )
  51. {
  52. ASSERT ((direction == VectorGoingUp) || (direction == VectorGoingDown));
  53. FIX4 xDelta = x2 - x1;
  54. FIX4 yDelta = y2 - y1;
  55. ASSERT (yDelta > 0);
  56. YDelta = yDelta;
  57. // Set up x increment
  58. INT quotient;
  59. INT remainder;
  60. // Error is initially 0, but we add yDelta - 1 for the ceiling,
  61. // but then subtract off yDelta so that we can check the sign
  62. // instead of comparing to yDelta.
  63. Error = -1;
  64. if (xDelta < 0)
  65. {
  66. xDelta = -xDelta;
  67. if (xDelta < yDelta) // y-major
  68. {
  69. XInc = -1;
  70. ErrorUp = yDelta - xDelta;
  71. }
  72. else // x-major
  73. {
  74. QUOTIENT_REMAINDER (xDelta, yDelta, quotient, remainder);
  75. XInc = -quotient;
  76. ErrorUp = remainder;
  77. if (remainder != 0)
  78. {
  79. XInc--;
  80. ErrorUp = yDelta - remainder;
  81. }
  82. }
  83. }
  84. else
  85. {
  86. if (xDelta < yDelta) // y-major
  87. {
  88. XInc = 0;
  89. ErrorUp = xDelta;
  90. }
  91. else // x-major
  92. {
  93. QUOTIENT_REMAINDER (xDelta, yDelta, quotient, remainder);
  94. XInc = quotient;
  95. ErrorUp = remainder;
  96. }
  97. }
  98. // See if we need to advance to an integer coordinate
  99. if ((y1 & FIX4_MASK) != 0)
  100. {
  101. INT i;
  102. for (i = FIX4_ONE - (y1 & FIX4_MASK); i > 0; i--)
  103. {
  104. x1 += XInc;
  105. Error += ErrorUp;
  106. if (Error >= 0)
  107. {
  108. Error -= yDelta;
  109. x1++;
  110. }
  111. }
  112. // y1 += FIX4_MASK;
  113. }
  114. if ((x1 & FIX4_MASK) != 0)
  115. {
  116. Error -= yDelta * (FIX4_ONE - (x1 & FIX4_MASK));
  117. x1 += FIX4_MASK; // to get the ceiling
  118. }
  119. Error >>= FIX4_PRECISION;
  120. Direction = direction;
  121. XCur = x1 >> FIX4_PRECISION;
  122. YMax = GpFix4Ceiling (y2) - 1;
  123. } // End of GpYDda::Init()
  124. /**************************************************************************\
  125. *
  126. * Function Description:
  127. *
  128. * Advance the DDA to the next raster.
  129. *
  130. * Arguments:
  131. *
  132. * NONE
  133. *
  134. * Return Value:
  135. *
  136. * NONE
  137. *
  138. * Created:
  139. *
  140. * 12/15/1998 DCurtis
  141. *
  142. \**************************************************************************/
  143. VOID
  144. GpYDda::Advance()
  145. {
  146. XCur += XInc;
  147. Error += ErrorUp;
  148. if (Error >= 0)
  149. {
  150. Error -= YDelta;
  151. XCur++;
  152. }
  153. }
  154. #ifndef USE_YSPAN_BUILDER
  155. /**************************************************************************\
  156. *
  157. * Function Description:
  158. *
  159. * Construct a GpRectBuilder object that will output 1 rect at a time
  160. *
  161. * Arguments:
  162. *
  163. * [IN] renderRect - a class that outputs a single rect at a time
  164. *
  165. * Return Value:
  166. *
  167. * NONE
  168. *
  169. * Created:
  170. *
  171. * 12/15/1998 DCurtis
  172. *
  173. \**************************************************************************/
  174. GpRectBuilder::GpRectBuilder(
  175. GpOutputRect * renderRect
  176. )
  177. {
  178. ASSERT(renderRect);
  179. SetValid(FALSE);
  180. if ((renderRect != NULL) && (InitArrays() == Ok))
  181. {
  182. SetValid(TRUE);
  183. FlushRects = this;
  184. RenderRect = renderRect;
  185. RectYMin = 0x7FFFFFFF;
  186. RectHeight = 0;
  187. }
  188. }
  189. /**************************************************************************\
  190. *
  191. * Function Description:
  192. *
  193. * Construct a GpRectBuilder object that will output a set of rects in a
  194. * YSpan (YMin to YMax) at a time.
  195. *
  196. * Arguments:
  197. *
  198. * [IN] flushRects - a class that outputs a Y span at a time
  199. *
  200. * Return Value:
  201. *
  202. * NONE
  203. *
  204. * Created:
  205. *
  206. * 12/15/1998 DCurtis
  207. *
  208. \**************************************************************************/
  209. GpRectBuilder::GpRectBuilder(
  210. GpOutputYSpan * flushRects
  211. )
  212. {
  213. ASSERT(flushRects);
  214. SetValid(FALSE);
  215. if ((flushRects != NULL) && (InitArrays() == Ok))
  216. {
  217. SetValid(TRUE);
  218. FlushRects = flushRects;
  219. RenderRect = NULL;
  220. RectYMin = 0x7FFFFFFF;
  221. RectHeight = 0;
  222. }
  223. }
  224. /**************************************************************************\
  225. *
  226. * Function Description:
  227. *
  228. * Initialize the Rect and Raster arrays that will build up a set of
  229. * X Coordinates within a Y span.
  230. *
  231. * Arguments:
  232. *
  233. * NONE
  234. *
  235. * Return Value:
  236. *
  237. * GpStatus - Ok or failure status
  238. *
  239. * Created:
  240. *
  241. * 12/15/1998 DCurtis
  242. *
  243. \**************************************************************************/
  244. GpStatus
  245. GpRectBuilder::InitArrays()
  246. {
  247. GpStatus status;
  248. status = RectXCoords.ReserveSpace(16);
  249. if (status == Ok)
  250. {
  251. status = RasterXCoords.ReserveSpace(16);
  252. }
  253. return status;
  254. }
  255. /**************************************************************************\
  256. *
  257. * Function Description:
  258. *
  259. * Outputs a single span within a raster. Is called by the rasterizer.
  260. * These spans provide the input for the rect builder.
  261. *
  262. * Arguments:
  263. *
  264. * [IN] y - the Y value of the raster being output
  265. * [IN] xMin - the X value of the left edge
  266. * [IN] xMax - the X value of the right edge (exclusive)
  267. *
  268. * Return Value:
  269. *
  270. * GpStatus - Ok or failure status
  271. *
  272. * Created:
  273. *
  274. * 12/15/1998 DCurtis
  275. *
  276. \**************************************************************************/
  277. GpStatus
  278. GpRectBuilder::OutputSpan(
  279. INT y,
  280. INT xMin,
  281. INT xMax // xMax is exclusive
  282. )
  283. {
  284. ASSERT (xMin < xMax);
  285. INT * xCoords;
  286. RasterY = y;
  287. // Test here if xMin == previous xMax and combine spans.
  288. // Some polygons (like the letter W) could benefit from such a check.
  289. // NT4 doesn't handle regions with adjacent spans that aren't combined.
  290. if ((RasterXCoords.GetCount() == 0) || (RasterXCoords.Last() != xMin))
  291. {
  292. if ((xCoords = RasterXCoords.AddMultiple(2)) != NULL)
  293. {
  294. xCoords[0] = xMin;
  295. xCoords[1] = xMax;
  296. return Ok;
  297. }
  298. return OutOfMemory;
  299. }
  300. else
  301. {
  302. RasterXCoords.Last() = xMax;
  303. }
  304. return Ok;
  305. }
  306. /**************************************************************************\
  307. *
  308. * Function Description:
  309. *
  310. * Called by the rasterizer when all the spans of a raster (Y value)
  311. * have been output.
  312. *
  313. * Arguments:
  314. *
  315. * NONE
  316. *
  317. * Return Value:
  318. *
  319. * GpStatus - Ok or failure status
  320. *
  321. * Created:
  322. *
  323. * 12/15/1998 DCurtis
  324. *
  325. \**************************************************************************/
  326. GpStatus
  327. GpRectBuilder::EndRaster()
  328. {
  329. INT rectXCount = RectXCoords.GetCount();
  330. INT rasterXCount = RasterXCoords.GetCount();
  331. INT * rasterXCoords = RasterXCoords.GetDataBuffer();
  332. GpStatus status = Ok;
  333. if (rectXCount != 0)
  334. {
  335. INT * rectXCoords = RectXCoords.GetDataBuffer();
  336. if ((RasterY == (RectYMin + RectHeight)) &&
  337. (rasterXCount == rectXCount))
  338. {
  339. if (rasterXCount == 2)
  340. {
  341. if ((rasterXCoords[0] == rectXCoords[0]) &&
  342. (rasterXCoords[1] == rectXCoords[1]))
  343. {
  344. FoundRectMatch:
  345. RasterXCoords.Reset(FALSE);
  346. RectHeight++;
  347. return Ok;
  348. }
  349. }
  350. else if (GpMemcmp(rasterXCoords, rectXCoords,
  351. rectXCount * sizeof(INT)) == 0)
  352. {
  353. goto FoundRectMatch;
  354. }
  355. }
  356. status = FlushRects->OutputYSpan(
  357. RectYMin,
  358. RectYMin + RectHeight,
  359. rectXCoords,
  360. rectXCount);
  361. }
  362. // if we get here, either the RectXCoords is empty or
  363. // it has just been flushed
  364. RectXCoords.Reset(FALSE);
  365. if (rasterXCount > 0)
  366. {
  367. status = static_cast<GpStatus>
  368. (status | RectXCoords.AddMultiple(rasterXCoords, rasterXCount));
  369. RasterXCoords.Reset(FALSE);
  370. RectHeight = 1;
  371. RectYMin = RasterY;
  372. }
  373. return status;
  374. }
  375. /**************************************************************************\
  376. *
  377. * Function Description:
  378. *
  379. * Called by the rasterizer when all the spans of all the rasters
  380. * have been output.
  381. *
  382. * Arguments:
  383. *
  384. * NONE
  385. *
  386. * Return Value:
  387. *
  388. * GpStatus - Ok or failure status
  389. *
  390. * Created:
  391. *
  392. * 12/15/1998 DCurtis
  393. *
  394. \**************************************************************************/
  395. GpStatus
  396. GpRectBuilder::End()
  397. {
  398. INT rectXCount = RectXCoords.GetCount();
  399. if (rectXCount != 0)
  400. {
  401. return FlushRects->OutputYSpan(
  402. RectYMin,
  403. RectYMin + RectHeight,
  404. RectXCoords.GetDataBuffer(),
  405. rectXCount);
  406. }
  407. return Ok;
  408. }
  409. /**************************************************************************\
  410. *
  411. * Function Description:
  412. *
  413. * If the rect builder was constructed to output 1 rect at a time, then
  414. * this method is called to do that after a Y span is completed.
  415. *
  416. * Arguments:
  417. *
  418. * [IN] yMin - top of the Y span
  419. * [IN] yMax - bottom of the Y span
  420. * [IN] xCoords - array of x coordinates
  421. * [IN] numXCoords - number of x coordinates (>= 2, multiple of 2)
  422. *
  423. * Return Value:
  424. *
  425. * GpStatus - Ok or failure status
  426. *
  427. * Created:
  428. *
  429. * 12/15/1998 DCurtis
  430. *
  431. \**************************************************************************/
  432. GpStatus
  433. GpRectBuilder::OutputYSpan(
  434. INT yMin,
  435. INT yMax,
  436. INT * xCoords, // even number of X coordinates
  437. INT numXCoords // must be a multiple of 2
  438. )
  439. {
  440. ASSERT (yMin < yMax);
  441. ASSERT (xCoords);
  442. ASSERT ((numXCoords >= 2) && ((numXCoords & 0x00000001) == 0))
  443. GpStatus status;
  444. INT i = 0;
  445. do
  446. {
  447. status = RenderRect->OutputRect(
  448. xCoords[i],
  449. yMin,
  450. xCoords[i+1],
  451. yMax);
  452. i += 2;
  453. } while ((i < numXCoords) && (status == Ok));
  454. return status;
  455. }
  456. #else
  457. /**************************************************************************\
  458. *
  459. * Function Description:
  460. *
  461. * Construct a GpYSpanBuilder object that will output one YSpan
  462. * (YMin to YMax) at a time.
  463. *
  464. * Arguments:
  465. *
  466. * [IN] output - a class that outputs a Y span at a time
  467. *
  468. * Return Value:
  469. *
  470. * NONE
  471. *
  472. * Created:
  473. *
  474. * 12/15/1998 DCurtis
  475. *
  476. \**************************************************************************/
  477. GpYSpanBuilder::GpYSpanBuilder(
  478. GpOutputYSpan * output
  479. )
  480. {
  481. ASSERT(output);
  482. SetValid(FALSE);
  483. if (output != NULL)
  484. {
  485. Output = output;
  486. SetValid(XCoords.ReserveSpace(16) == Ok);
  487. }
  488. }
  489. /**************************************************************************\
  490. *
  491. * Function Description:
  492. *
  493. * Outputs a single span within a raster. Is called by the rasterizer.
  494. * These spans provide the input for the rect builder.
  495. *
  496. * Arguments:
  497. *
  498. * [IN] y - the Y value of the raster being output
  499. * [IN] xMin - the X value of the left edge
  500. * [IN] xMax - the X value of the right edge (exclusive)
  501. *
  502. * Return Value:
  503. *
  504. * GpStatus - Ok or failure status
  505. *
  506. * Created:
  507. *
  508. * 12/15/1998 DCurtis
  509. *
  510. \**************************************************************************/
  511. GpStatus
  512. GpYSpanBuilder::OutputSpan(
  513. INT y,
  514. INT xMin,
  515. INT xMax // xMax is exclusive
  516. )
  517. {
  518. ASSERT (xMin < xMax);
  519. INT * xCoords;
  520. Y = y;
  521. if ((xCoords = XCoords.AddMultiple(2)) != NULL)
  522. {
  523. xCoords[0] = xMin;
  524. xCoords[1] = xMax;
  525. return Ok;
  526. }
  527. return OutOfMemory;
  528. }
  529. /**************************************************************************\
  530. *
  531. * Function Description:
  532. *
  533. * Called by the rasterizer when all the spans of a raster (Y value)
  534. * have been output.
  535. *
  536. * Arguments:
  537. *
  538. * NONE
  539. *
  540. * Return Value:
  541. *
  542. * GpStatus - Ok or failure status
  543. *
  544. * Created:
  545. *
  546. * 12/15/1998 DCurtis
  547. *
  548. \**************************************************************************/
  549. GpStatus
  550. GpYSpanBuilder::EndRaster()
  551. {
  552. INT count = XCoords.GetCount();
  553. // count can be 0
  554. if (count >= 2)
  555. {
  556. INT y = Y;
  557. GpStatus status = Output->OutputYSpan(y, y + 1,
  558. XCoords.GetDataBuffer(), count);
  559. XCoords.Reset(FALSE);
  560. return status;
  561. }
  562. return Ok;
  563. }
  564. #endif // USE_YSPAN_BUILDER
  565. /**************************************************************************\
  566. *
  567. * Macro Description:
  568. *
  569. * Add a newly identified vector to the VectorList. Keep track of the
  570. * direction of the vector, in case we're using the winding rule. Put
  571. * the min y value in y1, so we can sort the vectors by min y. Keep track
  572. * of the min and max y values for the entire list of vectors.
  573. *
  574. * Don't add the vector if this is a horizontal (or near-horizontal) line.
  575. * We don't scan-convert horizontal lines. Note that this check will also
  576. * fail if the two points are identical.
  577. *
  578. * Arguments:
  579. *
  580. * [IN] x1 - starting fixed-point x coordinate of vector
  581. * [IN] y1 - starting fixed-point y coordinate of vector
  582. * [IN] x2 - ending fixed-point x coordinate of vector
  583. * [IN] y2 - ending fixed-point y coordinate of vector
  584. *
  585. * [OUT] yMin - set to min of yMin and least y of y1, y2
  586. * [OUT] yMax - set to max of yMax and greatest y of y1, y2
  587. * [OUT] numVectors - incremented by 1
  588. * [OUT] vector - incremented by 1
  589. *
  590. * Return Value:
  591. *
  592. * NONE
  593. *
  594. * Created:
  595. *
  596. * 12/15/1998 DCurtis
  597. *
  598. \**************************************************************************/
  599. #define ADDVECTOR_SETYBOUNDS(x1,y1,x2,y2,yMin,yMax,numVectors,vector,dir) \
  600. if (GpFix4Ceiling(y1) != GpFix4Ceiling(y2)) \
  601. { \
  602. if ((y1) <= (y2)) \
  603. { \
  604. if ((y2) > (yMax)) \
  605. { \
  606. (yMax) = (y2); \
  607. } \
  608. if ((y1) < (yMin)) \
  609. { \
  610. (yMin) = (y1); \
  611. } \
  612. dir = VectorGoingDown; \
  613. vector->Set((x1),(y1),(x2),(y2),VectorGoingDown); \
  614. } \
  615. else \
  616. { \
  617. if ((y1) > (yMax)) \
  618. { \
  619. (yMax) = (y1); \
  620. } \
  621. if ((y2) < (yMin)) \
  622. { \
  623. (yMin) = (y2); \
  624. } \
  625. dir = VectorGoingUp; \
  626. vector->Set((x2),(y2),(x1),(y1),VectorGoingUp); \
  627. } \
  628. (numVectors)++; \
  629. (vector)++; \
  630. }
  631. // Used by Rasterizer to keep track of each vector in a path.
  632. class RasterizeVector
  633. {
  634. public:
  635. FIX4 X1;
  636. FIX4 Y1; // Min Y
  637. FIX4 X2;
  638. FIX4 Y2; // Max Y
  639. GpVectorDirection Direction; // VectorGoingUp or VectorGoingDown
  640. VOID Set(FIX4 x1, FIX4 y1, FIX4 x2, FIX4 y2, GpVectorDirection direction)
  641. {
  642. X1 = x1;
  643. Y1 = y1;
  644. X2 = x2;
  645. Y2 = y2;
  646. Direction = direction;
  647. }
  648. };
  649. typedef DynArray<RasterizeVector> DynVectorArray;
  650. /**************************************************************************\
  651. *
  652. * Function Description:
  653. *
  654. * Rasterizer for non-convex polygons.
  655. *
  656. * Rasterize a path into a set of spans on each raster (Y value) that the
  657. * path intersects. The specified output object is used to output the spans.
  658. * The Y values of the specified clip bounds (if any) are used to speed the
  659. * rasterization process by avoiding the processing of vectors that are
  660. * outside those bounds. However, it is assumed that at least part of the
  661. * path is visible in the vertical span of the clip bounds.
  662. *
  663. * This algorithm is based on the one documented in
  664. * Foley & Van Dam, Version 1, pp. 456 - 460.
  665. *
  666. * Starting with the min y value and ending with the max y value, each
  667. * raster (Y value) is rasterized (output) one at a time.
  668. *
  669. * (1) On each raster, check to see if new vectors need to be added to
  670. * the ActiveVectorList. When an vector is added, DDA information about
  671. * that vector is computed so that the intersection of that vector with
  672. * each raster can be computed.
  673. *
  674. * (2) Sort the ActiveVectorList in order of increasing x.
  675. *
  676. * (3) Using either the alternate rule or the winding rule, output the span
  677. * between the appropriate vectors.
  678. *
  679. * (4) Remove any vectors from the ActiveVectorList for which the current
  680. * raster is the max y of the vector.
  681. *
  682. * (5) Calculate the intersection of the next raster with all the vectors
  683. * that are still in the ActiveVectorList (i.e. advance their DDAs).
  684. *
  685. * Arguments:
  686. *
  687. * [IN] yMin - the min y value of the set of vectors
  688. * [IN] yMax - the max y value of the set of vectors
  689. * [IN] numVectors - the number of vectors in the vector list
  690. * [IN] vectorList - the list of vectors to rasterize
  691. * [IN] sortedVectorIndices - vector list sorted by increasing y
  692. * [IN] left - a dda object to use
  693. * [IN] right - a dda object to use
  694. * [IN] output - used to output the spans of the rasterization
  695. * [IN] clipBounds - clipbounds (if any) to use to speed the process
  696. * [IN] useAlternate - whether or not to use the alternate rule
  697. *
  698. * Return Value:
  699. *
  700. * GpStatus - Ok or failure status
  701. *
  702. * Created:
  703. *
  704. * 12/15/1998 DCurtis
  705. *
  706. \**************************************************************************/
  707. GpStatus
  708. NonConvexRasterizer(
  709. INT yMin, // min y of all vectors
  710. INT yMax, // max y of all vectors
  711. INT numVectors, // num vectors in VectorList
  712. RasterizeVector * vectorList, // list of all vectors of path
  713. INT * sortedVectorIndices, // sorted list of vector indices
  714. GpYDda * left,
  715. GpYDda * right,
  716. DpOutputSpan * output,
  717. const GpRect * clipBounds,
  718. BOOL useAlternate
  719. )
  720. {
  721. GpStatus status = Ok;
  722. INT yMinClipped = yMin; // used for clipping
  723. INT yMaxClipped = yMax; // used for clipping
  724. INT y;
  725. INT xMin;
  726. INT xMax;
  727. INT sortedVectorIndex = 0; // idx to sortedVectorIndices
  728. RasterizeVector * vector;
  729. INT i;
  730. INT count;
  731. INT numActiveVectors = 0; // num used in ActiveVectorList
  732. DynArrayIA<GpYDda *, 16> activeVectorList; // active GpYDda vectors
  733. GpYDda ** activeVectors;
  734. GpYDda * activeVector;
  735. activeVectors = reinterpret_cast<GpYDda **>
  736. (activeVectorList.AddMultiple(2));
  737. if (activeVectors == NULL)
  738. {
  739. delete left;
  740. delete right;
  741. return OutOfMemory;
  742. }
  743. activeVectors[0] = left;
  744. activeVectors[1] = right;
  745. if (clipBounds != NULL)
  746. {
  747. yMinClipped = clipBounds->Y;
  748. yMaxClipped = clipBounds->GetBottom();
  749. // There are a few cases where this can happen legitimately.
  750. // For example, the transformed bounds of an object could be
  751. // partially in the clip area although the object isn't.
  752. // Also, a Bezier control point might be in the clip area while
  753. // the actual curve isn't.
  754. if ((yMin > yMaxClipped) || (yMax < yMinClipped))
  755. {
  756. goto DoneNotConvex;
  757. }
  758. if (yMaxClipped > yMax)
  759. {
  760. yMaxClipped = yMax;
  761. }
  762. if (yMinClipped > yMin)
  763. {
  764. while (sortedVectorIndex < numVectors)
  765. {
  766. vector = vectorList + sortedVectorIndices[sortedVectorIndex];
  767. if (GpFix4Ceiling(vector->Y2) >= yMinClipped)
  768. {
  769. yMin = GpFix4Ceiling(vector->Y1);
  770. break;
  771. }
  772. sortedVectorIndex++;
  773. }
  774. }
  775. }
  776. for (y = yMin; (y <= yMaxClipped); y++)
  777. {
  778. // Add any appropriate new vectors to the active vector list
  779. while (sortedVectorIndex < numVectors)
  780. {
  781. vector = vectorList + sortedVectorIndices[sortedVectorIndex];
  782. if (GpFix4Ceiling(vector->Y1) != y)
  783. {
  784. break;
  785. }
  786. // Clip the vector (but only against Y or
  787. // we wouldn't get the right number of runs)
  788. if (GpFix4Ceiling(vector->Y2) >= yMinClipped)
  789. {
  790. if (numActiveVectors < activeVectorList.GetCount())
  791. {
  792. activeVector = activeVectors[numActiveVectors];
  793. }
  794. else
  795. {
  796. activeVector = left->CreateYDda();
  797. if ((activeVector == NULL) ||
  798. (activeVectorList.Add(activeVector) != Ok))
  799. {
  800. delete activeVector;
  801. status = OutOfMemory;
  802. goto DoneNotConvex;
  803. }
  804. // adding the vector could change the data buffer
  805. activeVectors = reinterpret_cast<GpYDda **>
  806. (activeVectorList.GetDataBuffer());
  807. }
  808. activeVector->Init(
  809. vector->X1,
  810. vector->Y1,
  811. vector->X2,
  812. vector->Y2,
  813. vector->Direction);
  814. numActiveVectors++;
  815. }
  816. sortedVectorIndex++;
  817. }
  818. if (y >= yMinClipped)
  819. {
  820. // Make sure the activeVectorList is sorted in order of
  821. // increasing x. We have to do this every time, even if
  822. // we haven't added any new active vectors, because the
  823. // slopes of the lines can be different, which means they
  824. // could cross.
  825. for (count = 1; count < numActiveVectors; count++)
  826. {
  827. i = count;
  828. do
  829. {
  830. if (activeVectors[i]->GetX() >=
  831. activeVectors[i-1]->GetX())
  832. {
  833. break;
  834. }
  835. activeVector = activeVectors[i-1];
  836. activeVectors[i-1] = activeVectors[i];
  837. activeVectors[i] = activeVector;
  838. } while (--i > 0);
  839. }
  840. // fill the appropriate pixels on the current scan line
  841. if (useAlternate)
  842. {
  843. // Use the alternating rule (also known as even/odd rule)
  844. // to output the spans of a raster between the intersections
  845. // of the vectors with the current scan line.
  846. //
  847. // The alternating rule means that a raster pattern is drawn
  848. // between the 1st and 2nd points and between the 3rd and
  849. // 4th points, etc., but not between the 2nd and 3rd points
  850. // or between the 4th and 5th points, etc.
  851. //
  852. // There could be an odd number of points; for example:
  853. //
  854. // 9 /\
  855. // 8 / \
  856. // 7 / \
  857. // 6 / \
  858. // 5 / \
  859. // 4 /----------\--------/
  860. // 3 \ /
  861. // 2 \ /
  862. // 1 \ /
  863. // 0 \/
  864. //
  865. // On raster y==4, there are 3 points, so the 2nd half of
  866. // the raster does not get output.
  867. for (i = 1; (i < numActiveVectors); i += 2)
  868. {
  869. xMin = activeVectors[i-1]->GetX();
  870. xMax = activeVectors[i]->GetX();
  871. // Make sure the X's aren't equal
  872. if (xMin < xMax)
  873. {
  874. if (output->OutputSpan(y, xMin, xMax) != Ok)
  875. {
  876. status = GenericError;
  877. goto DoneNotConvex;
  878. }
  879. }
  880. }
  881. }
  882. else // Winding
  883. {
  884. GpYDda * leftEdge;
  885. GpYDda * rightEdge;
  886. INT j;
  887. INT direction = 0; // num times going up and down
  888. // There's got to be the same number of lines
  889. // going up as going down before drawing the
  890. // scan line.
  891. for (count = 1; (count < numActiveVectors); count = j + 2)
  892. {
  893. leftEdge = activeVectors[count - 1];
  894. direction += static_cast<INT>(leftEdge->GetDirection());
  895. for (j = count; (j < numActiveVectors); j++)
  896. {
  897. rightEdge = activeVectors[j];
  898. direction += static_cast<INT>
  899. (rightEdge->GetDirection());
  900. if (direction == 0)
  901. {
  902. xMin = leftEdge->GetX();
  903. xMax = rightEdge->GetX();
  904. // Make sure the X's aren't equal
  905. if (xMin < xMax)
  906. {
  907. if (output->OutputSpan(y, xMin, xMax) != Ok)
  908. {
  909. status = GenericError;
  910. goto DoneNotConvex;
  911. }
  912. }
  913. break;
  914. }
  915. }
  916. }
  917. }
  918. if (output->EndRaster() != Ok)
  919. {
  920. status = GenericError;
  921. goto DoneNotConvex;
  922. }
  923. }
  924. // remove any appropriate vectors from the active vector list
  925. // and advance all the DDAs
  926. {
  927. INT activeIndex = 0;
  928. VOID * removedActiveVector;
  929. while (activeIndex < numActiveVectors)
  930. {
  931. activeVector = activeVectors[activeIndex];
  932. if (activeVector->DoneWithVector(y))
  933. {
  934. numActiveVectors--;
  935. if (numActiveVectors > activeIndex)
  936. {
  937. GpMemmove(
  938. &(activeVectors[activeIndex]),
  939. &(activeVectors[activeIndex + 1]),
  940. (numActiveVectors - activeIndex) *
  941. sizeof(activeVectors[0]));
  942. }
  943. activeVectors[numActiveVectors] = activeVector;
  944. }
  945. else
  946. {
  947. activeIndex++;
  948. }
  949. }
  950. }
  951. }
  952. status = output->End();
  953. DoneNotConvex:
  954. numActiveVectors = activeVectorList.GetCount();
  955. ASSERT(numActiveVectors > 0);
  956. activeVectors = reinterpret_cast<GpYDda **>
  957. (activeVectorList.GetDataBuffer());
  958. do
  959. {
  960. delete activeVectors[--numActiveVectors];
  961. } while (numActiveVectors > 0);
  962. return status;
  963. }
  964. /**************************************************************************\
  965. *
  966. * Function Description:
  967. *
  968. * Rasterizer for convex polygons.
  969. *
  970. * Uses basically the same algorithm to rasterize, but has a few optimizations
  971. * for when we know the polygon is convex. We know there will only be 2
  972. * active vectors at a time (and only 2). Even though they may cross each
  973. * other, we don't bother sorting them. We just check the X values instead.
  974. * These optimizations provide about a 15% increase in performance.
  975. *
  976. * Arguments:
  977. *
  978. * [IN] yMin - the min y value of the set of vectors
  979. * [IN] yMax - the max y value of the set of vectors
  980. * [IN] numVectors - the number of vectors in the vector list
  981. * [IN] vectorList - the list of vectors to rasterize
  982. * [IN] sortedVectorIndices - vector list sorted by increasing y
  983. * [IN] left - a dda object to use
  984. * [IN] right - a dda object to use
  985. * [IN] output - used to output the spans of the rasterization
  986. * [IN] clipBounds - clipbounds (if any) to use to speed the process
  987. *
  988. * Return Value:
  989. *
  990. * GpStatus - Ok or failure status
  991. *
  992. * Created:
  993. *
  994. * 2/24/1999 DCurtis
  995. *
  996. \**************************************************************************/
  997. GpStatus
  998. ConvexRasterizer(
  999. INT yMin, // min y of all vectors
  1000. INT yMax, // max y of all vectors
  1001. INT numVectors, // num vectors in VectorList
  1002. RasterizeVector * vectorList, // list of all vectors of path
  1003. INT * sortedVectorIndices, // sorted list of vector indices
  1004. GpYDda * dda1,
  1005. GpYDda * dda2,
  1006. DpOutputSpan * output,
  1007. const GpRect * clipBounds
  1008. )
  1009. {
  1010. GpStatus status = Ok;
  1011. INT yMinClipped = yMin; // used for clipping
  1012. INT yMaxClipped = yMax; // used for clipping
  1013. INT y;
  1014. INT x1;
  1015. INT x2;
  1016. INT sortedVectorIndex = 0; // idx to sortedVectorIndices
  1017. RasterizeVector * vector1;
  1018. RasterizeVector * vector2;
  1019. if (clipBounds != NULL)
  1020. {
  1021. yMinClipped = clipBounds->Y;
  1022. yMaxClipped = clipBounds->GetBottom();
  1023. // There are a few cases where this can happen legitimately.
  1024. // For example, the transformed bounds of an object could be
  1025. // partially in the clip area although the object isn't.
  1026. // Also, a Bezier control point might be in the clip area while
  1027. // the actual curve isn't.
  1028. if ((yMin > yMaxClipped) || (yMax < yMinClipped))
  1029. {
  1030. goto DoneConvex;
  1031. }
  1032. if (yMaxClipped > yMax)
  1033. {
  1034. yMaxClipped = yMax;
  1035. }
  1036. if (yMinClipped > yMin)
  1037. {
  1038. RasterizeVector * vector;
  1039. vector1 = NULL;
  1040. while (sortedVectorIndex < numVectors)
  1041. {
  1042. vector = vectorList+sortedVectorIndices[sortedVectorIndex++];
  1043. if (GpFix4Ceiling(vector->Y2) >= yMinClipped)
  1044. {
  1045. if (vector1 == NULL)
  1046. {
  1047. vector1 = vector;
  1048. }
  1049. else
  1050. {
  1051. vector2 = vector;
  1052. goto HaveVectors;
  1053. }
  1054. }
  1055. }
  1056. ASSERT(0);
  1057. status = InvalidParameter; // either not convex or clipped out
  1058. goto DoneConvex;
  1059. }
  1060. }
  1061. vector1 = vectorList + sortedVectorIndices[0];
  1062. vector2 = vectorList + sortedVectorIndices[1];
  1063. sortedVectorIndex = 2;
  1064. HaveVectors:
  1065. dda1->Init(vector1->X1, vector1->Y1,
  1066. vector1->X2, vector1->Y2,
  1067. VectorGoingUp);
  1068. dda2->Init(vector2->X1, vector2->Y1,
  1069. vector2->X2, vector2->Y2,
  1070. VectorGoingUp);
  1071. // For clipping case, we have to advance the first vector to catch up
  1072. // to the start of the 2nd vector.
  1073. {
  1074. yMin = GpFix4Ceiling(vector2->Y1);
  1075. for (INT yMinVector1 = GpFix4Ceiling(vector1->Y1);
  1076. yMinVector1 < yMin; yMinVector1++)
  1077. {
  1078. dda1->Advance();
  1079. }
  1080. }
  1081. for (y = yMin; (y <= yMaxClipped); y++)
  1082. {
  1083. if (y >= yMinClipped)
  1084. {
  1085. // fill the appropriate pixels on the current scan line
  1086. x1 = dda1->GetX();
  1087. x2 = dda2->GetX();
  1088. // Make sure the X's aren't equal before outputting span
  1089. if (x1 < x2)
  1090. {
  1091. if (output->OutputSpan(y, x1, x2) == Ok)
  1092. {
  1093. if (output->EndRaster() == Ok)
  1094. {
  1095. goto DoneCheck;
  1096. }
  1097. }
  1098. status = GenericError;
  1099. goto DoneConvex;
  1100. }
  1101. else if (x1 > x2)
  1102. {
  1103. if (output->OutputSpan(y, x2, x1) == Ok)
  1104. {
  1105. if (output->EndRaster() == Ok)
  1106. {
  1107. goto DoneCheck;
  1108. }
  1109. }
  1110. status = GenericError;
  1111. goto DoneConvex;
  1112. }
  1113. }
  1114. DoneCheck:
  1115. if (dda1->DoneWithVector(y))
  1116. {
  1117. if (sortedVectorIndex >= numVectors)
  1118. {
  1119. break;
  1120. }
  1121. vector1 = vectorList + sortedVectorIndices[sortedVectorIndex++];
  1122. ASSERT(GpFix4Ceiling(vector1->Y1) == (y + 1));
  1123. dda1->Init(vector1->X1, vector1->Y1,
  1124. vector1->X2, vector1->Y2,
  1125. VectorGoingUp);
  1126. }
  1127. if (dda2->DoneWithVector(y))
  1128. {
  1129. if (sortedVectorIndex >= numVectors)
  1130. {
  1131. ASSERT(0);
  1132. break;
  1133. }
  1134. vector2 = vectorList + sortedVectorIndices[sortedVectorIndex++];
  1135. ASSERT(GpFix4Ceiling(vector2->Y1) == (y + 1));
  1136. dda2->Init(vector2->X1, vector2->Y1,
  1137. vector2->X2, vector2->Y2,
  1138. VectorGoingUp);
  1139. }
  1140. }
  1141. status = output->End();
  1142. DoneConvex:
  1143. delete dda1;
  1144. delete dda2;
  1145. return status;
  1146. }
  1147. #define NUM_ENUMERATE_POINTS 32
  1148. /**************************************************************************\
  1149. *
  1150. * Function Description:
  1151. *
  1152. * Perform a simple partition sort on a list indexing into the vector list.
  1153. * The result is a sorted index array keyed on the vertex array Y1 coordinate.
  1154. * The index array is sorted in place and in ascending order.
  1155. *
  1156. * Arguments:
  1157. *
  1158. * v is the vertex list.
  1159. * F, L - First and Last pointer in the index array.
  1160. *
  1161. * Created:
  1162. *
  1163. * 09/16/2000 asecchia
  1164. *
  1165. \**************************************************************************/
  1166. void QuickSortIndex(
  1167. RasterizeVector *v,
  1168. int *F,
  1169. int *L
  1170. )
  1171. {
  1172. if(F < L)
  1173. {
  1174. // Find the median position.
  1175. int median = *(F + (L-F)/2);
  1176. int *i = F;
  1177. int *j = L;
  1178. while(i<j)
  1179. {
  1180. // seek for elements in the wrong partition.
  1181. while(v[*i].Y1 < v[median].Y1) {i++;}
  1182. while(v[*j].Y1 > v[median].Y1) {j--;}
  1183. if(i>=j) { break; }
  1184. // Swap.
  1185. int temp = *i;
  1186. *i = *j;
  1187. *j = temp;
  1188. // tie breaker - handle the case where [*i] == [*j] == [median], but
  1189. // i != j. Only possible with multiple copies of the same entry.
  1190. if(v[*i].Y1 == v[*j].Y1) { i++; }
  1191. }
  1192. // Call recursively for the two sub-partitions. The partitions don't
  1193. // include position i because it is correctly positioned.
  1194. QuickSortIndex(v, F, i-1);
  1195. QuickSortIndex(v, i+1, L);
  1196. }
  1197. }
  1198. /**************************************************************************\
  1199. *
  1200. * Function Description:
  1201. *
  1202. * Initialize the data needed for the rasterization and invoke the
  1203. * appropriate rasterizer (convex or non-convex).
  1204. *
  1205. * Arguments:
  1206. *
  1207. * [IN] path - the path to rasterize
  1208. * [IN] matrix - the matrix to transform the path points by
  1209. * [IN] fillMode - the fill mode to use (Alternate or Winding)
  1210. * [IN] output - used to output the spans of the rasterization
  1211. * [IN] clipBounds - clipbounds (if any) to use to speed the process
  1212. * [IN] yDda - instance of DDA class to use
  1213. * [IN] type - type of enumeration
  1214. * [IN] strokeWidth - for wide line rasterizing
  1215. *
  1216. * Return Value:
  1217. *
  1218. * NONE
  1219. *
  1220. * Created:
  1221. *
  1222. * 12/15/1998 DCurtis
  1223. *
  1224. \**************************************************************************/
  1225. GpStatus
  1226. Rasterizer(
  1227. const DpPath * path,
  1228. const GpMatrix * matrix,
  1229. GpFillMode fillMode,
  1230. DpOutputSpan * output,
  1231. REAL dpiX,
  1232. REAL dpiY,
  1233. const GpRect * clipBounds,
  1234. GpYDda * yDda,
  1235. DpEnumerationType type,
  1236. const DpPen * pen
  1237. )
  1238. {
  1239. ASSERT ((path != NULL) && (matrix != NULL) && (output != NULL));
  1240. if ((dpiX <= 0) || (dpiY <= 0))
  1241. {
  1242. dpiX = Globals::DesktopDpiX;
  1243. dpiY = Globals::DesktopDpiY;
  1244. }
  1245. GpStatus status = Ok;
  1246. FIX4 yMin; // min y of all vectors
  1247. FIX4 yMax; // max y of all vectors
  1248. INT numVectors; // num vectors in VectorList
  1249. RasterizeVector * vectorList = NULL; // list of all vectors of path
  1250. INT * sortedVectorIndices; // sorted list of vector indices
  1251. GpYDda * left;
  1252. GpYDda * right;
  1253. GpPointF pointsF[NUM_ENUMERATE_POINTS];
  1254. BYTE types[NUM_ENUMERATE_POINTS];
  1255. INT count;
  1256. INT estimateVectors;
  1257. GpPathPointType pointType;
  1258. FIX4 xFirst; // first point in sub-path
  1259. FIX4 yFirst;
  1260. FIX4 xStart; // start point of a vector
  1261. FIX4 yStart;
  1262. FIX4 xEnd; // end point of a vector
  1263. FIX4 yEnd;
  1264. RasterizeVector * vector;
  1265. INT i;
  1266. GpVectorDirection direction;
  1267. GpVectorDirection newDirection;
  1268. INT numDirections;
  1269. BOOL multipleSubPaths;
  1270. BOOL isAntiAliased = FALSE;
  1271. const DpPath* flattenedPath = path->GetFlattenedPath(
  1272. matrix,
  1273. type,
  1274. pen
  1275. );
  1276. if(!flattenedPath)
  1277. return OutOfMemory;
  1278. DpPathIterator enumerator(flattenedPath->GetPathPoints(),
  1279. flattenedPath->GetPathTypes(),
  1280. flattenedPath->GetPointCount());
  1281. if(!enumerator.IsValid())
  1282. {
  1283. // No need to rasterize. Exit gracefully.
  1284. goto Done;
  1285. }
  1286. estimateVectors = enumerator.GetCount() +
  1287. enumerator.GetSubpathCount() - 1;
  1288. // The estimate must be >= the actual number of points
  1289. if (estimateVectors < 2)
  1290. {
  1291. goto Done;
  1292. }
  1293. // Allocate vectorList and sortedVectorIndices together
  1294. vectorList = static_cast<RasterizeVector *>
  1295. (GpMalloc((estimateVectors * sizeof(RasterizeVector)) +
  1296. (estimateVectors * sizeof(INT))));
  1297. if (vectorList == NULL)
  1298. {
  1299. status = OutOfMemory;
  1300. goto Done;
  1301. }
  1302. sortedVectorIndices = reinterpret_cast<INT*>
  1303. (vectorList + estimateVectors);
  1304. // enumerate the first set of points from the path
  1305. count = enumerator.Enumerate(pointsF, types, NUM_ENUMERATE_POINTS);
  1306. ASSERT (count <= NUM_ENUMERATE_POINTS);
  1307. // We know we are done enumerating when we get back a 0 count
  1308. if (count <= 0)
  1309. {
  1310. goto Done;
  1311. }
  1312. // Keep track of direction changes as a way to know if we can use
  1313. // the convex rasterizer or not. As long as there is only 1 sub-path
  1314. // and there are at most 3 directions (e.g. down, up, down),
  1315. // we can use the convex rasterizer.
  1316. direction = VectorHorizontal;
  1317. newDirection = VectorHorizontal;
  1318. numDirections = 0;
  1319. multipleSubPaths = FALSE;
  1320. vector = vectorList;
  1321. numVectors = 0;
  1322. xFirst = GpRealToFix4(pointsF[0].X);
  1323. yFirst = GpRealToFix4(pointsF[0].Y);
  1324. xStart = xEnd = xFirst;
  1325. yStart = yEnd = yFirst;
  1326. yMin = yMax = yFirst;
  1327. // Add all the vectors to the vector list. The vector list keeps
  1328. // the coordinates as fixed point values (28.4). As each one is
  1329. // added, YMin and YMax are updated.
  1330. // Each sub-path is automatically closed, even if it was not
  1331. // specifically asked to be closed.
  1332. for (i = 1;; i++)
  1333. {
  1334. if (i == count)
  1335. {
  1336. count = enumerator.Enumerate(pointsF, types, 32);
  1337. ASSERT (count <= 32);
  1338. if (count <= 0)
  1339. {
  1340. // Close the last subpath, if necessary
  1341. ADDVECTOR_SETYBOUNDS(xEnd, yEnd, xFirst, yFirst, yMin, yMax,
  1342. numVectors, vector, newDirection);
  1343. ASSERT (numVectors <= estimateVectors);
  1344. if(newDirection != direction) // for convex test
  1345. {
  1346. numDirections++;
  1347. direction = newDirection;
  1348. }
  1349. break;
  1350. }
  1351. i = 0;
  1352. }
  1353. pointType = static_cast<GpPathPointType>
  1354. (types[i] & PathPointTypePathTypeMask);
  1355. if (pointType != PathPointTypeStart)
  1356. {
  1357. ASSERT(pointType == PathPointTypeLine);
  1358. xEnd = GpRealToFix4(pointsF[i].X);
  1359. yEnd = GpRealToFix4(pointsF[i].Y);
  1360. ADDVECTOR_SETYBOUNDS (xStart, yStart, xEnd, yEnd, yMin, yMax,
  1361. numVectors, vector, newDirection);
  1362. ASSERT (numVectors <= estimateVectors);
  1363. if(newDirection != direction) // for convex test
  1364. {
  1365. numDirections++;
  1366. direction = newDirection;
  1367. }
  1368. }
  1369. else // it is a start point
  1370. {
  1371. // Close the previous subpath, if necessary
  1372. ADDVECTOR_SETYBOUNDS(xEnd, yEnd, xFirst, yFirst, yMin, yMax,
  1373. numVectors, vector, newDirection);
  1374. ASSERT (numVectors <= estimateVectors);
  1375. xFirst = GpRealToFix4(pointsF[i].X);
  1376. yFirst = GpRealToFix4(pointsF[i].Y);
  1377. xEnd = xFirst;
  1378. yEnd = yFirst;
  1379. // Can't use convex rasterizer for more than one sub-path
  1380. // unless we've specifically been told it's Ok to do so.
  1381. multipleSubPaths = TRUE;
  1382. }
  1383. xStart = xEnd;
  1384. yStart = yEnd;
  1385. }
  1386. if (numVectors < 2)
  1387. {
  1388. goto Done;
  1389. }
  1390. yMin = GpFix4Ceiling (yMin); // convert to int
  1391. yMax = GpFix4Ceiling (yMax) - 1; // convert to int
  1392. // Initialize and sort the vector indices in order of
  1393. // increasing yMin values.
  1394. // All the vectors must be set up first in the VectorList.
  1395. // Initialize the index list.
  1396. for(INT count = 0; count < numVectors; count++)
  1397. {
  1398. sortedVectorIndices[count] = count;
  1399. }
  1400. // Sort the index list.
  1401. QuickSortIndex(
  1402. vectorList,
  1403. &sortedVectorIndices[0],
  1404. &sortedVectorIndices[numVectors-1]
  1405. );
  1406. left = yDda;
  1407. if (left == NULL)
  1408. {
  1409. left = new GpYDda();
  1410. if (left == NULL)
  1411. {
  1412. status = OutOfMemory;
  1413. goto Done;
  1414. }
  1415. }
  1416. right = left->CreateYDda();
  1417. if (right == NULL)
  1418. {
  1419. status = OutOfMemory;
  1420. delete left;
  1421. goto Done;
  1422. }
  1423. if ((flattenedPath->IsConvex()) ||
  1424. ((!multipleSubPaths) && (numDirections <= 3)))
  1425. {
  1426. status = ConvexRasterizer(yMin, yMax, numVectors, vectorList,
  1427. sortedVectorIndices, left, right,
  1428. output, clipBounds);
  1429. }
  1430. else
  1431. {
  1432. status = NonConvexRasterizer(yMin, yMax, numVectors, vectorList,
  1433. sortedVectorIndices, left, right,
  1434. output, clipBounds,
  1435. (fillMode == FillModeAlternate));
  1436. }
  1437. Done:
  1438. GpFree(vectorList);
  1439. delete flattenedPath;
  1440. return status;
  1441. }
  1442. /**************************************************************************\
  1443. *
  1444. * Function Description:
  1445. *
  1446. * Rasterize a path into a set of spans on each raster (Y value) that the
  1447. * path intersects. The specified output object is used to output the spans.
  1448. *
  1449. * First the clipping is looked at to determine if the path is visible.
  1450. * If not, we're done. If totally visible, no clipping needed. Otherwise,
  1451. * set up the clip region to handle the clipping of this path. The output
  1452. * method of the rasterizer is the clip region which then clips the span
  1453. * before calling the real output method.
  1454. *
  1455. * Arguments:
  1456. *
  1457. * [IN] path - the path to rasterize
  1458. * [IN] matrix - the matrix to transform the path points by
  1459. * [IN] fillMode - the fill mode to use (Alternate or Winding)
  1460. * [IN] output - the object used to output the spans of the rasterization
  1461. * [IN] clipRegion - clip region to clip against (or NULL)
  1462. * [IN] drawBounds - bounds of the path in device units
  1463. * [IN] yDda - instance of DDA class to use
  1464. * [IN] type - type of enumeration
  1465. * [IN] strokeWidth - for wide line rasterizing
  1466. *
  1467. * Return Value:
  1468. *
  1469. * GpStatus - Ok or failure status
  1470. *
  1471. * Created:
  1472. *
  1473. * 01/12/1999 DCurtis
  1474. *
  1475. \**************************************************************************/
  1476. GpStatus
  1477. Rasterize(
  1478. const DpPath * path,
  1479. GpMatrix * matrix,
  1480. GpFillMode fillMode,
  1481. DpOutputSpan * output,
  1482. DpClipRegion * clipRegion,
  1483. const GpRect * drawBounds,
  1484. REAL dpiX,
  1485. REAL dpiY,
  1486. GpYDda * yDda,
  1487. DpEnumerationType type,
  1488. const DpPen * pen
  1489. )
  1490. {
  1491. ASSERT ((path != NULL) && (matrix != NULL) && (output != NULL));
  1492. ASSERT ((clipRegion != NULL) && (drawBounds != NULL));
  1493. GpRect clipBounds;
  1494. GpRect * clipBoundsPointer = NULL;
  1495. DpRegion::Visibility visibility;
  1496. visibility = clipRegion->GetRectVisibility(
  1497. drawBounds->X,
  1498. drawBounds->Y,
  1499. drawBounds->X + drawBounds->Width,
  1500. drawBounds->Y + drawBounds->Height);
  1501. switch (visibility)
  1502. {
  1503. case DpRegion::Invisible:
  1504. return Ok;
  1505. case DpRegion::TotallyVisible: // No clipping needed
  1506. break;
  1507. default: // Need to clip
  1508. clipRegion->GetBounds(&clipBounds);
  1509. clipBoundsPointer = &clipBounds;
  1510. clipRegion->InitClipping(output, drawBounds->Y);
  1511. output = clipRegion;
  1512. break;
  1513. }
  1514. GpStatus status = Rasterizer(path, matrix, fillMode, output, dpiX, dpiY,
  1515. clipBoundsPointer, yDda, type, pen);
  1516. if (clipRegion != NULL)
  1517. {
  1518. clipRegion->EndClipping();
  1519. }
  1520. return status;
  1521. }