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.

5171 lines
144 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * DpRegion.cpp
  8. *
  9. * Abstract:
  10. *
  11. * DpRegion class operates on scan-converted Y spans of rects
  12. *
  13. * Created:
  14. *
  15. * 12/17/1998 DCurtis
  16. *
  17. \**************************************************************************/
  18. #include "precomp.hpp"
  19. //#define DEBUG_REGION 1
  20. /**************************************************************************\
  21. *
  22. * Function Description:
  23. *
  24. * Do a binary search of the horizontal tessellation structure to find
  25. * the Y Span containing y. If y is inside a Y Span, that span will be
  26. * returned. If y is inside the region extent but not inside a Y Span,
  27. * the span whose yMin > y will be returned. If y is less than the region
  28. * extent, the first Y span will be returned. If y is greater than the
  29. * region extent, the last Y Span will be returned.
  30. *
  31. * Arguments:
  32. *
  33. * [IN] y - y value to search for
  34. * [OUT] ySpanFound - y span pointer found by the search
  35. * [OUT] spanIndexFound - y span index found by the search
  36. *
  37. * Return Value:
  38. *
  39. * TRUE - found a y span that includes the y value
  40. * FALSE - the y span does not include the y value
  41. *
  42. * Created:
  43. *
  44. * 01/06/1999 DCurtis
  45. *
  46. \**************************************************************************/
  47. BOOL
  48. DpComplexRegion::YSpanSearch(
  49. INT y,
  50. INT ** ySpanFound,
  51. INT * spanIndexFound
  52. )
  53. {
  54. INT indexMin = 0;
  55. INT indexMax = NumYSpans - 1;
  56. INT indexMiddle = YSearchIndex;
  57. INT * ySpan = GetYSpan (indexMiddle);
  58. ASSERT((indexMiddle >= indexMin) && (indexMiddle <= indexMax));
  59. for (;;)
  60. {
  61. if (y >= ySpan[YSPAN_YMIN])
  62. {
  63. if (y < ySpan[YSPAN_YMAX])
  64. {
  65. *ySpanFound = ySpan;
  66. *spanIndexFound = indexMiddle;
  67. return TRUE;
  68. }
  69. else
  70. {
  71. // If only 1 span, this could go past the indexMax
  72. indexMin = indexMiddle + 1;
  73. }
  74. }
  75. else
  76. {
  77. indexMax = indexMiddle;
  78. }
  79. if (indexMin >= indexMax)
  80. {
  81. ySpan = GetYSpan (indexMax);
  82. *ySpanFound = ySpan;
  83. *spanIndexFound = indexMax;
  84. return (y >= ySpan[YSPAN_YMIN]) && (y < ySpan[YSPAN_YMAX]);
  85. }
  86. // If there are only 2 elements left to check, then
  87. // indexMiddle is set to indexMin.
  88. indexMiddle = (indexMin + indexMax) >> 1;
  89. ySpan = GetYSpan (indexMiddle);
  90. }
  91. }
  92. /**************************************************************************\
  93. *
  94. * Function Description:
  95. *
  96. * Determine if the specified point is inside this region.
  97. *
  98. * Arguments:
  99. *
  100. * [IN] x - x coordinate of point
  101. * [IN] y - y coordinate of point
  102. *
  103. * Return Value:
  104. *
  105. * TRUE - point is inside the region
  106. * FALSE - point is not inside the region
  107. *
  108. * Created:
  109. *
  110. * 01/06/1999 DCurtis
  111. *
  112. \**************************************************************************/
  113. BOOL
  114. DpRegion::PointInside(
  115. INT x,
  116. INT y
  117. )
  118. {
  119. ASSERT(IsValid());
  120. if (ComplexData == NULL)
  121. {
  122. #if 0
  123. if (Infinite)
  124. {
  125. return TRUE;
  126. }
  127. if (Empty)
  128. {
  129. return FALSE;
  130. }
  131. #endif
  132. return ((x >= XMin) && (x < XMax) &&
  133. (y >= YMin) && (y < YMax));
  134. }
  135. else
  136. {
  137. INT * ySpan;
  138. INT ySpanIndex;
  139. ComplexData->ResetSearchIndex();
  140. if (ComplexData->YSpanSearch (y, &ySpan, &ySpanIndex))
  141. {
  142. INT * xSpan;
  143. INT numXCoords;
  144. xSpan = ComplexData->XCoords + ySpan[YSPAN_XOFFSET];
  145. numXCoords = ySpan[YSPAN_XCOUNT];
  146. for (;;)
  147. {
  148. if (x < xSpan[1])
  149. {
  150. if (x >= xSpan[0])
  151. {
  152. return TRUE;
  153. }
  154. break;
  155. }
  156. if ((numXCoords -= 2) <= 0)
  157. {
  158. break;
  159. }
  160. xSpan += 2;
  161. }
  162. }
  163. return FALSE;
  164. }
  165. }
  166. /**************************************************************************\
  167. *
  168. * Function Description:
  169. *
  170. * Determine the visibility of the specified rectangle.
  171. *
  172. * Note that some rects that could return ClippedVisible end up returning
  173. * PartiallyVisible (for performance reasons).
  174. *
  175. * Arguments:
  176. *
  177. * [IN] xMin - minimum x of rect
  178. * [IN] yMin - minimum y of rect
  179. * [IN] xMax - maximum x of rect (exclusive)
  180. * [IN] yMax - maximum y of rect (exclusive)
  181. * [OUT] rectClipped - used when ClippedVisible is returned (can be NULL)
  182. *
  183. * Return Value:
  184. *
  185. * Visibility
  186. * Invisible - rect is completely outside all region rects
  187. * TotallyVisible - rect is completely inside a region rect
  188. * ClippedVisible - rect intersects 1 and only 1 region rect
  189. * PartiallyVisible - rect partially intersects at least 1 region rect
  190. *
  191. * Created:
  192. *
  193. * 01/06/1999 DCurtis
  194. *
  195. \**************************************************************************/
  196. DpRegion::Visibility
  197. DpRegion::GetRectVisibility(
  198. INT xMin,
  199. INT yMin,
  200. INT xMax, // exclusive
  201. INT yMax, // exclusive
  202. GpRect * rectClipped
  203. )
  204. {
  205. ASSERT(IsValid());
  206. ASSERT((xMin < xMax) && (yMin < yMax));
  207. Visibility visibility = ClippedVisible;
  208. if (Infinite)
  209. {
  210. IsTotallyVisible:
  211. if (rectClipped != NULL)
  212. {
  213. rectClipped->X = xMin;
  214. rectClipped->Y = yMin;
  215. rectClipped->Width = xMax - xMin;
  216. rectClipped->Height = yMax - yMin;
  217. }
  218. return TotallyVisible;
  219. }
  220. BOOL simpleRegion = (ComplexData == NULL);
  221. if (!Empty)
  222. {
  223. // If it is a simple region (only 1 rect) and the specified rect is
  224. // completely inside the region, then trivially accept it
  225. if (simpleRegion &&
  226. (xMin >= XMin) && (yMin >= YMin) &&
  227. (xMax <= XMax) && (yMax <= YMax))
  228. {
  229. goto IsTotallyVisible;
  230. }
  231. // Try to trivially reject rectangle.
  232. if ((xMax > XMin) && (xMin < XMax) &&
  233. (yMax > YMin) && (yMin < YMax))
  234. {
  235. // Couldn't trivially reject
  236. // If simple region, clip it against the region
  237. if (simpleRegion)
  238. {
  239. ClipToRgnExtent:
  240. if (rectClipped)
  241. {
  242. INT xMinTmp = (xMin > XMin) ? xMin : XMin;
  243. INT xMaxTmp = (xMax < XMax) ? xMax : XMax;
  244. INT yMinTmp = (yMin > YMin) ? yMin : YMin;
  245. INT yMaxTmp = (yMax < YMax) ? yMax : YMax;
  246. rectClipped->X = xMinTmp;
  247. rectClipped->Y = yMinTmp;
  248. rectClipped->Width = xMaxTmp - xMinTmp;
  249. rectClipped->Height = yMaxTmp - yMinTmp;
  250. }
  251. return visibility;
  252. }
  253. // else not a simple region -- see if the rect falls
  254. // within one of the region rects
  255. INT * ySpanYMin;
  256. INT * ySpanYMax;
  257. INT * xSpan;
  258. INT numXCoords;
  259. INT ySpanIndex;
  260. BOOL yMinInside;
  261. BOOL yMaxInside;
  262. // Don't resetSearchIndex() here cause if we're calling this
  263. // from regionOverlaps, we want to search from where we left off
  264. // the last time.
  265. yMinInside = ComplexData->YSpanSearch(
  266. yMin,
  267. &ySpanYMin,
  268. &ySpanIndex);
  269. ComplexData->YSearchIndex = ySpanIndex;
  270. yMaxInside = ComplexData->YSpanSearch(
  271. yMax - 1,
  272. &ySpanYMax,
  273. &ySpanIndex);
  274. // See if both values are inside the same Y span
  275. // so that we are totally visible in Y
  276. if (yMinInside && yMaxInside && (ySpanYMin == ySpanYMax))
  277. {
  278. xSpan = ComplexData->XCoords + ySpanYMin[YSPAN_XOFFSET];
  279. numXCoords = ySpanYMin[YSPAN_XCOUNT];
  280. for (;;)
  281. {
  282. if (xMax <= xSpan[0])
  283. {
  284. goto IsInvisible;
  285. }
  286. if (xMin < xSpan[1])
  287. {
  288. // we found an intersection!
  289. if (xMax <= xSpan[1])
  290. {
  291. if (xMin >= xSpan[0])
  292. {
  293. goto IsTotallyVisible;
  294. }
  295. if (rectClipped != NULL)
  296. {
  297. rectClipped->X = xSpan[0];
  298. rectClipped->Width = xMax - xSpan[0];
  299. rectClipped->Y = yMin;
  300. rectClipped->Height = yMax - yMin;
  301. }
  302. return ClippedVisible;
  303. }
  304. // we could look ahead to see if we are clipped visible
  305. visibility = PartiallyVisible;
  306. goto ClipToRgnExtent;
  307. }
  308. // continue on with loop through x spans
  309. if ((numXCoords -= 2) <= 0)
  310. {
  311. break;
  312. }
  313. xSpan += 2;
  314. }
  315. goto IsInvisible;
  316. }
  317. // See if the rect intersects with at least one X Span
  318. // within the set of Y Spans it crosses
  319. // If yMax was not inside a span, ySpanYMax could be
  320. // one span too far
  321. if (yMax <= ySpanYMax[YSPAN_YMIN])
  322. {
  323. ySpanYMax -= YSPAN_SIZE;
  324. }
  325. INT * ySpan = ySpanYMin;
  326. for (;;)
  327. {
  328. xSpan = ComplexData->XCoords + ySpan[YSPAN_XOFFSET];
  329. numXCoords = ySpan[YSPAN_XCOUNT];
  330. for (;;)
  331. {
  332. if (xMax <= xSpan[0])
  333. {
  334. break;
  335. }
  336. if (xMin < xSpan[1])
  337. {
  338. visibility = PartiallyVisible;
  339. goto ClipToRgnExtent;
  340. }
  341. // continue on with loop through x spans
  342. if ((numXCoords -= 2) <= 0)
  343. {
  344. break;
  345. }
  346. xSpan += 2;
  347. }
  348. if (ySpan >= ySpanYMax)
  349. {
  350. break;
  351. }
  352. ySpan += YSPAN_SIZE;
  353. }
  354. }
  355. }
  356. IsInvisible:
  357. // couldn't find a span that it intersected
  358. if (rectClipped)
  359. {
  360. rectClipped->X = 0;
  361. rectClipped->Y = 0;
  362. rectClipped->Width = 0;
  363. rectClipped->Height = 0;
  364. }
  365. return Invisible;
  366. }
  367. /**************************************************************************\
  368. *
  369. * Function Description:
  370. *
  371. * Determine if the specified region overlaps (intersects) this
  372. * region at all.
  373. *
  374. * Arguments:
  375. *
  376. * [IN] region - region to test visibility of
  377. *
  378. * Return Value:
  379. *
  380. * BOOL - whether region is at least partially visible or not
  381. *
  382. * Created:
  383. *
  384. * 01/06/1999 DCurtis
  385. *
  386. \**************************************************************************/
  387. BOOL
  388. DpRegion::RegionVisible(
  389. DpRegion * region
  390. )
  391. {
  392. ASSERT(IsValid());
  393. ASSERT((region != NULL) && region->IsValid());
  394. if (Empty || region->Empty)
  395. {
  396. return FALSE;
  397. }
  398. if (Infinite || region->Infinite)
  399. {
  400. return TRUE;
  401. }
  402. else // neither is empty or infinite
  403. {
  404. Visibility visibility = GetRectVisibility(
  405. region->XMin,
  406. region->YMin,
  407. region->XMax,
  408. region->YMax);
  409. if (visibility == TotallyVisible)
  410. {
  411. return TRUE;
  412. }
  413. if (visibility == Invisible)
  414. {
  415. return FALSE;
  416. }
  417. if ((ComplexData == NULL) && (region->ComplexData == NULL))
  418. {
  419. return TRUE;
  420. }
  421. else
  422. {
  423. INT * ySpan;
  424. INT * ySpanLast;
  425. INT * xSpan;
  426. INT * xCoords;
  427. INT numXCoords;
  428. INT yMin;
  429. INT yMax;
  430. INT ySpanTmp[YSPAN_SIZE];
  431. INT xCoordsTmp[2];
  432. if (region->ComplexData == NULL)
  433. {
  434. ySpan = ySpanTmp;
  435. ySpanLast = ySpanTmp;
  436. ySpan[YSPAN_YMIN] = region->YMin;
  437. ySpan[YSPAN_YMAX] = region->YMax;
  438. ySpan[YSPAN_XOFFSET] = 0;
  439. ySpan[YSPAN_XCOUNT] = 2;
  440. xCoords = xCoordsTmp;
  441. xCoords[0] = region->XMin;
  442. xCoords[1] = region->XMax;
  443. }
  444. else
  445. {
  446. DpComplexRegion * complexData = region->ComplexData;
  447. ySpan = complexData->YSpans;
  448. ySpanLast = ySpan + ((complexData->NumYSpans - 1) * YSPAN_SIZE);
  449. xCoords = complexData->XCoords;
  450. }
  451. if (ComplexData != NULL)
  452. {
  453. ComplexData->ResetSearchIndex();
  454. }
  455. do
  456. {
  457. yMin = ySpan[YSPAN_YMIN];
  458. yMax = ySpan[YSPAN_YMAX];
  459. if (yMin >= YMax)
  460. {
  461. break; // doesn't overlap
  462. }
  463. if (yMax > YMin)
  464. {
  465. xSpan = xCoords + ySpan[YSPAN_XOFFSET];
  466. numXCoords = ySpan[YSPAN_XCOUNT];
  467. for (;;)
  468. {
  469. if (GetRectVisibility(xSpan[0], yMin, xSpan[1], yMax) !=
  470. Invisible)
  471. {
  472. return TRUE;
  473. }
  474. if ((numXCoords -= 2) <= 0)
  475. {
  476. break;
  477. }
  478. xSpan += 2;
  479. }
  480. }
  481. } while ((ySpan += YSPAN_SIZE) <= ySpanLast);
  482. }
  483. }
  484. return FALSE;
  485. }
  486. /**************************************************************************\
  487. *
  488. * Function Description:
  489. *
  490. * Determine if the specified rect intersects this region.
  491. *
  492. * Arguments:
  493. *
  494. * [IN] xMin - minimum x coordinate of rect
  495. * [IN] yMin - minimum y coordinate of rect
  496. * [IN] xMax - maximum x coordinate of rect
  497. * [IN] yMax - maximum y coordinate of rect
  498. *
  499. * Return Value:
  500. *
  501. * BOOL
  502. * TRUE - rect intersects this region
  503. * FALSE - rect does not intersect this region
  504. *
  505. * Created:
  506. *
  507. * 01/06/1999 DCurtis
  508. *
  509. \**************************************************************************/
  510. BOOL
  511. DpRegion::RectVisible(
  512. INT xMin,
  513. INT yMin,
  514. INT xMax,
  515. INT yMax
  516. )
  517. {
  518. ASSERT(IsValid());
  519. // Do Trivial Rejection Test
  520. if ((xMin >= XMax) || (xMax <= XMin) ||
  521. (yMin >= YMax) || (yMax <= YMin) ||
  522. (xMin >= xMax) || (yMin >= yMax)) // must test for empty rect too
  523. {
  524. return FALSE;
  525. }
  526. if (ComplexData == NULL)
  527. {
  528. return TRUE;
  529. }
  530. ComplexData->ResetSearchIndex();
  531. return (GetRectVisibility(xMin, yMin, xMax, yMax) != Invisible);
  532. }
  533. /**************************************************************************\
  534. *
  535. * Function Description:
  536. *
  537. * Determine if the specified rect intersects this region.
  538. *
  539. * Arguments:
  540. *
  541. * [IN] xMin - minimum x coordinate of rect
  542. * [IN] yMin - minimum y coordinate of rect
  543. * [IN] xMax - maximum x coordinate of rect
  544. * [IN] yMax - maximum y coordinate of rect
  545. *
  546. * Return Value:
  547. *
  548. * BOOL
  549. * TRUE - rect intersects this region
  550. * FALSE - rect does not intersect this region
  551. *
  552. * Created:
  553. *
  554. * 01/06/1999 DCurtis
  555. *
  556. \**************************************************************************/
  557. BOOL
  558. DpRegion::RectInside(
  559. INT xMin,
  560. INT yMin,
  561. INT xMax,
  562. INT yMax
  563. )
  564. {
  565. ASSERT(IsValid());
  566. // Do Trivial Rejection Test
  567. if ((xMin < XMin) || (xMax > XMax) ||
  568. (yMin < YMin) || (yMax > YMax))
  569. {
  570. return FALSE;
  571. }
  572. if (ComplexData == NULL)
  573. {
  574. return TRUE;
  575. }
  576. ComplexData->ResetSearchIndex();
  577. return (GetRectVisibility(xMin, yMin, xMax, yMax) == TotallyVisible);
  578. }
  579. #define YSPAN_INC 16
  580. GpStatus
  581. DpRegionBuilder::InitComplexData(
  582. INT ySpans // estimate of number of y spans required for region
  583. )
  584. {
  585. if (ySpans < YSPAN_INC)
  586. {
  587. ySpans = YSPAN_INC;
  588. }
  589. INT xCoordsCapacity;
  590. for (;;)
  591. {
  592. xCoordsCapacity = ySpans * 4;
  593. ComplexData = static_cast<DpComplexRegion *>(
  594. GpMalloc(sizeof(DpComplexRegion) +
  595. (ySpans * (YSPAN_SIZE * sizeof(*(ComplexData->YSpans)))) +
  596. (xCoordsCapacity * sizeof(*(ComplexData->XCoords)))));
  597. if (ComplexData != NULL)
  598. {
  599. break;
  600. }
  601. ySpans >>= 1;
  602. if (ySpans <= (YSPAN_INC / 2))
  603. {
  604. return OutOfMemory;
  605. }
  606. }
  607. DpComplexRegion * complexData = ComplexData;
  608. complexData->XCoordsCapacity = xCoordsCapacity;
  609. complexData->XCoordsCount = 0;
  610. complexData->YSpansCapacity = ySpans;
  611. complexData->NumYSpans = 0;
  612. complexData->YSearchIndex = 0;
  613. complexData->XCoords = reinterpret_cast<INT *>(complexData + 1);
  614. complexData->YSpans = complexData->XCoords + xCoordsCapacity;
  615. XMin = XMax = YMin = YMax = 0;
  616. return Ok;
  617. }
  618. /**************************************************************************\
  619. *
  620. * Function Description:
  621. *
  622. * Traverse through the region, clipping as you go, doing a fill using
  623. * the specified output object.
  624. *
  625. * Arguments:
  626. *
  627. * [IN] output - the object used to output the region spans
  628. * [IN] clipBounds - the bounds to clip to (if any)
  629. *
  630. * Return Value:
  631. *
  632. * GpStatus - Ok or failure status
  633. *
  634. * Created:
  635. *
  636. * 02/25/1999 DCurtis
  637. *
  638. \**************************************************************************/
  639. GpStatus
  640. DpRegion::Fill(
  641. DpOutputSpan * output,
  642. GpRect * clipBounds
  643. ) const
  644. {
  645. GpStatus status = Ok;
  646. if (!Empty)
  647. {
  648. INT y;
  649. INT xMin;
  650. INT yMin;
  651. INT xMax;
  652. INT yMax;
  653. if (Infinite)
  654. {
  655. ASSERT(clipBounds != NULL);
  656. if (clipBounds != NULL)
  657. {
  658. xMin = clipBounds->X;
  659. xMax = clipBounds->GetRight();
  660. yMax = clipBounds->GetBottom();
  661. for (y = clipBounds->Y; (y < yMax) && (status == Ok); y++)
  662. {
  663. status = output->OutputSpan(y, xMin, xMax);
  664. }
  665. }
  666. }
  667. else if (ComplexData == NULL)
  668. {
  669. xMin = XMin;
  670. yMin = YMin;
  671. xMax = XMax;
  672. yMax = YMax;
  673. if (clipBounds != NULL)
  674. {
  675. if (xMin < clipBounds->X)
  676. {
  677. xMin = clipBounds->X;
  678. }
  679. if (yMin < clipBounds->Y)
  680. {
  681. yMin = clipBounds->Y;
  682. }
  683. if (xMax > clipBounds->GetRight())
  684. {
  685. xMax = clipBounds->GetRight();
  686. }
  687. if (yMax > clipBounds->GetBottom())
  688. {
  689. yMax = clipBounds->GetBottom();
  690. }
  691. }
  692. for (y = yMin; (y < yMax) && (status == Ok); y++)
  693. {
  694. status = output->OutputSpan(y, xMin, xMax);
  695. }
  696. }
  697. else // complex region
  698. {
  699. DpComplexRegion * complexData = ComplexData;
  700. INT * ySpan = complexData->YSpans;
  701. INT * ySpanLast = ySpan +
  702. ((complexData->NumYSpans - 1) * YSPAN_SIZE);
  703. INT * xCoords;
  704. INT * xSpan;
  705. INT numXCoords;
  706. INT numXSpan;
  707. if (clipBounds != NULL)
  708. {
  709. INT ySpanIndex;
  710. complexData->ResetSearchIndex();
  711. if (YMin < clipBounds->Y)
  712. {
  713. complexData->YSpanSearch(clipBounds->Y,
  714. &ySpan, &ySpanIndex);
  715. }
  716. if (YMax > clipBounds->GetBottom())
  717. {
  718. complexData->YSpanSearch(clipBounds->GetBottom(),
  719. &ySpanLast, &ySpanIndex);
  720. }
  721. }
  722. xCoords = complexData->XCoords + ySpan[YSPAN_XOFFSET];
  723. for (;;)
  724. {
  725. yMin = ySpan[YSPAN_YMIN];
  726. yMax = ySpan[YSPAN_YMAX];
  727. numXCoords = ySpan[YSPAN_XCOUNT];
  728. // [agodfrey] We must clip our output range to the clip region.
  729. // Bug #122789 showed that, otherwise, we can take inordinately
  730. // long to execute. In the bug's specific case, the loop below
  731. // executed 67 million iterations before getting to the
  732. // first unclipped scan.
  733. if (clipBounds != NULL)
  734. {
  735. if (yMin < clipBounds->Y)
  736. {
  737. yMin = clipBounds->Y;
  738. }
  739. if (yMax > clipBounds->GetBottom())
  740. {
  741. yMax = clipBounds->GetBottom();
  742. }
  743. }
  744. // The code below assumes that yMax > yMin. We think this should
  745. // be satisfied because the clipBounds and yspan should both
  746. // be non-empty, and yMax >= clipBounds->Y since the code
  747. // above searched for a yspan which intersects the clip bounds.
  748. // NTRAID#NTBUG9-393985-2001/05/16-asecchia
  749. // This ASSERT is overactive and fires when there is no real
  750. // crash problem, however there is a performance issue that
  751. // should be addressed - see RAID bug.
  752. // ASSERT(yMax > yMin);
  753. if (numXCoords == 2)
  754. {
  755. xMin = *xCoords++;
  756. xMax = *xCoords++;
  757. do
  758. {
  759. status = output->OutputSpan(yMin, xMin, xMax);
  760. } while ((++yMin < yMax) && (status == Ok));
  761. }
  762. else
  763. {
  764. do
  765. {
  766. for (xSpan = xCoords, numXSpan = numXCoords;;)
  767. {
  768. numXSpan -= 2;
  769. status = output->OutputSpan(yMin,xSpan[0],xSpan[1]);
  770. if (status != Ok)
  771. {
  772. goto Done;
  773. }
  774. if (numXSpan < 2)
  775. {
  776. break;
  777. }
  778. xSpan += 2;
  779. }
  780. } while (++yMin < yMax);
  781. xCoords += numXCoords;
  782. }
  783. if (ySpan >= ySpanLast)
  784. {
  785. break;
  786. }
  787. ySpan += YSPAN_SIZE;
  788. }
  789. }
  790. }
  791. Done:
  792. return status;
  793. }
  794. /**************************************************************************\
  795. *
  796. * Function Description:
  797. *
  798. * Impelement GpOutputYSpan interface to create the region
  799. * data from the path data, using the rasterizer.
  800. * Exclusive in yMax and in the xMax'es.
  801. *
  802. * Arguments:
  803. *
  804. * [IN] yMin - min y of this span
  805. * [IN] yMax - max y of this span
  806. * [IN] xCoords - array of x coordinates (in pairs of x min, x max)
  807. * [IN] numXCoords - number of x coordinates in xCoords array
  808. *
  809. * Return Value:
  810. *
  811. * GpStatus - Ok or failure status
  812. *
  813. * Created:
  814. *
  815. * 01/06/1999 DCurtis
  816. *
  817. \**************************************************************************/
  818. GpStatus
  819. DpRegionBuilder::OutputYSpan(
  820. INT yMin,
  821. INT yMax,
  822. INT * xCoords, // even number of X coordinates
  823. INT numXCoords // must be a multiple of 2
  824. )
  825. {
  826. ASSERT(IsValid());
  827. DpComplexRegion * complexData = ComplexData;
  828. INT numYSpans = complexData->NumYSpans;
  829. #ifdef USE_YSPAN_BUILDER
  830. if (numYSpans > 0)
  831. {
  832. // Try to add this row to the previous row,
  833. // if the scans are the same and the y's match up
  834. INT * ySpanPrev;
  835. INT * xSpanPrev;
  836. INT numXCoordsPrev;
  837. ySpanPrev = complexData->GetYSpan(numYSpans - 1);
  838. xSpanPrev = complexData->XCoords + ySpanPrev[YSPAN_XOFFSET];
  839. numXCoordsPrev = ySpanPrev[YSPAN_XCOUNT];
  840. if ((numXCoordsPrev == numXCoords) &&
  841. (ySpanPrev[YSPAN_YMAX] >= yMin) &&
  842. (GpMemcmp (xSpanPrev, xCoords, numXCoords * sizeof(INT)) == 0))
  843. {
  844. // Yes, it did match -- just set the new yMax and return
  845. YMax = yMax;
  846. ySpanPrev[YSPAN_YMAX] = yMax;
  847. return Ok;
  848. }
  849. }
  850. // no previous spans or doesn't match previous spans
  851. #endif
  852. INT xCount = complexData->XCoordsCount;
  853. INT * ySpan;
  854. INT * xArray;
  855. if ((complexData->YSpansCapacity > numYSpans) &&
  856. (complexData->XCoordsCapacity >= (xCount + numXCoords)))
  857. {
  858. complexData->NumYSpans++;
  859. complexData->XCoordsCount += numXCoords;
  860. }
  861. else // need more capacity
  862. {
  863. // We want to have YSPAN_INC Y spans available and
  864. // to have YSPAN_INC * 4 X coords available after we
  865. // add this data.
  866. INT newYSpansCapacity = numYSpans + (YSPAN_INC + 1);
  867. INT newXCoordsCapacity = xCount + numXCoords + (YSPAN_INC * 4);
  868. DpComplexRegion * oldData = complexData;
  869. complexData = static_cast<DpComplexRegion *>(
  870. GpMalloc(sizeof(DpComplexRegion) +
  871. (newYSpansCapacity * (YSPAN_SIZE * sizeof(*(oldData->YSpans)))) +
  872. (newXCoordsCapacity * sizeof(*(oldData->XCoords)))));
  873. if (complexData == NULL)
  874. {
  875. return OutOfMemory;
  876. }
  877. ComplexData = complexData;
  878. complexData->XCoordsCapacity = newXCoordsCapacity;
  879. complexData->XCoordsCount = xCount + numXCoords;
  880. complexData->YSpansCapacity = newYSpansCapacity;
  881. complexData->NumYSpans = numYSpans + 1;
  882. complexData->YSearchIndex = 0;
  883. complexData->XCoords = reinterpret_cast<INT *>(complexData + 1);
  884. complexData->YSpans = complexData->XCoords +
  885. newXCoordsCapacity;
  886. GpMemcpy(complexData->XCoords, oldData->XCoords,
  887. xCount * sizeof(*(complexData->XCoords)));
  888. GpMemcpy(complexData->YSpans, oldData->YSpans,
  889. numYSpans * (YSPAN_SIZE * sizeof(*(complexData->YSpans))));
  890. GpFree (oldData);
  891. }
  892. xArray = complexData->XCoords + xCount;
  893. ySpan = complexData->YSpans + (numYSpans * YSPAN_SIZE);
  894. ySpan[YSPAN_YMIN] = yMin; // y Start (Min)
  895. ySpan[YSPAN_YMAX] = yMax; // y End (Max)
  896. ySpan[YSPAN_XOFFSET] = xCount; // XCoords index
  897. ySpan[YSPAN_XCOUNT] = numXCoords; // number of X's
  898. GpMemcpy (xArray, xCoords, numXCoords * sizeof(xArray[0]));
  899. if (numYSpans == 0)
  900. {
  901. YMin = yMin;
  902. XMin = xCoords[0];
  903. XMax = xCoords[numXCoords - 1];
  904. }
  905. else
  906. {
  907. if (XMin > xCoords[0])
  908. {
  909. XMin = xCoords[0];
  910. }
  911. if (XMax < xCoords[numXCoords - 1])
  912. {
  913. XMax = xCoords[numXCoords - 1];
  914. }
  915. }
  916. YMax = yMax;
  917. return Ok;
  918. }
  919. /**************************************************************************\
  920. *
  921. * Function Description:
  922. *
  923. * constructor
  924. * Set to either empty or to infinite, depending on the value of empty.
  925. *
  926. * Arguments:
  927. *
  928. * [IN] empty - if non-zero, initialize to empty else to infinite
  929. *
  930. * Return Value:
  931. *
  932. * NONE
  933. *
  934. * Created:
  935. *
  936. * 01/06/1999 DCurtis
  937. *
  938. \**************************************************************************/
  939. DpRegion::DpRegion(
  940. BOOL empty
  941. )
  942. {
  943. ComplexData = NULL;
  944. Lazy = FALSE;
  945. if (!empty)
  946. {
  947. // set to infinite
  948. Infinite = TRUE;
  949. Empty = FALSE;
  950. XMin = INFINITE_MIN;
  951. YMin = INFINITE_MIN;
  952. XMax = INFINITE_MAX;
  953. YMax = INFINITE_MAX;
  954. }
  955. else
  956. {
  957. // set to empty
  958. Infinite = FALSE;
  959. Empty = TRUE;
  960. XMin = 0;
  961. YMin = 0;
  962. XMax = 0;
  963. YMax = 0;
  964. }
  965. SetValid(TRUE);
  966. UpdateUID();
  967. }
  968. /**************************************************************************\
  969. *
  970. * Function Description:
  971. *
  972. * constructor
  973. * Set to the specified rect.
  974. *
  975. * Arguments:
  976. *
  977. * [IN] rect - rect to use for the region coverage area
  978. *
  979. * Return Value:
  980. *
  981. * NONE
  982. *
  983. * Created:
  984. *
  985. * 01/06/1999 DCurtis
  986. *
  987. \**************************************************************************/
  988. DpRegion::DpRegion(
  989. const GpRect * rect
  990. )
  991. {
  992. ASSERT (rect != NULL);
  993. ComplexData = NULL;
  994. Lazy = FALSE;
  995. SetValid(TRUE);
  996. UpdateUID();
  997. Set(rect->X, rect->Y, rect->Width, rect->Height);
  998. }
  999. /**************************************************************************\
  1000. *
  1001. * Function Description:
  1002. *
  1003. * constructor
  1004. * Set to the specified list of rects, which must be in the same order
  1005. * as our YSpan data.
  1006. *
  1007. * Arguments:
  1008. *
  1009. * [IN] rects - rects to use for the region coverage area
  1010. * [IN] count - number of rects
  1011. *
  1012. * Return Value:
  1013. *
  1014. * NONE
  1015. *
  1016. * Created:
  1017. *
  1018. * 05/04/1999 DCurtis
  1019. *
  1020. \**************************************************************************/
  1021. DpRegion::DpRegion(
  1022. const RECT * rects,
  1023. INT count
  1024. )
  1025. {
  1026. ComplexData = NULL;
  1027. Lazy = FALSE;
  1028. SetValid(TRUE);
  1029. UpdateUID();
  1030. if (Set(rects, count) == Ok)
  1031. {
  1032. return;
  1033. }
  1034. SetValid(FALSE);
  1035. }
  1036. /**************************************************************************\
  1037. *
  1038. * Function Description:
  1039. *
  1040. * Set to the specified list of rects, which must be in the same order
  1041. * as our YSpan data.
  1042. *
  1043. * Arguments:
  1044. *
  1045. * [IN] rects - rects to use for the region coverage area
  1046. * [IN] count - number of rects
  1047. *
  1048. * Return Value:
  1049. *
  1050. * NONE
  1051. *
  1052. * Created:
  1053. *
  1054. * 05/04/1999 DCurtis
  1055. *
  1056. \**************************************************************************/
  1057. GpStatus
  1058. DpRegion::Set(
  1059. const RECT * rects,
  1060. INT count
  1061. )
  1062. {
  1063. if ((rects == NULL) || (count <= 0))
  1064. {
  1065. SetEmpty();
  1066. return Ok;
  1067. }
  1068. if (count == 1)
  1069. {
  1070. OneRect:
  1071. Set(rects->left, rects->top,
  1072. rects->right - rects->left,
  1073. rects->bottom - rects->top);
  1074. return Ok;
  1075. }
  1076. // Verify the first rect(s) to make sure they're not empty
  1077. for (;;)
  1078. {
  1079. // Ignore any empty rects at the beginning of the list
  1080. if ((rects->top < rects->bottom) &&
  1081. (rects->left < rects->right))
  1082. {
  1083. break;
  1084. }
  1085. WARNING1("Empty or Invalid Rect");
  1086. rects++;
  1087. if (--count == 1)
  1088. {
  1089. goto OneRect;
  1090. }
  1091. }
  1092. {
  1093. DpRegionBuilder regionBuilder(count);
  1094. if (regionBuilder.IsValid())
  1095. {
  1096. INT yMin = rects->top;
  1097. INT yMax = rects->bottom;
  1098. BOOL failed = FALSE;
  1099. DynArrayIA<INT,32> xCoords;
  1100. if(xCoords.ReserveSpace(count * 2) != Ok)
  1101. goto ErrorExit;
  1102. xCoords.Add(rects->left);
  1103. xCoords.Add(rects->right);
  1104. for (INT i = 1; i < count; i++)
  1105. {
  1106. // Ignore empty rects
  1107. if ((rects[i].top < rects[i].bottom) &&
  1108. (rects[i].left < rects[i].right))
  1109. {
  1110. if (rects[i].top != yMin)
  1111. {
  1112. if (regionBuilder.OutputYSpan(yMin, yMax,
  1113. xCoords.GetDataBuffer(), xCoords.GetCount()) != Ok)
  1114. {
  1115. goto ErrorExit;
  1116. }
  1117. ASSERT(rects[i].top >= yMax);
  1118. xCoords.SetCount(0);
  1119. yMin = rects[i].top;
  1120. yMax = rects[i].bottom;
  1121. }
  1122. xCoords.Add(rects[i].left);
  1123. xCoords.Add(rects[i].right);
  1124. }
  1125. else
  1126. {
  1127. WARNING1("Empty or Invalid Rect");
  1128. }
  1129. }
  1130. if (xCoords.GetCount() > 0)
  1131. {
  1132. if (regionBuilder.OutputYSpan(yMin, yMax,
  1133. xCoords.GetDataBuffer(), xCoords.GetCount()) != Ok)
  1134. {
  1135. goto ErrorExit;
  1136. }
  1137. }
  1138. return Set(regionBuilder);
  1139. }
  1140. }
  1141. ErrorExit:
  1142. SetEmpty();
  1143. SetValid(FALSE);
  1144. return GenericError;
  1145. }
  1146. /**************************************************************************\
  1147. *
  1148. * Function Description:
  1149. *
  1150. * constructor
  1151. * Make this region be the specified rect.
  1152. *
  1153. * Arguments:
  1154. *
  1155. * [IN] x - starting x coordinate of rect
  1156. * [IN] y - starting y coordinate of rect
  1157. * [IN] width - width of rect
  1158. * [IN] height - height of rect
  1159. *
  1160. * Return Value:
  1161. *
  1162. * NONE
  1163. *
  1164. * Created:
  1165. *
  1166. * 01/06/1999 DCurtis
  1167. *
  1168. \**************************************************************************/
  1169. DpRegion::DpRegion(
  1170. INT x,
  1171. INT y,
  1172. INT width,
  1173. INT height
  1174. )
  1175. {
  1176. ComplexData = NULL;
  1177. Lazy = FALSE;
  1178. SetValid(TRUE);
  1179. UpdateUID();
  1180. Set(x, y, width, height);
  1181. }
  1182. /**************************************************************************\
  1183. *
  1184. * Function Description:
  1185. *
  1186. * Make this region be the specified rect.
  1187. *
  1188. * Arguments:
  1189. *
  1190. * [IN] x - starting x coordinate of rect
  1191. * [IN] y - starting y coordinate of rect
  1192. * [IN] width - width of rect
  1193. * [IN] height - height of rect
  1194. *
  1195. * Return Value:
  1196. *
  1197. * NONE
  1198. *
  1199. * Created:
  1200. *
  1201. * 01/06/1999 DCurtis
  1202. *
  1203. \**************************************************************************/
  1204. VOID
  1205. DpRegion::Set(
  1206. INT x,
  1207. INT y,
  1208. INT width,
  1209. INT height
  1210. )
  1211. {
  1212. ASSERT(IsValid());
  1213. ASSERT((width >= 0) && (height >= 0));
  1214. // crop to infinity
  1215. if (x < INFINITE_MIN)
  1216. {
  1217. if (width < INFINITE_SIZE)
  1218. {
  1219. width -= (INFINITE_MIN - x);
  1220. }
  1221. x = INFINITE_MIN;
  1222. }
  1223. if (y < INFINITE_MIN)
  1224. {
  1225. if (height < INFINITE_SIZE)
  1226. {
  1227. height -= (INFINITE_MIN - y);
  1228. }
  1229. y = INFINITE_MIN;
  1230. }
  1231. if ((width > 0) && (width < INFINITE_SIZE) &&
  1232. (height > 0) && (height < INFINITE_SIZE))
  1233. {
  1234. FreeData();
  1235. SetValid(TRUE);
  1236. Infinite = FALSE;
  1237. Empty = FALSE;
  1238. UpdateUID();
  1239. XMin = x;
  1240. YMin = y;
  1241. XMax = x + width;
  1242. YMax = y + height;
  1243. }
  1244. else if ((width <= 0) || (height <= 0))
  1245. {
  1246. SetEmpty();
  1247. }
  1248. else
  1249. {
  1250. SetInfinite();
  1251. }
  1252. }
  1253. /**************************************************************************\
  1254. *
  1255. * Function Description:
  1256. *
  1257. * Initialize the region to a cleared state with an empty coverage area.
  1258. *
  1259. * Arguments:
  1260. *
  1261. * NONE
  1262. *
  1263. * Return Value:
  1264. *
  1265. * NONE
  1266. *
  1267. * Created:
  1268. *
  1269. * 01/06/1999 DCurtis
  1270. *
  1271. \**************************************************************************/
  1272. VOID
  1273. DpRegion::SetEmpty()
  1274. {
  1275. ASSERT(IsValid());
  1276. FreeData();
  1277. SetValid(TRUE);
  1278. Infinite = FALSE;
  1279. Empty = TRUE;
  1280. UpdateUID();
  1281. XMin = 0;
  1282. YMin = 0;
  1283. XMax = 0;
  1284. YMax = 0;
  1285. }
  1286. /**************************************************************************\
  1287. *
  1288. * Function Description:
  1289. *
  1290. * Initialize the region to contain an infinite coverage area.
  1291. *
  1292. * Arguments:
  1293. *
  1294. * NONE
  1295. *
  1296. * Return Value:
  1297. *
  1298. * NONE
  1299. *
  1300. * Created:
  1301. *
  1302. * 01/06/1999 DCurtis
  1303. *
  1304. \**************************************************************************/
  1305. VOID
  1306. DpRegion::SetInfinite()
  1307. {
  1308. ASSERT(IsValid());
  1309. FreeData();
  1310. SetValid(TRUE);
  1311. Infinite = TRUE;
  1312. Empty = FALSE;
  1313. UpdateUID();
  1314. XMin = INFINITE_MIN;
  1315. YMin = INFINITE_MIN;
  1316. XMax = INFINITE_MAX;
  1317. YMax = INFINITE_MAX;
  1318. }
  1319. /**************************************************************************\
  1320. *
  1321. * Function Description:
  1322. *
  1323. * Constructor.
  1324. * Make this region cover the area specified by the path.
  1325. *
  1326. * Arguments:
  1327. *
  1328. * [IN] path - specifies the coverage area in world units
  1329. * [IN] matrix - matrix to apply to the path
  1330. *
  1331. * Return Value:
  1332. *
  1333. * NONE
  1334. *
  1335. * Created:
  1336. *
  1337. * 01/06/1999 DCurtis
  1338. *
  1339. \**************************************************************************/
  1340. DpRegion::DpRegion(
  1341. const DpPath * path,
  1342. const GpMatrix * matrix
  1343. )
  1344. {
  1345. ComplexData = NULL;
  1346. Lazy = FALSE;
  1347. SetValid(TRUE);
  1348. UpdateUID();
  1349. if (Set(path, matrix) == Ok)
  1350. {
  1351. return;
  1352. }
  1353. SetValid(FALSE);
  1354. }
  1355. /**************************************************************************\
  1356. *
  1357. * Function Description:
  1358. *
  1359. * Make this region cover the area specified by the path.
  1360. *
  1361. * Arguments:
  1362. *
  1363. * [IN] path - specifies the coverage area in world units
  1364. * [IN] matrix - matrix to apply to the path
  1365. *
  1366. * Return Value:
  1367. *
  1368. * GpStatus - Ok or failure status
  1369. *
  1370. * Created:
  1371. *
  1372. * 01/06/1999 DCurtis
  1373. *
  1374. \**************************************************************************/
  1375. GpStatus
  1376. DpRegion::Set(
  1377. const DpPath * path,
  1378. const GpMatrix * matrix
  1379. )
  1380. {
  1381. ASSERT(IsValid());
  1382. ASSERT ((path != NULL) && (matrix != NULL));
  1383. GpRect bounds;
  1384. path->GetBounds(&bounds, matrix);
  1385. DpRegionBuilder regionBuilder(bounds.Height);
  1386. if (regionBuilder.IsValid())
  1387. {
  1388. #ifndef USE_YSPAN_BUILDER
  1389. GpRectBuilder rectBuilder(&regionBuilder);
  1390. if (rectBuilder.IsValid() &&
  1391. (Rasterizer(path, matrix, path->GetFillMode(), &rectBuilder) == Ok))
  1392. {
  1393. return Set(regionBuilder);
  1394. }
  1395. #else
  1396. GpYSpanBuilder ySpanBuilder(&regionBuilder);
  1397. if (ySpanBuilder.IsValid() &&
  1398. (Rasterizer(path, matrix, path->GetFillMode(), &ySpanBuilder) ==Ok))
  1399. {
  1400. return Set(regionBuilder);
  1401. }
  1402. #endif // USE_YSPAN_BUILDER
  1403. }
  1404. return GenericError;
  1405. }
  1406. /**************************************************************************\
  1407. *
  1408. * Function Description:
  1409. *
  1410. * Make this region be a copy of the data in the specified region builder.
  1411. *
  1412. * Arguments:
  1413. *
  1414. * [IN] regionBuilder - contains the simple or complex region data
  1415. *
  1416. * Return Value:
  1417. *
  1418. * GpStatus - Ok or failure status
  1419. *
  1420. * Created:
  1421. *
  1422. * 01/06/1999 DCurtis
  1423. *
  1424. \**************************************************************************/
  1425. GpStatus
  1426. DpRegion::Set(
  1427. DpRegionBuilder & regionBuilder
  1428. )
  1429. {
  1430. ASSERT(IsValid());
  1431. DpComplexRegion * srcComplexData = regionBuilder.ComplexData;
  1432. if (srcComplexData != NULL)
  1433. {
  1434. if ((srcComplexData->NumYSpans == 1) &&
  1435. (srcComplexData->XCoordsCount == 2))
  1436. {
  1437. Set(regionBuilder.XMin, regionBuilder.YMin,
  1438. regionBuilder.XMax - regionBuilder.XMin,
  1439. regionBuilder.YMax - regionBuilder.YMin);
  1440. return Ok;
  1441. }
  1442. if (srcComplexData->NumYSpans >= 1)
  1443. {
  1444. ASSERT(srcComplexData->XCoordsCount >= 2);
  1445. DpComplexRegion * destComplexData = NULL;
  1446. FreeData();
  1447. SetValid(TRUE);
  1448. Infinite = FALSE;
  1449. Empty = FALSE;
  1450. UpdateUID();
  1451. XMin = regionBuilder.XMin;
  1452. YMin = regionBuilder.YMin;
  1453. XMax = regionBuilder.XMax;
  1454. YMax = regionBuilder.YMax;
  1455. if ((srcComplexData->YSpansCapacity - srcComplexData->NumYSpans) >=
  1456. YSPAN_INC)
  1457. {
  1458. destComplexData = static_cast<DpComplexRegion *>(
  1459. GpMalloc(sizeof(DpComplexRegion) +
  1460. (srcComplexData->NumYSpans *
  1461. (YSPAN_SIZE * sizeof(*(srcComplexData->YSpans)))) +
  1462. (srcComplexData->XCoordsCount *
  1463. sizeof(*(srcComplexData->XCoords)))));
  1464. }
  1465. if (destComplexData != NULL)
  1466. {
  1467. destComplexData->XCoordsCapacity = srcComplexData->XCoordsCount;
  1468. destComplexData->XCoordsCount = srcComplexData->XCoordsCount;
  1469. destComplexData->YSpansCapacity = srcComplexData->NumYSpans;
  1470. destComplexData->NumYSpans = srcComplexData->NumYSpans;
  1471. destComplexData->XCoords =
  1472. reinterpret_cast<INT*>(destComplexData + 1);
  1473. destComplexData->YSpans = destComplexData->XCoords +
  1474. destComplexData->XCoordsCapacity;
  1475. GpMemcpy (destComplexData->XCoords,
  1476. srcComplexData->XCoords,
  1477. srcComplexData->XCoordsCount *
  1478. sizeof(*(destComplexData->XCoords)));
  1479. GpMemcpy (destComplexData->YSpans,
  1480. srcComplexData->YSpans,
  1481. srcComplexData->NumYSpans *
  1482. (YSPAN_SIZE * sizeof(*(destComplexData->YSpans))));
  1483. }
  1484. else
  1485. {
  1486. destComplexData = srcComplexData;
  1487. regionBuilder.ComplexData = NULL;
  1488. }
  1489. destComplexData->ResetSearchIndex();
  1490. ComplexData = destComplexData;
  1491. return Ok;
  1492. }
  1493. }
  1494. // else empty
  1495. SetEmpty();
  1496. return Ok;
  1497. }
  1498. /**************************************************************************\
  1499. *
  1500. * Function Description:
  1501. *
  1502. * Constructor - makes a copy of the specified region
  1503. *
  1504. * Arguments:
  1505. *
  1506. * [IN] region - region to copy
  1507. *
  1508. * Return Value:
  1509. *
  1510. * NONE
  1511. *
  1512. * Created:
  1513. *
  1514. * 01/06/1999 DCurtis
  1515. *
  1516. \**************************************************************************/
  1517. DpRegion::DpRegion(
  1518. const DpRegion * region,
  1519. BOOL lazy
  1520. )
  1521. {
  1522. ASSERT((region != NULL) && region->IsValid());
  1523. ComplexData = NULL;
  1524. Lazy = FALSE;
  1525. SetValid(TRUE);
  1526. UpdateUID();
  1527. if (Set(region, lazy) == Ok)
  1528. {
  1529. return;
  1530. }
  1531. SetValid(FALSE);
  1532. }
  1533. /**************************************************************************\
  1534. *
  1535. * Function Description:
  1536. *
  1537. * Copy constructor
  1538. *
  1539. * Arguments:
  1540. *
  1541. * [IN] region - region to copy
  1542. *
  1543. * Return Value:
  1544. *
  1545. * NONE
  1546. *
  1547. * Created:
  1548. *
  1549. * 01/06/1999 DCurtis
  1550. *
  1551. \**************************************************************************/
  1552. DpRegion::DpRegion(
  1553. DpRegion & region
  1554. )
  1555. {
  1556. ASSERT(region.IsValid());
  1557. ComplexData = NULL;
  1558. Lazy = FALSE;
  1559. SetValid(TRUE);
  1560. UpdateUID();
  1561. if (Set(&region) == Ok)
  1562. {
  1563. return;
  1564. }
  1565. SetValid(FALSE);
  1566. }
  1567. /**************************************************************************\
  1568. *
  1569. * Function Description:
  1570. *
  1571. * Makes this region be a copy of another source region.
  1572. *
  1573. * Arguments:
  1574. *
  1575. * [IN] region - region to copy.
  1576. *
  1577. * Return Value:
  1578. *
  1579. * GpStatus - Ok or failure status
  1580. *
  1581. * Created:
  1582. *
  1583. * 01/06/1999 DCurtis
  1584. *
  1585. \**************************************************************************/
  1586. GpStatus
  1587. DpRegion::Set(
  1588. const DpRegion * region,
  1589. BOOL lazy
  1590. )
  1591. {
  1592. ASSERT(IsValid());
  1593. ASSERT((region != NULL) && region->IsValid());
  1594. if (region != NULL)
  1595. {
  1596. GpStatus status = Ok;
  1597. DpComplexRegion * srcComplexData = region->ComplexData;
  1598. if (srcComplexData == NULL)
  1599. {
  1600. Set (region->XMin, region->YMin,
  1601. region->XMax - region->XMin,
  1602. region->YMax - region->YMin);
  1603. return Ok;
  1604. }
  1605. if ((region == this) && !Lazy)
  1606. {
  1607. return Ok;
  1608. }
  1609. FreeData();
  1610. if (!lazy)
  1611. {
  1612. ComplexData = static_cast<DpComplexRegion*>(
  1613. GpMalloc(sizeof(DpComplexRegion) +
  1614. (srcComplexData->NumYSpans *
  1615. (YSPAN_SIZE * sizeof(*(ComplexData->YSpans)))) +
  1616. (srcComplexData->XCoordsCount *
  1617. sizeof(*(ComplexData->XCoords)))));
  1618. if (ComplexData == NULL)
  1619. {
  1620. ASSERT(0);
  1621. SetValid(FALSE);
  1622. return OutOfMemory;
  1623. }
  1624. DpComplexRegion * destComplexData = ComplexData;
  1625. destComplexData->XCoordsCapacity = srcComplexData->XCoordsCount;
  1626. destComplexData->XCoordsCount = srcComplexData->XCoordsCount;
  1627. destComplexData->YSpansCapacity = srcComplexData->NumYSpans;
  1628. destComplexData->NumYSpans = srcComplexData->NumYSpans;
  1629. destComplexData->ResetSearchIndex();
  1630. destComplexData->XCoords= reinterpret_cast<INT*>(destComplexData+1);
  1631. destComplexData->YSpans = destComplexData->XCoords +
  1632. destComplexData->XCoordsCapacity;
  1633. GpMemcpy (destComplexData->XCoords,
  1634. srcComplexData->XCoords,
  1635. srcComplexData->XCoordsCount *
  1636. sizeof(*(destComplexData->XCoords)));
  1637. GpMemcpy (destComplexData->YSpans,
  1638. srcComplexData->YSpans,
  1639. srcComplexData->NumYSpans *
  1640. (YSPAN_SIZE * sizeof(*(destComplexData->YSpans))));
  1641. }
  1642. else
  1643. {
  1644. ComplexData = srcComplexData;
  1645. Lazy = TRUE;
  1646. }
  1647. SetValid(TRUE);
  1648. Empty = FALSE;
  1649. Infinite = FALSE;
  1650. UpdateUID();
  1651. XMin = region->XMin;
  1652. YMin = region->YMin;
  1653. XMax = region->XMax;
  1654. YMax = region->YMax;
  1655. return Ok;
  1656. }
  1657. return InvalidParameter;
  1658. }
  1659. /**************************************************************************\
  1660. *
  1661. * Function Description:
  1662. *
  1663. * assignment operator.
  1664. *
  1665. * Arguments:
  1666. *
  1667. * [IN] region - region to copy
  1668. *
  1669. * Return Value:
  1670. *
  1671. * NONE
  1672. *
  1673. * Created:
  1674. *
  1675. * 01/06/1999 DCurtis
  1676. *
  1677. \**************************************************************************/
  1678. DpRegion &
  1679. DpRegion::operator=(
  1680. DpRegion & region
  1681. )
  1682. {
  1683. ASSERT(IsValid());
  1684. ASSERT(region.IsValid());
  1685. Set (&region); // what do we do if this fails?
  1686. return *this; // Assignment operator returns left side.
  1687. }
  1688. /**************************************************************************\
  1689. *
  1690. * Function Description:
  1691. *
  1692. * Offset (translate) the region by the specified offset values
  1693. *
  1694. * Arguments:
  1695. *
  1696. * [IN] xOffset - x offset (delta) value
  1697. * [IN] yOffset - y offset (delta) value
  1698. *
  1699. * Return Value:
  1700. *
  1701. * NONE
  1702. *
  1703. * Created:
  1704. *
  1705. * 01/06/1999 DCurtis
  1706. *
  1707. \**************************************************************************/
  1708. GpStatus
  1709. DpRegion::Offset(
  1710. INT xOffset,
  1711. INT yOffset
  1712. )
  1713. {
  1714. ASSERT(IsValid());
  1715. if ((xOffset | yOffset) != 0)
  1716. {
  1717. // copy the data, so it's not a lazy copy
  1718. if (Lazy && (Set(this) != Ok))
  1719. {
  1720. return GenericError;
  1721. }
  1722. if (Infinite || Empty)
  1723. {
  1724. return Ok;
  1725. }
  1726. if (xOffset != 0)
  1727. {
  1728. XMin += xOffset;
  1729. XMax += xOffset;
  1730. // !!! Handle this for non-debug case
  1731. ASSERT((XMin >= INFINITE_MIN) && (XMin <= INFINITE_MAX));
  1732. ASSERT((XMax >= INFINITE_MIN) && (XMax <= INFINITE_MAX));
  1733. if (ComplexData != NULL)
  1734. {
  1735. INT * xCoords = ComplexData->XCoords;
  1736. INT count = ComplexData->XCoordsCount;
  1737. while (count >= 2)
  1738. {
  1739. xCoords[0] += xOffset;
  1740. xCoords[1] += xOffset;
  1741. xCoords += 2;
  1742. count -= 2;
  1743. }
  1744. }
  1745. }
  1746. if (yOffset != 0)
  1747. {
  1748. YMin += yOffset;
  1749. YMax += yOffset;
  1750. // !!! Handle this for non-debug case
  1751. ASSERT((YMin >= INFINITE_MIN) && (YMin <= INFINITE_MAX));
  1752. ASSERT((YMax >= INFINITE_MIN) && (YMax <= INFINITE_MAX));
  1753. if (ComplexData != NULL)
  1754. {
  1755. INT * ySpans = ComplexData->YSpans;
  1756. INT count = ComplexData->NumYSpans;
  1757. while (count > 0)
  1758. {
  1759. ySpans[YSPAN_YMIN] += yOffset;
  1760. ySpans[YSPAN_YMAX] += yOffset;
  1761. ySpans += YSPAN_SIZE;
  1762. count--;
  1763. }
  1764. }
  1765. }
  1766. }
  1767. return Ok;
  1768. }
  1769. /**************************************************************************\
  1770. *
  1771. * Function Description:
  1772. *
  1773. * See if another region is identical in coverage to this one.
  1774. * For this to work, infinite regions must all have the same data.
  1775. *
  1776. * Arguments:
  1777. *
  1778. * [IN] region - region to compare with
  1779. *
  1780. * Return Value:
  1781. *
  1782. * TRUE - regions cover the same area
  1783. * FALSE - regions not identical
  1784. *
  1785. * Created:
  1786. *
  1787. * 01/06/1999 DCurtis
  1788. *
  1789. \**************************************************************************/
  1790. BOOL
  1791. DpRegion::IsEqual(
  1792. DpRegion * region
  1793. )
  1794. {
  1795. ASSERT(IsValid());
  1796. ASSERT((region != NULL) && region->IsValid());
  1797. if (!Empty)
  1798. {
  1799. if ((XMin == region->XMin) &&
  1800. (YMin == region->YMin) &&
  1801. (XMax == region->XMax) &&
  1802. (YMax == region->YMax))
  1803. {
  1804. if (ComplexData == NULL)
  1805. {
  1806. return (region->ComplexData == NULL);
  1807. }
  1808. if (region->ComplexData == NULL)
  1809. {
  1810. return FALSE;
  1811. }
  1812. if (ComplexData->NumYSpans == region->ComplexData->NumYSpans)
  1813. {
  1814. // If the ySpans are the same, then the size of the
  1815. // xCoords buffers should also be the same.
  1816. return ((GpMemcmp (ComplexData->YSpans,
  1817. region->ComplexData->YSpans,
  1818. ComplexData->NumYSpans *
  1819. YSPAN_SIZE * sizeof(INT)) == 0) &&
  1820. (GpMemcmp (ComplexData->XCoords,
  1821. region->ComplexData->XCoords,
  1822. ComplexData->XCoordsCount *
  1823. sizeof(INT)) == 0));
  1824. }
  1825. }
  1826. return FALSE;
  1827. }
  1828. return region->Empty;
  1829. }
  1830. /**************************************************************************\
  1831. *
  1832. * Function Description:
  1833. *
  1834. * Add Y Span data to a regionBuilder, compacting the data as we go.
  1835. * Used by the region combine methods.
  1836. *
  1837. * Arguments:
  1838. *
  1839. * [IN] yMin - min y of this span
  1840. * [IN] yMax - max y of this span
  1841. * [IN] xCoords - array of x coordinates (in pairs of x min, x max)
  1842. * [IN] numXCoords - number of x coordinates in xCoords array
  1843. * [IN] regionBuilder - the region builder that stores the data
  1844. * [IN] combineCoords - used to compact the data
  1845. *
  1846. * Return Value:
  1847. *
  1848. * GpStatus - Ok or failure status
  1849. *
  1850. * Created:
  1851. *
  1852. * 01/06/1999 DCurtis
  1853. *
  1854. \**************************************************************************/
  1855. GpStatus
  1856. DpRegion::CompactAndOutput(
  1857. INT yMin,
  1858. INT yMax,
  1859. INT * xCoords,
  1860. INT numXCoords,
  1861. DpRegionBuilder * regionBuilder,
  1862. DynIntArray * combineCoords
  1863. )
  1864. {
  1865. // numEdgeCoords could be 0 when this is called from the combine code
  1866. if (numXCoords > 0)
  1867. {
  1868. if (numXCoords > 2)
  1869. {
  1870. // Try to compact the X Span data.
  1871. // First, make a copy of the data if we need to
  1872. // so we can compact it in place.
  1873. if (combineCoords != NULL)
  1874. {
  1875. combineCoords->Reset(FALSE);
  1876. if (combineCoords->AddMultiple(xCoords, numXCoords) != Ok)
  1877. {
  1878. return OutOfMemory;
  1879. }
  1880. xCoords = combineCoords->GetDataBuffer();
  1881. }
  1882. INT indexDest = 0;
  1883. INT index = 2;
  1884. INT indexLast = numXCoords - 2;
  1885. numXCoords = 2;
  1886. do
  1887. {
  1888. if ((xCoords[indexDest + 1]) >= xCoords[index])
  1889. {
  1890. xCoords[indexDest + 1] = xCoords[index + 1];
  1891. index += 2;
  1892. }
  1893. else
  1894. {
  1895. indexDest += 2;
  1896. if (indexDest != index)
  1897. {
  1898. xCoords[indexDest] = xCoords[index];
  1899. xCoords[indexDest+1] = xCoords[index+1];
  1900. }
  1901. index += 2;
  1902. numXCoords += 2;
  1903. }
  1904. } while (index <= indexLast);
  1905. }
  1906. #ifndef USE_YSPAN_BUILDER
  1907. DpComplexRegion * complexData = regionBuilder->ComplexData;
  1908. if (complexData->NumYSpans > 0)
  1909. {
  1910. // Try to add this row to the previous row,
  1911. // if the scans are the same and the y's match up
  1912. INT * ySpanPrev;
  1913. INT * xSpanPrev;
  1914. INT numXCoordsPrev;
  1915. ySpanPrev = complexData->GetYSpan(complexData->NumYSpans - 1);
  1916. xSpanPrev = complexData->XCoords + ySpanPrev[YSPAN_XOFFSET];
  1917. numXCoordsPrev = ySpanPrev[YSPAN_XCOUNT];
  1918. if ((numXCoordsPrev == numXCoords) &&
  1919. (ySpanPrev[YSPAN_YMAX] >= yMin) &&
  1920. (GpMemcmp (xSpanPrev, xCoords, numXCoords * sizeof(INT)) == 0))
  1921. {
  1922. // Yes, it did match -- just set the new yMax and return
  1923. regionBuilder->YMax = yMax;
  1924. ySpanPrev[YSPAN_YMAX] = yMax;
  1925. return Ok;
  1926. }
  1927. }
  1928. #endif // USE_YSPAN_BUILDER
  1929. return regionBuilder->OutputYSpan(yMin, yMax, xCoords, numXCoords);
  1930. }
  1931. return Ok;
  1932. }
  1933. /**************************************************************************\
  1934. *
  1935. * Function Description:
  1936. *
  1937. * Combine another region with this one using the AND operator.
  1938. *
  1939. * Arguments:
  1940. *
  1941. * [IN] region - the region to combine with this one
  1942. *
  1943. * Return Value:
  1944. *
  1945. * GpStatus - Ok or failure status
  1946. *
  1947. * Created:
  1948. *
  1949. * 01/06/1999 DCurtis
  1950. *
  1951. \**************************************************************************/
  1952. GpStatus
  1953. DpRegion::And(
  1954. const DpRegion * region
  1955. )
  1956. {
  1957. ASSERT(IsValid());
  1958. ASSERT((region != NULL) && region->IsValid());
  1959. if (Empty || (region->Infinite) || (region == this))
  1960. {
  1961. return Ok;
  1962. }
  1963. if (Infinite)
  1964. {
  1965. return Set(region);
  1966. }
  1967. if (region->Empty)
  1968. {
  1969. SetEmpty();
  1970. return Ok;
  1971. }
  1972. // check if the region totally encompasses this
  1973. if ((region->ComplexData == NULL) &&
  1974. (region->XMin <= XMin) &&
  1975. (region->YMin <= YMin) &&
  1976. (region->XMax >= XMax) &&
  1977. (region->YMax >= YMax))
  1978. {
  1979. return Ok;
  1980. }
  1981. // check if this totally encompasses the region
  1982. if ((ComplexData == NULL) &&
  1983. (XMin <= region->XMin) &&
  1984. (YMin <= region->YMin) &&
  1985. (XMax >= region->XMax) &&
  1986. (YMax >= region->YMax))
  1987. {
  1988. return Set(region);
  1989. }
  1990. // check for no intersection
  1991. if ((XMin >= region->XMax) ||
  1992. (region->XMax <= XMin) ||
  1993. (XMax <= region->XMin) ||
  1994. (region->XMin >= XMax) ||
  1995. (YMin >= region->YMax) ||
  1996. (region->YMax <= YMin) ||
  1997. (YMax <= region->YMin) ||
  1998. (region->YMin >= YMax))
  1999. {
  2000. SetEmpty();
  2001. return Ok;
  2002. }
  2003. else
  2004. {
  2005. INT * ySpan1;
  2006. INT * ySpan2;
  2007. INT * ySpan1Last;
  2008. INT * ySpan2Last;
  2009. INT * xCoords1;
  2010. INT * xCoords2;
  2011. INT ySpan1Tmp[YSPAN_SIZE];
  2012. INT ySpan2Tmp[YSPAN_SIZE];
  2013. INT xCoords1Tmp[2];
  2014. INT xCoords2Tmp[2];
  2015. INT yMin1 = YMin;
  2016. INT yMax1;
  2017. INT yMin2 = region->YMin;
  2018. INT yMax2;
  2019. INT numYSpans1;
  2020. INT numYSpans2;
  2021. INT combineTmp[4];
  2022. DynIntArray combineCoords(combineTmp, 4);
  2023. if (ComplexData == NULL)
  2024. {
  2025. numYSpans1 = 1;
  2026. ySpan1 = ySpan1Tmp;
  2027. ySpan1Last = ySpan1Tmp;
  2028. yMax1 = YMax;
  2029. ySpan1[YSPAN_YMIN] = yMin1;
  2030. ySpan1[YSPAN_YMAX] = yMax1;
  2031. ySpan1[YSPAN_XOFFSET] = 0;
  2032. ySpan1[YSPAN_XCOUNT] = 2;
  2033. xCoords1 = xCoords1Tmp;
  2034. xCoords1[0] = XMin;
  2035. xCoords1[1] = XMax;
  2036. }
  2037. else
  2038. {
  2039. numYSpans1 = ComplexData->NumYSpans;
  2040. ySpan1 = ComplexData->YSpans;
  2041. ySpan1Last = ySpan1 + ((numYSpans1 - 1) * YSPAN_SIZE);
  2042. yMax1 = ySpan1[YSPAN_YMAX];
  2043. xCoords1 = ComplexData->XCoords;
  2044. }
  2045. if (region->ComplexData == NULL)
  2046. {
  2047. numYSpans2 = 1;
  2048. ySpan2 = ySpan2Tmp;
  2049. ySpan2Last = ySpan2Tmp;
  2050. yMax2 = region->YMax;
  2051. ySpan2[YSPAN_YMIN] = yMin2;
  2052. ySpan2[YSPAN_YMAX] = yMax2;
  2053. ySpan2[YSPAN_XOFFSET] = 0;
  2054. ySpan2[YSPAN_XCOUNT] = 2;
  2055. xCoords2 = xCoords2Tmp;
  2056. xCoords2[0] = region->XMin;
  2057. xCoords2[1] = region->XMax;
  2058. }
  2059. else
  2060. {
  2061. numYSpans2 = region->ComplexData->NumYSpans;
  2062. ySpan2 = region->ComplexData->YSpans;
  2063. ySpan2Last = ySpan2 + ((numYSpans2 - 1) * YSPAN_SIZE);
  2064. yMax2 = ySpan2[YSPAN_YMAX];
  2065. xCoords2 = region->ComplexData->XCoords;
  2066. }
  2067. DpRegionBuilder regionBuilder(numYSpans1 + numYSpans2);
  2068. if (!regionBuilder.IsValid())
  2069. {
  2070. return OutOfMemory;
  2071. }
  2072. for (;;)
  2073. {
  2074. if (yMin1 <= yMin2)
  2075. {
  2076. if (yMax1 > yMin2)
  2077. {
  2078. if (XSpansAND(
  2079. &combineCoords,
  2080. xCoords1 + ySpan1[YSPAN_XOFFSET],
  2081. ySpan1[YSPAN_XCOUNT],
  2082. xCoords2 + ySpan2[YSPAN_XOFFSET],
  2083. ySpan2[YSPAN_XCOUNT]) == Ok)
  2084. {
  2085. if (yMax1 <= yMax2)
  2086. {
  2087. if (CompactAndOutput(
  2088. yMin2,
  2089. yMax1,
  2090. combineCoords.GetDataBuffer(),
  2091. combineCoords.GetCount(),
  2092. &regionBuilder, NULL) == Ok)
  2093. {
  2094. goto AndIncYSpan1;
  2095. }
  2096. }
  2097. else
  2098. {
  2099. if (CompactAndOutput(
  2100. yMin2,
  2101. yMax2,
  2102. combineCoords.GetDataBuffer(),
  2103. combineCoords.GetCount(),
  2104. &regionBuilder, NULL) == Ok)
  2105. {
  2106. goto AndIncYSpan2;
  2107. }
  2108. }
  2109. }
  2110. return GenericError;
  2111. }
  2112. goto AndIncYSpan1;
  2113. }
  2114. if (yMax2 > yMin1)
  2115. {
  2116. if (XSpansAND(
  2117. &combineCoords,
  2118. xCoords1 + ySpan1[YSPAN_XOFFSET],
  2119. ySpan1[YSPAN_XCOUNT],
  2120. xCoords2 + ySpan2[YSPAN_XOFFSET],
  2121. ySpan2[YSPAN_XCOUNT]) == Ok)
  2122. {
  2123. if (yMax2 <= yMax1)
  2124. {
  2125. if (CompactAndOutput(
  2126. yMin1,
  2127. yMax2,
  2128. combineCoords.GetDataBuffer(),
  2129. combineCoords.GetCount(),
  2130. &regionBuilder, NULL) == Ok)
  2131. {
  2132. goto AndIncYSpan2;
  2133. }
  2134. }
  2135. else
  2136. {
  2137. if (CompactAndOutput(
  2138. yMin1,
  2139. yMax1,
  2140. combineCoords.GetDataBuffer(),
  2141. combineCoords.GetCount(),
  2142. &regionBuilder, NULL) == Ok)
  2143. {
  2144. goto AndIncYSpan1;
  2145. }
  2146. }
  2147. }
  2148. return GenericError;
  2149. }
  2150. // else goto AndIncYSpan2
  2151. AndIncYSpan2:
  2152. if ((ySpan2 += YSPAN_SIZE) > ySpan2Last)
  2153. {
  2154. break;
  2155. }
  2156. yMin2 = ySpan2[YSPAN_YMIN];
  2157. yMax2 = ySpan2[YSPAN_YMAX];
  2158. continue;
  2159. AndIncYSpan1:
  2160. if ((ySpan1 += YSPAN_SIZE) > ySpan1Last)
  2161. {
  2162. break;
  2163. }
  2164. yMin1 = ySpan1[YSPAN_YMIN];
  2165. yMax1 = ySpan1[YSPAN_YMAX];
  2166. }
  2167. return Set(regionBuilder);
  2168. }
  2169. }
  2170. /**************************************************************************\
  2171. *
  2172. * Function Description:
  2173. *
  2174. * Combine a set of X spans from each region with the AND operator.
  2175. *
  2176. * Arguments:
  2177. *
  2178. * [IN] combineCoords - where to put the combined coordinates
  2179. * [IN] xSpan1 - x spans from this region
  2180. * [IN] numXCoords1 - number of xSpan1 coordinates
  2181. * [IN] xSpan2 - x spans from the other region
  2182. * [IN] numXCoords2 - number of xSpan2 coordinates
  2183. *
  2184. * Return Value:
  2185. *
  2186. * GpStatus - Ok or failure status
  2187. *
  2188. * Created:
  2189. *
  2190. * 01/06/1999 DCurtis
  2191. *
  2192. \**************************************************************************/
  2193. GpStatus
  2194. DpRegion::XSpansAND(
  2195. DynIntArray * combineCoords,
  2196. INT * xSpan1,
  2197. INT numXCoords1,
  2198. INT * xSpan2,
  2199. INT numXCoords2)
  2200. {
  2201. INT * XCoords;
  2202. INT count = 0;
  2203. combineCoords->Reset(FALSE);
  2204. XCoords = combineCoords->AddMultiple(numXCoords1 + numXCoords2);
  2205. if (XCoords != NULL)
  2206. {
  2207. INT xMin1 = xSpan1[0];
  2208. INT xMax1 = xSpan1[1];
  2209. INT xMin2 = xSpan2[0];
  2210. INT xMax2 = xSpan2[1];
  2211. for (;;)
  2212. {
  2213. if (xMin1 <= xMin2)
  2214. {
  2215. if (xMax1 > xMin2)
  2216. {
  2217. XCoords[count++] = xMin2; // left
  2218. if (xMax1 <= xMax2)
  2219. {
  2220. XCoords[count++] = xMax1; // right
  2221. goto AndIncXSpan1;
  2222. }
  2223. XCoords[count++] = xMax2; // right
  2224. goto AndIncXSpan2;
  2225. }
  2226. goto AndIncXSpan1;
  2227. }
  2228. if (xMax2 > xMin1)
  2229. {
  2230. XCoords[count++] = xMin1; // left
  2231. if (xMax2 <= xMax1)
  2232. {
  2233. XCoords[count++] = xMax2; // right
  2234. goto AndIncXSpan2;
  2235. }
  2236. XCoords[count++] = xMax1; // right
  2237. goto AndIncXSpan1;
  2238. }
  2239. // else goto AndIncXSpan2;
  2240. AndIncXSpan2:
  2241. if ((numXCoords2 -= 2) < 2)
  2242. {
  2243. break;
  2244. }
  2245. xSpan2 += 2;
  2246. xMin2 = xSpan2[0];
  2247. xMax2 = xSpan2[1];
  2248. continue;
  2249. AndIncXSpan1:
  2250. if ((numXCoords1 -= 2) < 2)
  2251. {
  2252. break;
  2253. }
  2254. xSpan1 += 2;
  2255. xMin1 = xSpan1[0];
  2256. xMax1 = xSpan1[1];
  2257. }
  2258. combineCoords->SetCount(count);
  2259. return Ok;
  2260. }
  2261. return OutOfMemory;
  2262. }
  2263. /**************************************************************************\
  2264. *
  2265. * Function Description:
  2266. *
  2267. * Combine another region with this one using the OR operator.
  2268. *
  2269. * Arguments:
  2270. *
  2271. * [IN] region - the region to combine with this one
  2272. *
  2273. * Return Value:
  2274. *
  2275. * GpStatus - Ok or failure status
  2276. *
  2277. * Created:
  2278. *
  2279. * 01/06/1999 DCurtis
  2280. *
  2281. \**************************************************************************/
  2282. GpStatus
  2283. DpRegion::Or(
  2284. const DpRegion * region
  2285. )
  2286. {
  2287. ASSERT(IsValid());
  2288. ASSERT((region != NULL) && region->IsValid());
  2289. if (Infinite || region->Empty || (region == this))
  2290. {
  2291. return Ok;
  2292. }
  2293. if (region->Infinite)
  2294. {
  2295. SetInfinite();
  2296. return Ok;
  2297. }
  2298. if (Empty)
  2299. {
  2300. return Set(region);
  2301. }
  2302. // check if the region totally encompasses this
  2303. if ((region->ComplexData == NULL) &&
  2304. (region->XMin <= XMin) &&
  2305. (region->YMin <= YMin) &&
  2306. (region->XMax >= XMax) &&
  2307. (region->YMax >= YMax))
  2308. {
  2309. Set(region->XMin, region->YMin,
  2310. region->XMax - region->XMin,
  2311. region->YMax - region->YMin);
  2312. return Ok;
  2313. }
  2314. // check if this totally encompasses the region
  2315. if ((ComplexData == NULL) &&
  2316. (XMin <= region->XMin) &&
  2317. (YMin <= region->YMin) &&
  2318. (XMax >= region->XMax) &&
  2319. (YMax >= region->YMax))
  2320. {
  2321. return Ok;
  2322. }
  2323. else
  2324. {
  2325. INT * ySpan1;
  2326. INT * ySpan2;
  2327. INT * ySpan1Last;
  2328. INT * ySpan2Last;
  2329. INT * xCoords1;
  2330. INT * xCoords2;
  2331. INT ySpan1Tmp[YSPAN_SIZE];
  2332. INT ySpan2Tmp[YSPAN_SIZE];
  2333. INT xCoords1Tmp[2];
  2334. INT xCoords2Tmp[2];
  2335. INT yMin1 = YMin;
  2336. INT yMax1;
  2337. INT yMin2 = region->YMin;
  2338. INT yMax2;
  2339. INT numYSpans1;
  2340. INT numYSpans2;
  2341. INT combineTmp[4];
  2342. DynIntArray combineCoords(combineTmp, 4);
  2343. if (ComplexData == NULL)
  2344. {
  2345. numYSpans1 = 1;
  2346. ySpan1 = ySpan1Tmp;
  2347. ySpan1Last = ySpan1Tmp;
  2348. yMax1 = YMax;
  2349. ySpan1[YSPAN_YMIN] = yMin1;
  2350. ySpan1[YSPAN_YMAX] = yMax1;
  2351. ySpan1[YSPAN_XOFFSET] = 0;
  2352. ySpan1[YSPAN_XCOUNT] = 2;
  2353. xCoords1 = xCoords1Tmp;
  2354. xCoords1[0] = XMin;
  2355. xCoords1[1] = XMax;
  2356. }
  2357. else
  2358. {
  2359. numYSpans1 = ComplexData->NumYSpans;
  2360. ySpan1 = ComplexData->YSpans;
  2361. ySpan1Last = ySpan1 + ((numYSpans1 - 1) * YSPAN_SIZE);
  2362. yMax1 = ySpan1[YSPAN_YMAX];
  2363. xCoords1 = ComplexData->XCoords;
  2364. }
  2365. if (region->ComplexData == NULL)
  2366. {
  2367. numYSpans2 = 1;
  2368. ySpan2 = ySpan2Tmp;
  2369. ySpan2Last = ySpan2Tmp;
  2370. yMax2 = region->YMax;
  2371. ySpan2[YSPAN_YMIN] = yMin2;
  2372. ySpan2[YSPAN_YMAX] = yMax2;
  2373. ySpan2[YSPAN_XOFFSET] = 0;
  2374. ySpan2[YSPAN_XCOUNT] = 2;
  2375. xCoords2 = xCoords2Tmp;
  2376. xCoords2[0] = region->XMin;
  2377. xCoords2[1] = region->XMax;
  2378. }
  2379. else
  2380. {
  2381. numYSpans2 = region->ComplexData->NumYSpans;
  2382. ySpan2 = region->ComplexData->YSpans;
  2383. ySpan2Last = ySpan2 + ((numYSpans2 - 1) * YSPAN_SIZE);
  2384. yMax2 = ySpan2[YSPAN_YMAX];
  2385. xCoords2 = region->ComplexData->XCoords;
  2386. }
  2387. DpRegionBuilder regionBuilder(numYSpans1 + numYSpans2);
  2388. BOOL done = FALSE;
  2389. INT numXCoords;
  2390. INT * xSpan;
  2391. if (!regionBuilder.IsValid())
  2392. {
  2393. return OutOfMemory;
  2394. }
  2395. for (;;)
  2396. {
  2397. if (yMin1 < yMin2)
  2398. {
  2399. xSpan = xCoords1 + ySpan1[YSPAN_XOFFSET];
  2400. numXCoords = ySpan1[YSPAN_XCOUNT];
  2401. if (yMax1 <= yMin2)
  2402. {
  2403. if (CompactAndOutput(
  2404. yMin1,
  2405. yMax1,
  2406. xSpan,
  2407. numXCoords,
  2408. &regionBuilder,
  2409. &combineCoords) == Ok)
  2410. {
  2411. goto OrIncYSpan1;
  2412. }
  2413. }
  2414. else
  2415. {
  2416. if (CompactAndOutput(
  2417. yMin1,
  2418. yMin2,
  2419. xSpan,
  2420. numXCoords,
  2421. &regionBuilder,
  2422. &combineCoords) == Ok)
  2423. {
  2424. yMin1 = yMin2;
  2425. continue; // no increment
  2426. }
  2427. }
  2428. return GenericError;
  2429. }
  2430. else if (yMin1 > yMin2)
  2431. {
  2432. xSpan = xCoords2 + ySpan2[YSPAN_XOFFSET];
  2433. numXCoords = ySpan2[YSPAN_XCOUNT];
  2434. if (yMax2 <= yMin1)
  2435. {
  2436. if (CompactAndOutput(
  2437. yMin2,
  2438. yMax2,
  2439. xSpan,
  2440. numXCoords,
  2441. &regionBuilder,
  2442. &combineCoords) == Ok)
  2443. {
  2444. goto OrIncYSpan2;
  2445. }
  2446. }
  2447. else
  2448. {
  2449. if (CompactAndOutput(
  2450. yMin2,
  2451. yMin1,
  2452. xSpan,
  2453. numXCoords,
  2454. &regionBuilder,
  2455. &combineCoords) == Ok)
  2456. {
  2457. yMin2 = yMin1;
  2458. continue; // no increment
  2459. }
  2460. }
  2461. return GenericError;
  2462. }
  2463. // else if (yMin1 == yMin2)
  2464. if (XSpansOR (
  2465. &combineCoords,
  2466. xCoords1 + ySpan1[YSPAN_XOFFSET],
  2467. ySpan1[YSPAN_XCOUNT],
  2468. xCoords2 + ySpan2[YSPAN_XOFFSET],
  2469. ySpan2[YSPAN_XCOUNT]) == Ok)
  2470. {
  2471. if (yMax1 < yMax2)
  2472. {
  2473. if (CompactAndOutput(
  2474. yMin1,
  2475. yMax1,
  2476. combineCoords.GetDataBuffer(),
  2477. combineCoords.GetCount(),
  2478. &regionBuilder, NULL) == Ok)
  2479. {
  2480. yMin2 = yMax1;
  2481. goto OrIncYSpan1;
  2482. }
  2483. }
  2484. else if (yMax1 > yMax2)
  2485. {
  2486. if (CompactAndOutput(
  2487. yMin1,
  2488. yMax2,
  2489. combineCoords.GetDataBuffer(),
  2490. combineCoords.GetCount(),
  2491. &regionBuilder, NULL) == Ok)
  2492. {
  2493. yMin1 = yMax2;
  2494. goto OrIncYSpan2;
  2495. }
  2496. }
  2497. else // if (yMax1 == yMax2)
  2498. {
  2499. if (CompactAndOutput(
  2500. yMin1,
  2501. yMax1,
  2502. combineCoords.GetDataBuffer(),
  2503. combineCoords.GetCount(),
  2504. &regionBuilder, NULL) == Ok)
  2505. {
  2506. goto OrIncYSpanBoth;
  2507. }
  2508. }
  2509. }
  2510. return GenericError;
  2511. OrIncYSpanBoth:
  2512. if ((ySpan2 += YSPAN_SIZE) > ySpan2Last)
  2513. {
  2514. done = TRUE;
  2515. }
  2516. else
  2517. {
  2518. yMin2 = ySpan2[YSPAN_YMIN];
  2519. yMax2 = ySpan2[YSPAN_YMAX];
  2520. }
  2521. if ((ySpan1 += YSPAN_SIZE) > ySpan1Last)
  2522. {
  2523. goto OrCheckMoreY2Spans;
  2524. }
  2525. else
  2526. {
  2527. yMin1 = ySpan1[YSPAN_YMIN];
  2528. yMax1 = ySpan1[YSPAN_YMAX];
  2529. }
  2530. if (done)
  2531. {
  2532. break;
  2533. }
  2534. continue;
  2535. OrIncYSpan2:
  2536. if ((ySpan2 += YSPAN_SIZE) > ySpan2Last)
  2537. {
  2538. break;
  2539. }
  2540. yMin2 = ySpan2[YSPAN_YMIN];
  2541. yMax2 = ySpan2[YSPAN_YMAX];
  2542. continue;
  2543. OrIncYSpan1:
  2544. if ((ySpan1 += YSPAN_SIZE) > ySpan1Last)
  2545. {
  2546. goto OrCheckMoreY2Spans;
  2547. }
  2548. yMin1 = ySpan1[YSPAN_YMIN];
  2549. yMax1 = ySpan1[YSPAN_YMAX];
  2550. }
  2551. if (ySpan1 <= ySpan1Last)
  2552. {
  2553. for (;;)
  2554. {
  2555. xSpan = xCoords1 + ySpan1[YSPAN_XOFFSET];
  2556. numXCoords = ySpan1[YSPAN_XCOUNT];
  2557. if (CompactAndOutput(
  2558. yMin1,
  2559. yMax1,
  2560. xSpan,
  2561. numXCoords,
  2562. &regionBuilder,
  2563. &combineCoords) != Ok)
  2564. {
  2565. return GenericError;
  2566. }
  2567. ySpan1 += YSPAN_SIZE;
  2568. if (ySpan1 > ySpan1Last)
  2569. {
  2570. break;
  2571. }
  2572. yMin1 = ySpan1[YSPAN_YMIN];
  2573. yMax1 = ySpan1[YSPAN_YMAX];
  2574. }
  2575. }
  2576. OrCheckMoreY2Spans:
  2577. if (ySpan2 <= ySpan2Last)
  2578. {
  2579. for (;;)
  2580. {
  2581. xSpan = xCoords2 + ySpan2[YSPAN_XOFFSET];
  2582. numXCoords = ySpan2[YSPAN_XCOUNT];
  2583. if (CompactAndOutput(
  2584. yMin2,
  2585. yMax2,
  2586. xSpan,
  2587. numXCoords,
  2588. &regionBuilder,
  2589. &combineCoords) != Ok)
  2590. {
  2591. return GenericError;
  2592. }
  2593. ySpan2 += YSPAN_SIZE;
  2594. if (ySpan2 > ySpan2Last)
  2595. {
  2596. break;
  2597. }
  2598. yMin2 = ySpan2[YSPAN_YMIN];
  2599. yMax2 = ySpan2[YSPAN_YMAX];
  2600. }
  2601. }
  2602. return Set(regionBuilder);
  2603. }
  2604. }
  2605. /**************************************************************************\
  2606. *
  2607. * Function Description:
  2608. *
  2609. * Combine a set of X spans from each region with the OR operator.
  2610. *
  2611. * Arguments:
  2612. *
  2613. * [IN] combineCoords - where to put the combined coordinates
  2614. * [IN] xSpan1 - x spans from this region
  2615. * [IN] numXCoords1 - number of xSpan1 coordinates
  2616. * [IN] xSpan2 - x spans from the other region
  2617. * [IN] numXCoords2 - number of xSpan2 coordinates
  2618. *
  2619. * Return Value:
  2620. *
  2621. * GpStatus - Ok or failure status
  2622. *
  2623. * Created:
  2624. *
  2625. * 01/06/1999 DCurtis
  2626. *
  2627. \**************************************************************************/
  2628. GpStatus
  2629. DpRegion::XSpansOR (
  2630. DynIntArray * combineCoords,
  2631. INT * xSpan1,
  2632. INT numXCoords1,
  2633. INT * xSpan2,
  2634. INT numXCoords2)
  2635. {
  2636. INT * XCoords;
  2637. INT count = 0;
  2638. combineCoords->Reset(FALSE);
  2639. XCoords = combineCoords->AddMultiple(numXCoords1 + numXCoords2);
  2640. if (XCoords != NULL)
  2641. {
  2642. INT xMin1 = xSpan1[0];
  2643. INT xMax1 = xSpan1[1];
  2644. INT xMin2 = xSpan2[0];
  2645. INT xMax2 = xSpan2[1];
  2646. BOOL done = FALSE;
  2647. for (;;)
  2648. {
  2649. if (xMin1 <= xMin2)
  2650. {
  2651. XCoords[count++] = xMin1;
  2652. if (xMax1 <= xMin2)
  2653. {
  2654. XCoords[count++] = xMax1;
  2655. goto OrIncXSpan1;
  2656. }
  2657. XCoords[count++] = (xMax1 <= xMax2) ? xMax2 : xMax1;
  2658. goto OrIncXSpanBoth;
  2659. }
  2660. XCoords[count++] = xMin2;
  2661. if (xMax2 <= xMin1)
  2662. {
  2663. XCoords[count++] = xMax2;
  2664. goto OrIncXSpan2;
  2665. }
  2666. XCoords[count++] = (xMax2 <= xMax1) ? xMax1 : xMax2;
  2667. // goto OrIncXSpanBoth;
  2668. OrIncXSpanBoth:
  2669. xSpan2 += 2;
  2670. if ((numXCoords2 -= 2) < 2)
  2671. {
  2672. done = TRUE;
  2673. }
  2674. else
  2675. {
  2676. xMin2 = xSpan2[0];
  2677. xMax2 = xSpan2[1];
  2678. }
  2679. xSpan1 += 2;
  2680. if ((numXCoords1 -= 2) < 2)
  2681. {
  2682. goto OrCheckMoreX2Spans;
  2683. }
  2684. else
  2685. {
  2686. xMin1 = xSpan1[0];
  2687. xMax1 = xSpan1[1];
  2688. }
  2689. if (done)
  2690. {
  2691. break;
  2692. }
  2693. continue;
  2694. OrIncXSpan2:
  2695. xSpan2 += 2;
  2696. if ((numXCoords2 -= 2) < 2)
  2697. {
  2698. break;
  2699. }
  2700. xMin2 = xSpan2[0];
  2701. xMax2 = xSpan2[1];
  2702. continue;
  2703. OrIncXSpan1:
  2704. xSpan1 += 2;
  2705. if ((numXCoords1 -= 2) < 2)
  2706. {
  2707. goto OrCheckMoreX2Spans;
  2708. }
  2709. xMin1 = xSpan1[0];
  2710. xMax1 = xSpan1[1];
  2711. }
  2712. while (numXCoords1 >= 2)
  2713. {
  2714. XCoords[count++] = xSpan1[0];
  2715. XCoords[count++] = xSpan1[1];
  2716. numXCoords1 -= 2;
  2717. xSpan1 += 2;
  2718. }
  2719. OrCheckMoreX2Spans:
  2720. while (numXCoords2 >= 2)
  2721. {
  2722. XCoords[count++] = xSpan2[0];
  2723. XCoords[count++] = xSpan2[1];
  2724. numXCoords2 -= 2;
  2725. xSpan2 += 2;
  2726. }
  2727. combineCoords->SetCount(count);
  2728. return Ok;
  2729. }
  2730. return GenericError;
  2731. }
  2732. /**************************************************************************\
  2733. *
  2734. * Function Description:
  2735. *
  2736. * Combine another region with this one using the XOR operator.
  2737. *
  2738. * Arguments:
  2739. *
  2740. * [IN] region - the region to combine with this one
  2741. *
  2742. * Return Value:
  2743. *
  2744. * GpStatus - Ok or failure status
  2745. *
  2746. * Created:
  2747. *
  2748. * 01/06/1999 DCurtis
  2749. *
  2750. \**************************************************************************/
  2751. GpStatus
  2752. DpRegion::Xor(
  2753. const DpRegion * region
  2754. )
  2755. {
  2756. ASSERT(IsValid());
  2757. ASSERT((region != NULL) && region->IsValid());
  2758. if (region == this)
  2759. {
  2760. SetEmpty();
  2761. return Ok;
  2762. }
  2763. if (region->Empty)
  2764. {
  2765. return Ok;
  2766. }
  2767. if (Empty)
  2768. {
  2769. return Set(region);
  2770. }
  2771. if (Infinite)
  2772. {
  2773. if (region->Infinite)
  2774. {
  2775. SetEmpty();
  2776. return Ok;
  2777. }
  2778. return Exclude(region);
  2779. }
  2780. if (region->Infinite)
  2781. {
  2782. return Complement(region);
  2783. }
  2784. else
  2785. {
  2786. INT * ySpan1;
  2787. INT * ySpan2;
  2788. INT * ySpan1Last;
  2789. INT * ySpan2Last;
  2790. INT * xCoords1;
  2791. INT * xCoords2;
  2792. INT ySpan1Tmp[YSPAN_SIZE];
  2793. INT ySpan2Tmp[YSPAN_SIZE];
  2794. INT xCoords1Tmp[2];
  2795. INT xCoords2Tmp[2];
  2796. INT yMin1 = YMin;
  2797. INT yMax1;
  2798. INT yMin2 = region->YMin;
  2799. INT yMax2;
  2800. INT numYSpans1;
  2801. INT numYSpans2;
  2802. INT combineTmp[4];
  2803. DynIntArray combineCoords(combineTmp, 4);
  2804. if (ComplexData == NULL)
  2805. {
  2806. numYSpans1 = 1;
  2807. ySpan1 = ySpan1Tmp;
  2808. ySpan1Last = ySpan1Tmp;
  2809. yMax1 = YMax;
  2810. ySpan1[YSPAN_YMIN] = yMin1;
  2811. ySpan1[YSPAN_YMAX] = yMax1;
  2812. ySpan1[YSPAN_XOFFSET] = 0;
  2813. ySpan1[YSPAN_XCOUNT] = 2;
  2814. xCoords1 = xCoords1Tmp;
  2815. xCoords1[0] = XMin;
  2816. xCoords1[1] = XMax;
  2817. }
  2818. else
  2819. {
  2820. numYSpans1 = ComplexData->NumYSpans;
  2821. ySpan1 = ComplexData->YSpans;
  2822. ySpan1Last = ySpan1 + ((numYSpans1 - 1) * YSPAN_SIZE);
  2823. yMax1 = ySpan1[YSPAN_YMAX];
  2824. xCoords1 = ComplexData->XCoords;
  2825. }
  2826. if (region->ComplexData == NULL)
  2827. {
  2828. numYSpans2 = 1;
  2829. ySpan2 = ySpan2Tmp;
  2830. ySpan2Last = ySpan2Tmp;
  2831. yMax2 = region->YMax;
  2832. ySpan2[YSPAN_YMIN] = yMin2;
  2833. ySpan2[YSPAN_YMAX] = yMax2;
  2834. ySpan2[YSPAN_XOFFSET] = 0;
  2835. ySpan2[YSPAN_XCOUNT] = 2;
  2836. xCoords2 = xCoords2Tmp;
  2837. xCoords2[0] = region->XMin;
  2838. xCoords2[1] = region->XMax;
  2839. }
  2840. else
  2841. {
  2842. numYSpans2 = region->ComplexData->NumYSpans;
  2843. ySpan2 = region->ComplexData->YSpans;
  2844. ySpan2Last = ySpan2 + ((numYSpans2 - 1) * YSPAN_SIZE);
  2845. yMax2 = ySpan2[YSPAN_YMAX];
  2846. xCoords2 = region->ComplexData->XCoords;
  2847. }
  2848. DpRegionBuilder regionBuilder(2 * (numYSpans1 + numYSpans2));
  2849. BOOL done = FALSE;
  2850. INT numXCoords;
  2851. INT * xSpan;
  2852. if (!regionBuilder.IsValid())
  2853. {
  2854. return OutOfMemory;
  2855. }
  2856. for (;;)
  2857. {
  2858. if (yMin1 < yMin2)
  2859. {
  2860. xSpan = xCoords1 + ySpan1[YSPAN_XOFFSET];
  2861. numXCoords = ySpan1[YSPAN_XCOUNT];
  2862. if (yMax1 <= yMin2)
  2863. {
  2864. if (CompactAndOutput(
  2865. yMin1,
  2866. yMax1,
  2867. xSpan,
  2868. numXCoords,
  2869. &regionBuilder,
  2870. &combineCoords) == Ok)
  2871. {
  2872. goto XorIncYSpan1;
  2873. }
  2874. }
  2875. else
  2876. {
  2877. if (CompactAndOutput(
  2878. yMin1,
  2879. yMin2,
  2880. xSpan,
  2881. numXCoords,
  2882. &regionBuilder,
  2883. &combineCoords) == Ok)
  2884. {
  2885. yMin1 = yMin2;
  2886. continue; // no increment
  2887. }
  2888. }
  2889. return GenericError;
  2890. }
  2891. else if (yMin1 > yMin2)
  2892. {
  2893. xSpan = xCoords2 + ySpan2[YSPAN_XOFFSET];
  2894. numXCoords = ySpan2[YSPAN_XCOUNT];
  2895. if (yMax2 <= yMin1)
  2896. {
  2897. if (CompactAndOutput(
  2898. yMin2,
  2899. yMax2,
  2900. xSpan,
  2901. numXCoords,
  2902. &regionBuilder,
  2903. &combineCoords) == Ok)
  2904. {
  2905. goto XorIncYSpan2;
  2906. }
  2907. }
  2908. else
  2909. {
  2910. if (CompactAndOutput(
  2911. yMin2,
  2912. yMin1,
  2913. xSpan,
  2914. numXCoords,
  2915. &regionBuilder,
  2916. &combineCoords) == Ok)
  2917. {
  2918. yMin2 = yMin1;
  2919. continue; // no increment
  2920. }
  2921. }
  2922. return GenericError;
  2923. }
  2924. // else if (yMin1 == yMin2)
  2925. if (XSpansXOR (
  2926. &combineCoords,
  2927. xCoords1 + ySpan1[YSPAN_XOFFSET],
  2928. ySpan1[YSPAN_XCOUNT],
  2929. xCoords2 + ySpan2[YSPAN_XOFFSET],
  2930. ySpan2[YSPAN_XCOUNT]) == Ok)
  2931. {
  2932. if (yMax1 < yMax2)
  2933. {
  2934. if (CompactAndOutput(
  2935. yMin1,
  2936. yMax1,
  2937. combineCoords.GetDataBuffer(),
  2938. combineCoords.GetCount(),
  2939. &regionBuilder, NULL) == Ok)
  2940. {
  2941. yMin2 = yMax1;
  2942. goto XorIncYSpan1;
  2943. }
  2944. }
  2945. else if (yMax1 > yMax2)
  2946. {
  2947. if (CompactAndOutput(
  2948. yMin1,
  2949. yMax2,
  2950. combineCoords.GetDataBuffer(),
  2951. combineCoords.GetCount(),
  2952. &regionBuilder, NULL) == Ok)
  2953. {
  2954. yMin1 = yMax2;
  2955. goto XorIncYSpan2;
  2956. }
  2957. }
  2958. else // if (yMax1 == yMax2)
  2959. {
  2960. if (CompactAndOutput(
  2961. yMin1,
  2962. yMax1,
  2963. combineCoords.GetDataBuffer(),
  2964. combineCoords.GetCount(),
  2965. &regionBuilder, NULL) == Ok)
  2966. {
  2967. goto XorIncYSpanBoth;
  2968. }
  2969. }
  2970. }
  2971. return GenericError;
  2972. XorIncYSpanBoth:
  2973. if ((ySpan2 += YSPAN_SIZE) > ySpan2Last)
  2974. {
  2975. done = TRUE;
  2976. }
  2977. else
  2978. {
  2979. yMin2 = ySpan2[YSPAN_YMIN];
  2980. yMax2 = ySpan2[YSPAN_YMAX];
  2981. }
  2982. if ((ySpan1 += YSPAN_SIZE) > ySpan1Last)
  2983. {
  2984. goto XorCheckMoreY2Spans;
  2985. }
  2986. else
  2987. {
  2988. yMin1 = ySpan1[YSPAN_YMIN];
  2989. yMax1 = ySpan1[YSPAN_YMAX];
  2990. }
  2991. if (done)
  2992. {
  2993. break;
  2994. }
  2995. continue;
  2996. XorIncYSpan2:
  2997. if ((ySpan2 += YSPAN_SIZE) > ySpan2Last)
  2998. {
  2999. break;
  3000. }
  3001. yMin2 = ySpan2[YSPAN_YMIN];
  3002. yMax2 = ySpan2[YSPAN_YMAX];
  3003. continue;
  3004. XorIncYSpan1:
  3005. if ((ySpan1 += YSPAN_SIZE) > ySpan1Last)
  3006. {
  3007. goto XorCheckMoreY2Spans;
  3008. }
  3009. yMin1 = ySpan1[YSPAN_YMIN];
  3010. yMax1 = ySpan1[YSPAN_YMAX];
  3011. }
  3012. if (ySpan1 <= ySpan1Last)
  3013. {
  3014. for (;;)
  3015. {
  3016. xSpan = xCoords1 + ySpan1[YSPAN_XOFFSET];
  3017. numXCoords = ySpan1[YSPAN_XCOUNT];
  3018. if (CompactAndOutput(
  3019. yMin1,
  3020. yMax1,
  3021. xSpan,
  3022. numXCoords,
  3023. &regionBuilder,
  3024. &combineCoords) != Ok)
  3025. {
  3026. return GenericError;
  3027. }
  3028. ySpan1 += YSPAN_SIZE;
  3029. if (ySpan1 > ySpan1Last)
  3030. {
  3031. break;
  3032. }
  3033. yMin1 = ySpan1[YSPAN_YMIN];
  3034. yMax1 = ySpan1[YSPAN_YMAX];
  3035. }
  3036. }
  3037. XorCheckMoreY2Spans:
  3038. if (ySpan2 <= ySpan2Last)
  3039. {
  3040. for (;;)
  3041. {
  3042. xSpan = xCoords2 + ySpan2[YSPAN_XOFFSET];
  3043. numXCoords = ySpan2[YSPAN_XCOUNT];
  3044. if (CompactAndOutput(
  3045. yMin2,
  3046. yMax2,
  3047. xSpan,
  3048. numXCoords,
  3049. &regionBuilder,
  3050. &combineCoords) != Ok)
  3051. {
  3052. return GenericError;
  3053. }
  3054. ySpan2 += YSPAN_SIZE;
  3055. if (ySpan2 > ySpan2Last)
  3056. {
  3057. break;
  3058. }
  3059. yMin2 = ySpan2[YSPAN_YMIN];
  3060. yMax2 = ySpan2[YSPAN_YMAX];
  3061. }
  3062. }
  3063. return Set(regionBuilder);
  3064. }
  3065. }
  3066. /**************************************************************************\
  3067. *
  3068. * Function Description:
  3069. *
  3070. * Combine a set of X spans from each region with the XOR operator.
  3071. *
  3072. * Arguments:
  3073. *
  3074. * [IN] combineCoords - where to put the combined coordinates
  3075. * [IN] xSpan1 - x spans from this region
  3076. * [IN] numXCoords1 - number of xSpan1 coordinates
  3077. * [IN] xSpan2 - x spans from the other region
  3078. * [IN] numXCoords2 - number of xSpan2 coordinates
  3079. *
  3080. * Return Value:
  3081. *
  3082. * GpStatus - Ok or failure status
  3083. *
  3084. * Created:
  3085. *
  3086. * 01/06/1999 DCurtis
  3087. *
  3088. \**************************************************************************/
  3089. GpStatus
  3090. DpRegion::XSpansXOR(
  3091. DynIntArray * combineCoords,
  3092. INT * xSpan1,
  3093. INT numXCoords1,
  3094. INT * xSpan2,
  3095. INT numXCoords2)
  3096. {
  3097. INT * XCoords;
  3098. INT count = 0;
  3099. combineCoords->Reset(FALSE);
  3100. XCoords = combineCoords->AddMultiple(numXCoords1 + numXCoords2);
  3101. if (XCoords != NULL)
  3102. {
  3103. INT xMin1 = xSpan1[0];
  3104. INT xMax1 = xSpan1[1];
  3105. INT xMin2 = xSpan2[0];
  3106. INT xMax2 = xSpan2[1];
  3107. BOOL done = FALSE;
  3108. for (;;)
  3109. {
  3110. if (xMin1 < xMin2)
  3111. {
  3112. XCoords[count++] = xMin1; // left
  3113. if (xMax1 <= xMin2)
  3114. {
  3115. XCoords[count++] = xMax1; // right
  3116. goto XorIncXSpan1;
  3117. }
  3118. XCoords[count++] = xMin2; // right
  3119. if (xMax1 < xMax2)
  3120. {
  3121. xMin2 = xMax1;
  3122. goto XorIncXSpan1;
  3123. }
  3124. else if (xMax1 > xMax2)
  3125. {
  3126. xMin1 = xMax2;
  3127. goto XorIncXSpan2;
  3128. }
  3129. // else if (xMax1 == xMax2)
  3130. goto XorIncXSpanBoth;
  3131. }
  3132. else if (xMin1 > xMin2)
  3133. {
  3134. XCoords[count++] = xMin2; // left
  3135. if (xMax2 <= xMin1)
  3136. {
  3137. XCoords[count++] = xMax2; // right
  3138. goto XorIncXSpan2;
  3139. }
  3140. XCoords[count++] = xMin1; // right
  3141. if (xMax1 < xMax2)
  3142. {
  3143. xMin2 = xMax1;
  3144. goto XorIncXSpan1;
  3145. }
  3146. else if (xMax1 > xMax2)
  3147. {
  3148. xMin1 = xMax2;
  3149. goto XorIncXSpan2;
  3150. }
  3151. // else if (xMax1 == xMax2)
  3152. goto XorIncXSpanBoth;
  3153. }
  3154. // else if (xMin1 == xMin2)
  3155. if (xMax1 < xMax2)
  3156. {
  3157. xMin2 = xMax1;
  3158. goto XorIncXSpan1;
  3159. }
  3160. else if (xMax1 > xMax2)
  3161. {
  3162. xMin1 = xMax2;
  3163. goto XorIncXSpan2;
  3164. }
  3165. // else if (xMax1 == xMax2)
  3166. // goto XorIncXSpanBoth;
  3167. XorIncXSpanBoth:
  3168. xSpan2 += 2;
  3169. if ((numXCoords2 -= 2) < 2)
  3170. {
  3171. done = TRUE;
  3172. }
  3173. else
  3174. {
  3175. xMin2 = xSpan2[0];
  3176. xMax2 = xSpan2[1];
  3177. }
  3178. xSpan1 += 2;
  3179. if ((numXCoords1 -= 2) < 2)
  3180. {
  3181. goto XorCheckMoreX2Spans;
  3182. }
  3183. else
  3184. {
  3185. xMin1 = xSpan1[0];
  3186. xMax1 = xSpan1[1];
  3187. }
  3188. if (done)
  3189. {
  3190. break;
  3191. }
  3192. continue;
  3193. XorIncXSpan2:
  3194. xSpan2 += 2;
  3195. if ((numXCoords2 -= 2) < 2)
  3196. {
  3197. break;
  3198. }
  3199. xMin2 = xSpan2[0];
  3200. xMax2 = xSpan2[1];
  3201. continue;
  3202. XorIncXSpan1:
  3203. xSpan1 += 2;
  3204. if ((numXCoords1 -= 2) < 2)
  3205. {
  3206. goto XorCheckMoreX2Spans;
  3207. }
  3208. xMin1 = xSpan1[0];
  3209. xMax1 = xSpan1[1];
  3210. }
  3211. if (numXCoords1 >= 2)
  3212. {
  3213. for (;;)
  3214. {
  3215. XCoords[count++] = xMin1;
  3216. XCoords[count++] = xMax1;
  3217. numXCoords1 -= 2;
  3218. if (numXCoords1 < 2)
  3219. {
  3220. break;
  3221. }
  3222. xSpan1 += 2;
  3223. xMin1 = xSpan1[0];
  3224. xMax1 = xSpan1[1];
  3225. }
  3226. }
  3227. XorCheckMoreX2Spans:
  3228. if (numXCoords2 >= 2)
  3229. {
  3230. for (;;)
  3231. {
  3232. XCoords[count++] = xMin2;
  3233. XCoords[count++] = xMax2;
  3234. numXCoords2 -= 2;
  3235. if (numXCoords2 < 2)
  3236. {
  3237. break;
  3238. }
  3239. xSpan2 += 2;
  3240. xMin2 = xSpan2[0];
  3241. xMax2 = xSpan2[1];
  3242. }
  3243. }
  3244. combineCoords->SetCount(count);
  3245. return Ok;
  3246. }
  3247. return GenericError;
  3248. }
  3249. /**************************************************************************\
  3250. *
  3251. * Function Description:
  3252. *
  3253. * Combine another region with this one using the Complement operator.
  3254. * i.e. this = region - this
  3255. *
  3256. * Arguments:
  3257. *
  3258. * [IN] region - the region to combine with this one
  3259. *
  3260. * Return Value:
  3261. *
  3262. * GpStatus - Ok or failure status
  3263. *
  3264. * Created:
  3265. *
  3266. * 01/06/1999 DCurtis
  3267. *
  3268. \**************************************************************************/
  3269. GpStatus
  3270. DpRegion::Complement(
  3271. const DpRegion * region
  3272. )
  3273. {
  3274. ASSERT(IsValid());
  3275. ASSERT((region != NULL) && region->IsValid());
  3276. if (region->Empty || (region == this) || Infinite)
  3277. {
  3278. SetEmpty();
  3279. return Ok;
  3280. }
  3281. if (Empty)
  3282. {
  3283. return Set(region);
  3284. }
  3285. // check if this totally encompasses the region
  3286. if ((ComplexData == NULL) &&
  3287. (XMin <= region->XMin) &&
  3288. (YMin <= region->YMin) &&
  3289. (XMax >= region->XMax) &&
  3290. (YMax >= region->YMax))
  3291. {
  3292. SetEmpty();
  3293. return Ok;
  3294. }
  3295. // check for no intersection
  3296. if ((XMin >= region->XMax) ||
  3297. (region->XMax <= XMin) ||
  3298. (XMax <= region->XMin) ||
  3299. (region->XMin >= XMax) ||
  3300. (YMin >= region->YMax) ||
  3301. (region->YMax <= YMin) ||
  3302. (YMax <= region->YMin) ||
  3303. (region->YMin >= YMax))
  3304. {
  3305. return Set(region);
  3306. }
  3307. return Diff(const_cast<DpRegion *>(region), this, FALSE);
  3308. }
  3309. /**************************************************************************\
  3310. *
  3311. * Function Description:
  3312. *
  3313. * Combine another region with this one using the Exclude operator.
  3314. * i.e. this = this - region
  3315. *
  3316. * Arguments:
  3317. *
  3318. * [IN] region - the region to combine with this one
  3319. *
  3320. * Return Value:
  3321. *
  3322. * GpStatus - Ok or failure status
  3323. *
  3324. * Created:
  3325. *
  3326. * 01/06/1999 DCurtis
  3327. *
  3328. \**************************************************************************/
  3329. GpStatus
  3330. DpRegion::Exclude(
  3331. const DpRegion * region
  3332. )
  3333. {
  3334. ASSERT(IsValid());
  3335. ASSERT((region != NULL) && region->IsValid());
  3336. if (Empty || region->Empty)
  3337. {
  3338. return Ok;
  3339. }
  3340. if ((region == this) || region->Infinite)
  3341. {
  3342. SetEmpty();
  3343. return Ok;
  3344. }
  3345. // check if the region totally encompasses this
  3346. if ((region->ComplexData == NULL) &&
  3347. (region->XMin <= XMin) &&
  3348. (region->YMin <= YMin) &&
  3349. (region->XMax >= XMax) &&
  3350. (region->YMax >= YMax))
  3351. {
  3352. SetEmpty();
  3353. return Ok;
  3354. }
  3355. // check for no intersection
  3356. if ((XMin >= region->XMax) ||
  3357. (region->XMax <= XMin) ||
  3358. (XMax <= region->XMin) ||
  3359. (region->XMin >= XMax) ||
  3360. (YMin >= region->YMax) ||
  3361. (region->YMax <= YMin) ||
  3362. (YMax <= region->YMin) ||
  3363. (region->YMin >= YMax))
  3364. {
  3365. return Ok;
  3366. }
  3367. return Diff(this, const_cast<DpRegion *>(region), TRUE);
  3368. }
  3369. /**************************************************************************\
  3370. *
  3371. * Function Description:
  3372. *
  3373. * Subtract region2 from region1. If set1, then region1 gets the result;
  3374. * otherwise region2 gets the result.
  3375. *
  3376. * Arguments:
  3377. *
  3378. * [IN] region1 - the 1st region
  3379. * [IN] region2 - the 2nd region
  3380. * [IN] set1 - if TRUE, region1 gets result, else region2 does
  3381. *
  3382. * Return Value:
  3383. *
  3384. * GpStatus - Ok or failure status
  3385. *
  3386. * Created:
  3387. *
  3388. * 01/06/1999 DCurtis
  3389. *
  3390. \**************************************************************************/
  3391. GpStatus
  3392. DpRegion::Diff(
  3393. DpRegion * region1,
  3394. DpRegion * region2,
  3395. BOOL set1
  3396. )
  3397. {
  3398. INT * ySpan1;
  3399. INT * ySpan2;
  3400. INT * ySpan1Last;
  3401. INT * ySpan2Last;
  3402. INT * xCoords1;
  3403. INT * xCoords2;
  3404. INT ySpan1Tmp[YSPAN_SIZE];
  3405. INT ySpan2Tmp[YSPAN_SIZE];
  3406. INT xCoords1Tmp[2];
  3407. INT xCoords2Tmp[2];
  3408. INT yMin1 = region1->YMin;
  3409. INT yMax1;
  3410. INT yMin2 = region2->YMin;
  3411. INT yMax2;
  3412. INT numYSpans1;
  3413. INT numYSpans2;
  3414. INT combineTmp[4];
  3415. DynIntArray combineCoords(combineTmp, 4);
  3416. if (region1->ComplexData == NULL)
  3417. {
  3418. numYSpans1 = 1;
  3419. ySpan1 = ySpan1Tmp;
  3420. ySpan1Last = ySpan1Tmp;
  3421. yMax1 = region1->YMax;
  3422. ySpan1[YSPAN_YMIN] = yMin1;
  3423. ySpan1[YSPAN_YMAX] = yMax1;
  3424. ySpan1[YSPAN_XOFFSET] = 0;
  3425. ySpan1[YSPAN_XCOUNT] = 2;
  3426. xCoords1 = xCoords1Tmp;
  3427. xCoords1[0] = region1->XMin;
  3428. xCoords1[1] = region1->XMax;
  3429. }
  3430. else
  3431. {
  3432. numYSpans1 = region1->ComplexData->NumYSpans;
  3433. ySpan1 = region1->ComplexData->YSpans;
  3434. ySpan1Last = ySpan1 + ((numYSpans1 - 1) * YSPAN_SIZE);
  3435. yMax1 = ySpan1[YSPAN_YMAX];
  3436. xCoords1 = region1->ComplexData->XCoords;
  3437. }
  3438. if (region2->ComplexData == NULL)
  3439. {
  3440. numYSpans2 = 1;
  3441. ySpan2 = ySpan2Tmp;
  3442. ySpan2Last = ySpan2Tmp;
  3443. yMax2 = region2->YMax;
  3444. ySpan2[YSPAN_YMIN] = yMin2;
  3445. ySpan2[YSPAN_YMAX] = yMax2;
  3446. ySpan2[YSPAN_XOFFSET] = 0;
  3447. ySpan2[YSPAN_XCOUNT] = 2;
  3448. xCoords2 = xCoords2Tmp;
  3449. xCoords2[0] = region2->XMin;
  3450. xCoords2[1] = region2->XMax;
  3451. }
  3452. else
  3453. {
  3454. numYSpans2 = region2->ComplexData->NumYSpans;
  3455. ySpan2 = region2->ComplexData->YSpans;
  3456. ySpan2Last = ySpan2 + ((numYSpans2 - 1) * YSPAN_SIZE);
  3457. yMax2 = ySpan2[YSPAN_YMAX];
  3458. xCoords2 = region2->ComplexData->XCoords;
  3459. }
  3460. DpRegionBuilder regionBuilder(numYSpans1 + (2 * numYSpans2));
  3461. INT numXCoords;
  3462. INT * xSpan;
  3463. if (!regionBuilder.IsValid())
  3464. {
  3465. return OutOfMemory;
  3466. }
  3467. for (;;)
  3468. {
  3469. if (yMin1 < yMin2)
  3470. {
  3471. xSpan = xCoords1 + ySpan1[YSPAN_XOFFSET];
  3472. numXCoords = ySpan1[YSPAN_XCOUNT];
  3473. if (yMax1 <= yMin2)
  3474. {
  3475. if (CompactAndOutput(
  3476. yMin1,
  3477. yMax1,
  3478. xSpan,
  3479. numXCoords,
  3480. &regionBuilder,
  3481. &combineCoords) == Ok)
  3482. {
  3483. goto DiffIncYSpan1;
  3484. }
  3485. }
  3486. else
  3487. {
  3488. if (CompactAndOutput(
  3489. yMin1,
  3490. yMin2,
  3491. xSpan,
  3492. numXCoords,
  3493. &regionBuilder,
  3494. &combineCoords) == Ok)
  3495. {
  3496. yMin1 = yMin2;
  3497. continue; // no increment
  3498. }
  3499. }
  3500. return GenericError;
  3501. }
  3502. else if (yMin1 < yMax2)
  3503. {
  3504. if (XSpansDIFF(
  3505. &combineCoords,
  3506. xCoords1 + ySpan1[YSPAN_XOFFSET],
  3507. ySpan1[YSPAN_XCOUNT],
  3508. xCoords2 + ySpan2[YSPAN_XOFFSET],
  3509. ySpan2[YSPAN_XCOUNT]) == Ok)
  3510. {
  3511. if (yMax1 <= yMax2)
  3512. {
  3513. if (CompactAndOutput(
  3514. yMin1,
  3515. yMax1,
  3516. combineCoords.GetDataBuffer(),
  3517. combineCoords.GetCount(),
  3518. &regionBuilder, NULL) == Ok)
  3519. {
  3520. goto DiffIncYSpan1;
  3521. }
  3522. }
  3523. else
  3524. {
  3525. if (CompactAndOutput(
  3526. yMin1,
  3527. yMax2,
  3528. combineCoords.GetDataBuffer(),
  3529. combineCoords.GetCount(),
  3530. &regionBuilder, NULL) == Ok)
  3531. {
  3532. yMin1 = yMax2;
  3533. goto DiffIncYSpan2;
  3534. }
  3535. }
  3536. }
  3537. return GenericError;
  3538. }
  3539. // else goto DiffIncYSpan2;
  3540. DiffIncYSpan2:
  3541. if ((ySpan2 += YSPAN_SIZE) > ySpan2Last)
  3542. {
  3543. break;
  3544. }
  3545. yMin2 = ySpan2[YSPAN_YMIN];
  3546. yMax2 = ySpan2[YSPAN_YMAX];
  3547. continue;
  3548. DiffIncYSpan1:
  3549. if ((ySpan1 += YSPAN_SIZE) > ySpan1Last)
  3550. {
  3551. goto DiffDone;
  3552. }
  3553. yMin1 = ySpan1[YSPAN_YMIN];
  3554. yMax1 = ySpan1[YSPAN_YMAX];
  3555. }
  3556. if (ySpan1 <= ySpan1Last)
  3557. {
  3558. for (;;)
  3559. {
  3560. xSpan = xCoords1 + ySpan1[YSPAN_XOFFSET];
  3561. numXCoords = ySpan1[YSPAN_XCOUNT];
  3562. if (CompactAndOutput(
  3563. yMin1,
  3564. yMax1,
  3565. xSpan,
  3566. numXCoords,
  3567. &regionBuilder,
  3568. &combineCoords) != Ok)
  3569. {
  3570. return GenericError;
  3571. }
  3572. ySpan1 += YSPAN_SIZE;
  3573. if (ySpan1 > ySpan1Last)
  3574. {
  3575. break;
  3576. }
  3577. yMin1 = ySpan1[YSPAN_YMIN];
  3578. yMax1 = ySpan1[YSPAN_YMAX];
  3579. }
  3580. }
  3581. DiffDone:
  3582. if (set1)
  3583. {
  3584. return region1->Set(regionBuilder);
  3585. }
  3586. return region2->Set(regionBuilder);
  3587. }
  3588. /**************************************************************************\
  3589. *
  3590. * Function Description:
  3591. *
  3592. * Combine a set of X spans from each region with the DIFF operator.
  3593. * i.e. xSpan1 - xSpan2
  3594. *
  3595. * Arguments:
  3596. *
  3597. * [IN] combineCoords - where to put the combined coordinates
  3598. * [IN] xSpan1 - x spans from this region
  3599. * [IN] numXCoords1 - number of xSpan1 coordinates
  3600. * [IN] xSpan2 - x spans from the other region
  3601. * [IN] numXCoords2 - number of xSpan2 coordinates
  3602. *
  3603. * Return Value:
  3604. *
  3605. * GpStatus - Ok or failure status
  3606. *
  3607. * Created:
  3608. *
  3609. * 01/06/1999 DCurtis
  3610. *
  3611. \**************************************************************************/
  3612. GpStatus
  3613. DpRegion::XSpansDIFF(
  3614. DynIntArray * combineCoords,
  3615. INT * xSpan1,
  3616. INT numXCoords1,
  3617. INT * xSpan2,
  3618. INT numXCoords2)
  3619. {
  3620. INT * XCoords;
  3621. INT count = 0;
  3622. combineCoords->Reset(FALSE);
  3623. XCoords = combineCoords->AddMultiple(numXCoords1 + numXCoords2);
  3624. if (XCoords != NULL)
  3625. {
  3626. INT xMin1 = xSpan1[0];
  3627. INT xMax1 = xSpan1[1];
  3628. INT xMin2 = xSpan2[0];
  3629. INT xMax2 = xSpan2[1];
  3630. for (;;)
  3631. {
  3632. if (xMin1 < xMin2)
  3633. {
  3634. XCoords[count++] = xMin1; // left
  3635. if (xMax1 <= xMin2)
  3636. {
  3637. XCoords[count++] = xMax1; // right
  3638. goto DiffIncXSpan1;
  3639. }
  3640. XCoords[count++] = xMin2; // right
  3641. xMin1 = xMin2;
  3642. continue; // no increment
  3643. }
  3644. else if (xMin1 < xMax2)
  3645. {
  3646. if (xMax1 <= xMax2)
  3647. {
  3648. goto DiffIncXSpan1;
  3649. }
  3650. xMin1 = xMax2;
  3651. // goto DiffIncXSpan2;
  3652. }
  3653. // else goto DiffIncXSpan2;
  3654. // DiffIncXSpan2:
  3655. xSpan2 += 2;
  3656. if ((numXCoords2 -= 2) < 2)
  3657. {
  3658. break;
  3659. }
  3660. xMin2 = xSpan2[0];
  3661. xMax2 = xSpan2[1];
  3662. continue;
  3663. DiffIncXSpan1:
  3664. xSpan1 += 2;
  3665. if ((numXCoords1 -= 2) < 2)
  3666. {
  3667. goto DiffDone;
  3668. }
  3669. xMin1 = xSpan1[0];
  3670. xMax1 = xSpan1[1];
  3671. }
  3672. if (numXCoords1 >= 2)
  3673. {
  3674. for (;;)
  3675. {
  3676. XCoords[count++] = xMin1;
  3677. XCoords[count++] = xMax1;
  3678. numXCoords1 -= 2;
  3679. if (numXCoords1 < 2)
  3680. {
  3681. break;
  3682. }
  3683. xSpan1 += 2;
  3684. xMin1 = xSpan1[0];
  3685. xMax1 = xSpan1[1];
  3686. }
  3687. }
  3688. DiffDone:
  3689. combineCoords->SetCount(count);
  3690. return Ok;
  3691. }
  3692. return GenericError;
  3693. }
  3694. /**************************************************************************\
  3695. *
  3696. * Function Description:
  3697. *
  3698. * Initialize the clipper by setting the output method and setting the
  3699. * starting y span search index.
  3700. *
  3701. * Arguments:
  3702. *
  3703. * [IN] outputClippedSpan - The output class for clipped spans
  3704. * [IN] yMin - The starting y value of the object to clip
  3705. *
  3706. * Return Value:
  3707. *
  3708. * NONE
  3709. *
  3710. * Created:
  3711. *
  3712. * 01/12/1999 DCurtis
  3713. *
  3714. \**************************************************************************/
  3715. VOID
  3716. DpClipRegion::InitClipping(
  3717. DpOutputSpan * outputClippedSpan,
  3718. INT yMin
  3719. )
  3720. {
  3721. OutputClippedSpan = outputClippedSpan;
  3722. // init search index if appropriate
  3723. if (ComplexData != NULL)
  3724. {
  3725. INT * ySpan;
  3726. INT ySpanIndex;
  3727. ComplexData->ResetSearchIndex();
  3728. ComplexData->YSpanSearch (yMin, &ySpan, &ySpanIndex);
  3729. ComplexData->YSearchIndex = ySpanIndex;
  3730. }
  3731. }
  3732. /**************************************************************************\
  3733. *
  3734. * Function Description:
  3735. *
  3736. * The method called from the rasterizer during the rasterization when a
  3737. * horizontal span has been identified. We clip it and if not clipped out,
  3738. * we send the clipped data to the output method.
  3739. *
  3740. * Arguments:
  3741. *
  3742. * [IN] y - the Y value of the raster being output
  3743. * [IN] xMin - the X value of the left edge
  3744. * [IN] xMax - the X value of the right edge (exclusive)
  3745. *
  3746. * Return Value:
  3747. *
  3748. * NONE
  3749. *
  3750. * Created:
  3751. *
  3752. * 01/12/1999 DCurtis
  3753. *
  3754. \**************************************************************************/
  3755. GpStatus
  3756. DpClipRegion::OutputSpan(
  3757. INT y,
  3758. INT xMin,
  3759. INT xMax // xMax is exclusive
  3760. )
  3761. {
  3762. ASSERT(!Empty && !Infinite);
  3763. ASSERT(OutputClippedSpan != NULL);
  3764. INT xMinCur = xMin;
  3765. INT xMaxCur = xMax;
  3766. // do simple clip test to bounding rectangle
  3767. if ((xMin < XMax) && (xMax > XMin) &&
  3768. (y >= YMin) && (y < YMax))
  3769. {
  3770. if (xMin < XMin)
  3771. {
  3772. xMinCur = XMin;
  3773. }
  3774. if (xMax > XMax)
  3775. {
  3776. xMaxCur = XMax;
  3777. }
  3778. }
  3779. else
  3780. return Ok;
  3781. if (ComplexData == NULL)
  3782. {
  3783. return OutputClippedSpan->OutputSpan(y, xMinCur, xMaxCur);
  3784. }
  3785. else // not a simple region
  3786. {
  3787. // find the Y span that includes the line (if any)
  3788. INT ySpanIndex = ComplexData->YSearchIndex;
  3789. INT * ySpan = ComplexData->GetYSpan (ySpanIndex);
  3790. if (y >= ySpan[YSPAN_YMIN])
  3791. {
  3792. if (y >= ySpan[YSPAN_YMAX])
  3793. {
  3794. // do forward linear search from previous point
  3795. for (;;)
  3796. {
  3797. // see if we're past the end of the tessellation
  3798. if (++ySpanIndex >= ComplexData->NumYSpans)
  3799. {
  3800. ComplexData->YSearchIndex = ComplexData->NumYSpans - 1;
  3801. return Ok; // nothing to draw
  3802. }
  3803. ySpan += YSPAN_SIZE;
  3804. if (y < ySpan[YSPAN_YMAX])
  3805. {
  3806. ComplexData->YSearchIndex = ySpanIndex;
  3807. if (y >= ySpan[YSPAN_YMIN])
  3808. {
  3809. break;
  3810. }
  3811. return Ok; // nothing to draw
  3812. }
  3813. }
  3814. }
  3815. // else yMin is inside this ySpan
  3816. }
  3817. else // need to search backward (shouldn't happen when rasterizing)
  3818. {
  3819. for (;;)
  3820. {
  3821. if (ySpanIndex == 0)
  3822. {
  3823. ComplexData->YSearchIndex = 0;
  3824. return Ok; // nothing to draw
  3825. }
  3826. ySpanIndex--;
  3827. ySpan -= YSPAN_SIZE;
  3828. if (y >= ySpan[YSPAN_YMIN])
  3829. {
  3830. ComplexData->YSearchIndex = ySpanIndex;
  3831. if (y < ySpan[YSPAN_YMAX])
  3832. {
  3833. break;
  3834. }
  3835. return Ok; // nothing to draw
  3836. }
  3837. }
  3838. }
  3839. // If we get here, we know there y is within a Y span and that
  3840. // ySpan points to the correct Y span
  3841. GpStatus status = Ok;
  3842. INT * xSpan;
  3843. INT numXCoords;
  3844. xSpan = ComplexData->XCoords + ySpan[YSPAN_XOFFSET];
  3845. numXCoords = ySpan[YSPAN_XCOUNT];
  3846. for (;;)
  3847. {
  3848. if (xMax <= xSpan[0])
  3849. {
  3850. break;
  3851. }
  3852. if (xMin < xSpan[1])
  3853. {
  3854. xMinCur = (xMin < xSpan[0]) ? xSpan[0] : xMin;
  3855. xMaxCur = (xMax > xSpan[1]) ? xSpan[1] : xMax;
  3856. status = OutputClippedSpan->OutputSpan(y, xMinCur, xMaxCur);
  3857. }
  3858. // continue on with loop through x spans
  3859. if (((numXCoords -= 2) <= 0) || (status != Ok))
  3860. {
  3861. break;
  3862. }
  3863. xSpan += 2;
  3864. }
  3865. return status;
  3866. }
  3867. }
  3868. INT
  3869. DpRegion::GetRects(
  3870. GpRect * rects
  3871. ) const
  3872. {
  3873. if (Empty)
  3874. {
  3875. return 0;
  3876. }
  3877. else if (Infinite)
  3878. {
  3879. if (rects != NULL)
  3880. {
  3881. rects->X = INFINITE_MIN;
  3882. rects->Y = INFINITE_MIN;
  3883. rects->Width = INFINITE_SIZE;
  3884. rects->Height = INFINITE_SIZE;
  3885. }
  3886. return 1;
  3887. }
  3888. else if (ComplexData == NULL)
  3889. {
  3890. if (rects != NULL)
  3891. {
  3892. rects->X = XMin;
  3893. rects->Y = YMin;
  3894. rects->Width = XMax - XMin;
  3895. rects->Height = YMax - YMin;
  3896. }
  3897. return 1;
  3898. }
  3899. else
  3900. {
  3901. if (rects != NULL)
  3902. {
  3903. DpComplexRegion * complexData = ComplexData;
  3904. INT * xCoords = complexData->XCoords;
  3905. INT * ySpan = complexData->YSpans;
  3906. INT * ySpanLast = ySpan +
  3907. ((complexData->NumYSpans - 1) * YSPAN_SIZE);
  3908. INT numXCoords;
  3909. INT yMin;
  3910. INT height;
  3911. INT xMin;
  3912. INT xMax;
  3913. do
  3914. {
  3915. yMin = ySpan[YSPAN_YMIN];
  3916. height = ySpan[YSPAN_YMAX] - yMin;
  3917. numXCoords = ySpan[YSPAN_XCOUNT];
  3918. do
  3919. {
  3920. xMin = *xCoords++;
  3921. xMax = *xCoords++;
  3922. rects->X = xMin;
  3923. rects->Y = yMin;
  3924. rects->Width = xMax - xMin;
  3925. rects->Height = height;
  3926. rects++;
  3927. numXCoords -= 2;
  3928. } while (numXCoords >= 2);
  3929. ySpan += YSPAN_SIZE;
  3930. } while (ySpan <= ySpanLast);
  3931. }
  3932. return ComplexData->XCoordsCount / 2;
  3933. }
  3934. }
  3935. INT
  3936. DpRegion::GetRects(
  3937. GpRectF * rects
  3938. ) const
  3939. {
  3940. if (Empty)
  3941. {
  3942. return 0;
  3943. }
  3944. else if (Infinite)
  3945. {
  3946. if (rects != NULL)
  3947. {
  3948. rects->X = (REAL)INFINITE_MIN;
  3949. rects->Y = (REAL)INFINITE_MIN;
  3950. rects->Width = (REAL)INFINITE_SIZE;
  3951. rects->Height = (REAL)INFINITE_SIZE;
  3952. }
  3953. return 1;
  3954. }
  3955. else if (ComplexData == NULL)
  3956. {
  3957. if (rects != NULL)
  3958. {
  3959. rects->X = (REAL)XMin;
  3960. rects->Y = (REAL)YMin;
  3961. rects->Width = (REAL)(XMax - XMin);
  3962. rects->Height = (REAL)(YMax - YMin);
  3963. }
  3964. return 1;
  3965. }
  3966. else
  3967. {
  3968. if (rects != NULL)
  3969. {
  3970. DpComplexRegion * complexData = ComplexData;
  3971. INT * xCoords = complexData->XCoords;
  3972. INT * ySpan = complexData->YSpans;
  3973. INT * ySpanLast = ySpan +
  3974. ((complexData->NumYSpans - 1) * YSPAN_SIZE);
  3975. INT numXCoords;
  3976. INT yMin;
  3977. INT height;
  3978. INT xMin;
  3979. INT xMax;
  3980. do
  3981. {
  3982. yMin = ySpan[YSPAN_YMIN];
  3983. height = ySpan[YSPAN_YMAX] - yMin;
  3984. numXCoords = ySpan[YSPAN_XCOUNT];
  3985. do
  3986. {
  3987. xMin = *xCoords++;
  3988. xMax = *xCoords++;
  3989. rects->X = (REAL)xMin;
  3990. rects->Y = (REAL)yMin;
  3991. rects->Width = (REAL)(xMax - xMin);
  3992. rects->Height = (REAL)height;
  3993. rects++;
  3994. numXCoords -= 2;
  3995. } while (numXCoords >= 2);
  3996. ySpan += YSPAN_SIZE;
  3997. } while (ySpan <= ySpanLast);
  3998. }
  3999. return ComplexData->XCoordsCount / 2;
  4000. }
  4001. }
  4002. // The WIN9x infinite max and min values are set up to be the greatest
  4003. // values that will interop with GDI HRGNs on Win9x successfully.
  4004. #define INFINITE_MIN_WIN9X -16384
  4005. #define INFINITE_MAX_WIN9X 16383
  4006. INT
  4007. DpRegion::GetRects(
  4008. RECT * rects,
  4009. BOOL clampToWin9xSize
  4010. ) const
  4011. {
  4012. if (Empty)
  4013. {
  4014. return 0;
  4015. }
  4016. else if (Infinite)
  4017. {
  4018. if (rects != NULL)
  4019. {
  4020. if (!clampToWin9xSize)
  4021. {
  4022. rects->left = INFINITE_MIN;
  4023. rects->top = INFINITE_MIN;
  4024. rects->right = INFINITE_MAX;
  4025. rects->bottom = INFINITE_MAX;
  4026. }
  4027. else
  4028. {
  4029. rects->left = INFINITE_MIN_WIN9X;
  4030. rects->top = INFINITE_MIN_WIN9X;
  4031. rects->right = INFINITE_MAX_WIN9X;
  4032. rects->bottom = INFINITE_MAX_WIN9X;
  4033. }
  4034. }
  4035. return 1;
  4036. }
  4037. else if (ComplexData == NULL)
  4038. {
  4039. if (rects != NULL)
  4040. {
  4041. rects->left = XMin;
  4042. rects->top = YMin;
  4043. rects->right = XMax;
  4044. rects->bottom = YMax;
  4045. if (clampToWin9xSize)
  4046. {
  4047. if (rects->left < INFINITE_MIN_WIN9X)
  4048. {
  4049. rects->left = INFINITE_MIN_WIN9X;
  4050. }
  4051. if (rects->top < INFINITE_MIN_WIN9X)
  4052. {
  4053. rects->top = INFINITE_MIN_WIN9X;
  4054. }
  4055. if (rects->right > INFINITE_MAX_WIN9X)
  4056. {
  4057. rects->right = INFINITE_MAX_WIN9X;
  4058. }
  4059. if (rects->bottom > INFINITE_MAX_WIN9X)
  4060. {
  4061. rects->bottom = INFINITE_MAX_WIN9X;
  4062. }
  4063. }
  4064. }
  4065. return 1;
  4066. }
  4067. else
  4068. {
  4069. if (rects != NULL)
  4070. {
  4071. DpComplexRegion * complexData = ComplexData;
  4072. INT * xCoords = complexData->XCoords;
  4073. INT * ySpan = complexData->YSpans;
  4074. INT * ySpanLast = ySpan +
  4075. ((complexData->NumYSpans - 1) * YSPAN_SIZE);
  4076. INT numXCoords;
  4077. INT yMin;
  4078. INT height;
  4079. INT xMin;
  4080. INT xMax;
  4081. do
  4082. {
  4083. yMin = ySpan[YSPAN_YMIN];
  4084. height = ySpan[YSPAN_YMAX] - yMin;
  4085. numXCoords = ySpan[YSPAN_XCOUNT];
  4086. do
  4087. {
  4088. xMin = *xCoords++;
  4089. xMax = *xCoords++;
  4090. rects->left = xMin;
  4091. rects->top = yMin;
  4092. rects->right = xMax;
  4093. rects->bottom = yMin + height;
  4094. if (clampToWin9xSize)
  4095. {
  4096. // In this case, this could invalidate the region,
  4097. // but hopefully ExtCreateRegion will catch this.
  4098. if (rects->left < INFINITE_MIN_WIN9X)
  4099. {
  4100. rects->left = INFINITE_MIN_WIN9X;
  4101. }
  4102. if (rects->top < INFINITE_MIN_WIN9X)
  4103. {
  4104. rects->top = INFINITE_MIN_WIN9X;
  4105. }
  4106. if (rects->right > INFINITE_MAX_WIN9X)
  4107. {
  4108. rects->right = INFINITE_MAX_WIN9X;
  4109. }
  4110. if (rects->bottom > INFINITE_MAX_WIN9X)
  4111. {
  4112. rects->bottom = INFINITE_MAX_WIN9X;
  4113. }
  4114. }
  4115. rects++;
  4116. numXCoords -= 2;
  4117. } while (numXCoords >= 2);
  4118. ySpan += YSPAN_SIZE;
  4119. } while (ySpan <= ySpanLast);
  4120. }
  4121. return ComplexData->XCoordsCount / 2;
  4122. }
  4123. }
  4124. // If error, returns INVALID_HANDLE_VALUE
  4125. HRGN
  4126. DpRegion::GetHRgn() const
  4127. {
  4128. HRGN hRgn = NULL;
  4129. if (Infinite)
  4130. {
  4131. return NULL;
  4132. }
  4133. else if (Empty)
  4134. {
  4135. hRgn = CreateRectRgn(0, 0, 0, 0);
  4136. }
  4137. else if (ComplexData == NULL)
  4138. {
  4139. hRgn = CreateRectRgn(XMin, YMin, XMax, YMax);
  4140. }
  4141. else
  4142. {
  4143. INT numRects = GetRects((RECT *)NULL);
  4144. ASSERT(numRects > 1);
  4145. // Allocate memory to hold RGNDATA structure
  4146. INT rgnDataSize = numRects * sizeof(RECT);
  4147. RGNDATA * rgnData = (RGNDATA*)GpMalloc(sizeof(RGNDATAHEADER) +
  4148. rgnDataSize);
  4149. if (rgnData != NULL)
  4150. {
  4151. RECT* rects = (RECT*)rgnData->Buffer;
  4152. RECT bounds;
  4153. bounds.left = XMin;
  4154. bounds.top = YMin;
  4155. bounds.right = XMax;
  4156. bounds.bottom = YMax;
  4157. rgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
  4158. rgnData->rdh.iType = RDH_RECTANGLES;
  4159. rgnData->rdh.nCount = numRects;
  4160. rgnData->rdh.nRgnSize = rgnDataSize;
  4161. rgnData->rdh.rcBound = bounds;
  4162. GetRects(rects, !Globals::IsNt);
  4163. hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + rgnDataSize,
  4164. rgnData);
  4165. GpFree(rgnData);
  4166. }
  4167. }
  4168. if (hRgn != NULL)
  4169. {
  4170. return hRgn;
  4171. }
  4172. WARNING(("Couldn't create win32 HRGN"));
  4173. return (HRGN)INVALID_HANDLE_VALUE;
  4174. }
  4175. VOID
  4176. DpClipRegion::StartEnumeration (
  4177. INT yMin,
  4178. Direction direction
  4179. )
  4180. {
  4181. INT * ySpan;
  4182. EnumDirection = direction;
  4183. if (ComplexData != NULL)
  4184. {
  4185. DpComplexRegion * complexData = ComplexData;
  4186. INT ySpanIndex;
  4187. complexData->ResetSearchIndex();
  4188. complexData->YSpanSearch (yMin, &ySpan, &ySpanIndex);
  4189. complexData->YSearchIndex = ySpanIndex;
  4190. if(EnumDirection == TopLeftToBottomRight ||
  4191. EnumDirection == BottomLeftToTopRight )
  4192. {
  4193. EnumSpan = 0;
  4194. }
  4195. else
  4196. {
  4197. EnumSpan = ySpan[YSPAN_XCOUNT] - 2;
  4198. }
  4199. if(EnumDirection == BottomLeftToTopRight ||
  4200. EnumDirection == BottomRightToTopLeft)
  4201. {
  4202. //If the enumeration is from bottom to top,
  4203. //and the suplied y is not inside a span, we
  4204. //want to return the span with the next smaller
  4205. //y, instead of the one with the next largest y.
  4206. //Or better, the next span in the enumeration order.
  4207. if(yMin < ySpan[YSPAN_YMIN])
  4208. {
  4209. //Get the previous span
  4210. complexData->YSearchIndex--;
  4211. if(complexData->YSearchIndex < 0)
  4212. {
  4213. complexData->YSearchIndex = 0;
  4214. EnumDirection = NotEnumerating;
  4215. }
  4216. }
  4217. }
  4218. else
  4219. {
  4220. if(yMin > ySpan[YSPAN_YMAX])
  4221. {
  4222. // This situation can only happen if there
  4223. // are no more spans.
  4224. EnumDirection = NotEnumerating;
  4225. }
  4226. }
  4227. }
  4228. }
  4229. BOOL
  4230. DpClipRegion::Enumerate (
  4231. GpRect * rects,
  4232. INT & numRects
  4233. )
  4234. {
  4235. INT numOut = 0;
  4236. INT *ySpan = ComplexData->YSpans +
  4237. ComplexData->YSearchIndex*YSPAN_SIZE;
  4238. if(EnumDirection == NotEnumerating)
  4239. {
  4240. numRects = 0;
  4241. return FALSE;
  4242. }
  4243. while(numOut < numRects)
  4244. {
  4245. // Return the current rectangle
  4246. INT *xCoords = ComplexData->XCoords + ySpan[YSPAN_XOFFSET] + EnumSpan;
  4247. INT xMin = *xCoords++;
  4248. INT xMax = *xCoords;
  4249. rects->X = xMin;
  4250. rects->Y = ySpan[YSPAN_YMIN];
  4251. rects->Width = xMax - xMin;
  4252. rects->Height = ySpan[YSPAN_YMAX] - rects->Y;
  4253. rects++;
  4254. numOut++;
  4255. // Update the indices
  4256. switch(EnumDirection)
  4257. {
  4258. case TopLeftToBottomRight:
  4259. EnumSpan += 2;
  4260. if(EnumSpan == ySpan[YSPAN_XCOUNT])
  4261. {
  4262. if(ComplexData->YSearchIndex == ComplexData->NumYSpans - 1)
  4263. {
  4264. goto enumeration_finished;
  4265. }
  4266. ComplexData->YSearchIndex++;
  4267. ySpan += YSPAN_SIZE;
  4268. EnumSpan = 0;
  4269. }
  4270. break;
  4271. case BottomLeftToTopRight:
  4272. EnumSpan += 2;
  4273. if(EnumSpan == ySpan[YSPAN_XCOUNT])
  4274. {
  4275. if(ComplexData->YSearchIndex == 0)
  4276. {
  4277. goto enumeration_finished;
  4278. }
  4279. ComplexData->YSearchIndex--;
  4280. ySpan -= YSPAN_SIZE;
  4281. EnumSpan = 0;
  4282. }
  4283. break;
  4284. case TopRightToBottomLeft:
  4285. EnumSpan -= 2;
  4286. if(EnumSpan < 0)
  4287. {
  4288. if(ComplexData->YSearchIndex == ComplexData->NumYSpans - 1)
  4289. {
  4290. goto enumeration_finished;
  4291. }
  4292. ComplexData->YSearchIndex++;
  4293. ySpan += YSPAN_SIZE;
  4294. EnumSpan = ySpan[YSPAN_XCOUNT] - 2;
  4295. }
  4296. break;
  4297. case BottomRightToTopLeft:
  4298. EnumSpan -= 2;
  4299. if(EnumSpan < 0)
  4300. {
  4301. if(ComplexData->YSearchIndex == 0)
  4302. {
  4303. goto enumeration_finished;
  4304. }
  4305. ComplexData->YSearchIndex--;
  4306. ySpan -= YSPAN_SIZE;
  4307. EnumSpan = ySpan[YSPAN_XCOUNT] - 2;
  4308. }
  4309. break;
  4310. }
  4311. }
  4312. numRects = numOut;
  4313. return TRUE;
  4314. enumeration_finished:
  4315. EnumDirection = NotEnumerating;
  4316. numRects = numOut;
  4317. return FALSE;
  4318. }
  4319. /**************************************************************************\
  4320. *
  4321. * Function Description:
  4322. *
  4323. * The method called to convert the region scans to an outline path. The
  4324. * path can be quite large and contains only points at righ angles with
  4325. * each other.
  4326. *
  4327. * Arguments:
  4328. *
  4329. * [IN,OUT] points - array of points to output
  4330. * [IN,OUT] types - array of types for output
  4331. *
  4332. * We do not return a path because we work on GpPoint's not GpPointF's.
  4333. *
  4334. * NOTE: This alorithm was copied from GDI's RGNOBJ::bOutline by
  4335. * J. Andrew Goossen.
  4336. *
  4337. *
  4338. * Return Value:
  4339. *
  4340. * NONE
  4341. *
  4342. * Created:
  4343. *
  4344. * 01/12/1999 DCurtis
  4345. *
  4346. \**************************************************************************/
  4347. // Because the XCoords may be negative, the high bit is reserved. Instead we
  4348. // use a bit in the Types byte array since we know the
  4349. // Types.Count >= XCoordsCount. We also know that points generated by this
  4350. // code aren't in dash mode, so we reuse the dash mode bit for marking a
  4351. // visited wall. We clear all bits on exit.
  4352. const UINT MarkWallBit = PathPointTypeDashMode; // 0x10, currently in dash mode.
  4353. #define XOFFSET(span,index) (INT)(XCoords[*(span + YSPAN_XOFFSET) + index])
  4354. #define XCOUNT(span) *(span + YSPAN_XCOUNT)
  4355. #define MARKXOFFSET(span,index) MarkWallPtr[*(span + YSPAN_XOFFSET) + index] \
  4356. |= MarkWallBit
  4357. // This macro adds a type to the type array. If the current count exceeds
  4358. // the capacity, then we grow the structure by 256 bytes. Then we continue
  4359. // adding the new type to array.
  4360. #define ADDTYPE(pointtype) if ((UINT)types.GetCount() >= types.GetCapacity()) { \
  4361. if (types.ReserveSpace(512) == Ok) \
  4362. { \
  4363. Types = (INT)(Types - MarkWallPtr) + types.GetDataBuffer(); \
  4364. GpMemset(Types, 0, types.GetCapacity() - types.GetCount()); \
  4365. MarkWallPtr = types.GetDataBuffer(); \
  4366. } else { \
  4367. return FALSE; \
  4368. } \
  4369. } \
  4370. types.AdjustCount(1); \
  4371. *Types++ |= pointtype;
  4372. DpRegion::GetOutlinePoints(DynPointArray& points,
  4373. DynByteArray& types) const
  4374. {
  4375. if (IsSimple())
  4376. {
  4377. GpRect rect;
  4378. GpPoint newPoints[4];
  4379. BYTE newTypes[4];
  4380. GetBounds(&rect);
  4381. newPoints[0] = GpPoint(rect.X, rect.Y);
  4382. newPoints[1] = GpPoint(rect.X + rect.Width, rect.Y);
  4383. newPoints[2] = GpPoint(rect.X + rect.Width, rect.Y + rect.Height);
  4384. newPoints[3] = GpPoint(rect.X, rect.Y + rect.Height);
  4385. newTypes[0] = PathPointTypeStart;
  4386. newTypes[1] = PathPointTypeLine;
  4387. newTypes[2] = PathPointTypeLine;
  4388. newTypes[3] = PathPointTypeLine | PathPointTypeCloseSubpath;
  4389. points.AddMultiple(&newPoints[0], 4);
  4390. types.AddMultiple(&newTypes[0], 4);
  4391. return TRUE;
  4392. }
  4393. // to avoid too many reallocations, we grow the array by the total number
  4394. // or x,y pairs in the reigon.
  4395. points.ReserveSpace(ComplexData->XCoordsCount+10);
  4396. types.ReserveSpace(ComplexData->XCoordsCount+10);
  4397. BYTE* MarkWallPtr = types.GetDataBuffer();
  4398. BYTE* Types = types.GetDataBuffer();
  4399. // Clear all bits in the Types array
  4400. GpMemset(MarkWallPtr, 0, types.GetCapacity());
  4401. // complicated case.
  4402. GpPoint pt[2];
  4403. INT NumYScans;
  4404. INT* CurYScan;
  4405. INT* XCoords;
  4406. INT* LastYScan;
  4407. INT* FirstYScan;
  4408. INT XOffset;
  4409. INT XIndex;
  4410. INT XCount;
  4411. // Now compute the outline:
  4412. CurYScan = ComplexData->YSpans;
  4413. NumYScans = ComplexData->NumYSpans;
  4414. XCoords = ComplexData->XCoords;
  4415. LastYScan = CurYScan + NumYScans * YSPAN_SIZE;
  4416. FirstYScan = CurYScan;
  4417. while (NumYScans--)
  4418. {
  4419. XCount = *(CurYScan + YSPAN_XCOUNT);
  4420. XOffset = *(CurYScan + YSPAN_XOFFSET);
  4421. for (XIndex = 0; XIndex < XCount; XIndex++)
  4422. {
  4423. // Only start at unvisited walls:
  4424. if ((MarkWallPtr[XOffset + XIndex] & MarkWallBit) == 0)
  4425. {
  4426. INT* YScan = CurYScan;
  4427. INT IndexWall = XIndex;
  4428. LONG Turn;
  4429. pt[0].X = XCoords[XOffset + XIndex];
  4430. pt[0].Y = *(CurYScan + YSPAN_YMIN);
  4431. points.Add(pt[0]);
  4432. ADDTYPE(PathPointTypeStart);
  4433. #ifdef DEBUG_REGION
  4434. DbgPrint("Point: (%d,%d)\n",pt[0].X, pt[0].Y);
  4435. #endif
  4436. INT* YSearch = CurYScan + YSPAN_SIZE;
  4437. BOOL Inside = (BOOL) (XIndex & 1);
  4438. // Mark that we've visited this wall:
  4439. MarkWallPtr[XOffset + IndexWall] |= MarkWallBit;
  4440. // Loop until the path closes on itself:
  4441. GoDown:
  4442. // YSPAN_YMAX is exclusive, YSPAN_YMIN is inclusive so
  4443. // vertically adjacent spans have YSPAN_YMIN==YSPAN_YMAX
  4444. Turn = +1;
  4445. while (
  4446. (YSearch >= CurYScan) &&
  4447. (YSearch < LastYScan) &&
  4448. (YScan[YSPAN_YMAX] == YSearch[YSPAN_YMIN])
  4449. )
  4450. {
  4451. INT Wall = XOFFSET(YScan, IndexWall);
  4452. INT IndexNewWall;
  4453. INT NewWall;
  4454. INT Left = Inside;
  4455. INT Right = XCOUNT(YSearch) - 1 - Inside;
  4456. // It would be nice if the first wall in the region structure
  4457. // was minus infinity, but it isn't, so we do this check:
  4458. if (XOFFSET(YSearch, Left) > Wall)
  4459. IndexNewWall = Left;
  4460. else
  4461. {
  4462. // Check if it's possible to find a wall with the
  4463. // minimum x-value > xWall:
  4464. if (XOFFSET(YSearch, Right) <= Wall)
  4465. break; // =====>
  4466. // Do a binary search to find it:
  4467. while (TRUE)
  4468. {
  4469. INT IndexSearch = (Left + Right) >> 1;
  4470. if (IndexSearch == Left)
  4471. break; // =====>
  4472. INT Search = XOFFSET(YSearch, IndexSearch);
  4473. if (Search > Wall)
  4474. Right = IndexSearch;
  4475. else
  4476. Left = IndexSearch;
  4477. }
  4478. IndexNewWall = Right;
  4479. }
  4480. if ((IndexNewWall & 1) != Inside)
  4481. {
  4482. // There is a region directly below xWall. We can't
  4483. // move down if its left side is < the left
  4484. // side of our space:
  4485. if (IndexWall > 0 &&
  4486. XOFFSET(YSearch, IndexNewWall - 1) <
  4487. XOFFSET(YScan, IndexWall - 1))
  4488. {
  4489. Turn = -1;
  4490. break; // =====>
  4491. }
  4492. IndexNewWall--;
  4493. }
  4494. else
  4495. {
  4496. // There is a space directly below xWall. We can't
  4497. // move down if its right side is more than the
  4498. // right side of our region:
  4499. if (XOFFSET(YSearch, IndexNewWall) >=
  4500. XOFFSET(YScan, IndexWall + 1))
  4501. break; // =====>
  4502. }
  4503. NewWall = XOFFSET(YSearch, IndexNewWall);
  4504. // Don't bother outputing multiple in-line straight lines:
  4505. if (Wall != NewWall ||
  4506. XOFFSET(YScan, IndexWall) != NewWall ||
  4507. XOFFSET(YSearch, IndexNewWall) != NewWall)
  4508. {
  4509. pt[0].X = Wall;
  4510. pt[0].Y = *(YScan + YSPAN_YMAX);
  4511. pt[1].Y = *(YScan + YSPAN_YMAX);
  4512. pt[1].X = NewWall;
  4513. points.Add(pt[0]);
  4514. points.Add(pt[1]);
  4515. ADDTYPE(PathPointTypeLine);
  4516. ADDTYPE(PathPointTypeLine);
  4517. #ifdef DEBUG_REGION
  4518. DbgPrint("Points: (%d,%d), (%d,%d)\n",
  4519. pt[0].X, pt[0].Y, pt[1].X, pt[1].Y);
  4520. #endif
  4521. }
  4522. YScan = YSearch;
  4523. IndexWall = IndexNewWall;
  4524. YSearch = YScan + YSPAN_SIZE;
  4525. MARKXOFFSET(YScan, IndexWall);
  4526. }
  4527. // Setup to go up other side:
  4528. pt[0].X = XOFFSET(YScan, IndexWall);
  4529. pt[0].Y = *(YScan + YSPAN_YMAX);
  4530. pt[1].Y = *(YScan + YSPAN_YMAX);
  4531. pt[1].X = XOFFSET(YScan, IndexWall + Turn);
  4532. points.Add(pt[0]);
  4533. points.Add(pt[1]);
  4534. ADDTYPE(PathPointTypeLine);
  4535. ADDTYPE(PathPointTypeLine);
  4536. #ifdef DEBUG_REGION
  4537. DbgPrint("Points: (%d,%d), (%d,%d)\n",
  4538. pt[0].X, pt[0].Y, pt[1].X, pt[1].Y);
  4539. #endif
  4540. YSearch = YScan - YSPAN_SIZE;
  4541. IndexWall += Turn;
  4542. MARKXOFFSET(YScan, IndexWall);
  4543. // Go up:
  4544. // YSPAN_YMAX is exclusive, YSPAN_YMIN is inclusive so
  4545. // vertically adjacent spans have YSPAN_YMIN==YSPAN_YMAX
  4546. Turn = -1;
  4547. while (
  4548. (YSearch >= CurYScan) &&
  4549. (YSearch < LastYScan) &&
  4550. (YScan[YSPAN_YMIN] == YSearch[YSPAN_YMAX])
  4551. )
  4552. {
  4553. INT Wall = XOFFSET(YScan, IndexWall);
  4554. INT IndexNewWall;
  4555. INT NewWall;
  4556. INT Left = Inside;
  4557. INT Right = XCOUNT(YSearch) - 1 - Inside;
  4558. // It would be nice if the last wall in the region structure
  4559. // was plus infinity, but it isn't, so we do this check:
  4560. if (XOFFSET(YSearch, Right) < Wall)
  4561. IndexNewWall = Right;
  4562. else
  4563. {
  4564. // Check if it's possible to find a wall with the
  4565. // maximum x-value < xWall:
  4566. if (XOFFSET(YSearch, Left) >= Wall)
  4567. break; // =====>
  4568. // Binary search to find it:
  4569. while (TRUE)
  4570. {
  4571. INT IndexSearch = (Left + Right) >> 1;
  4572. if (IndexSearch == Left)
  4573. break; // =====>
  4574. INT Search = XOFFSET(YSearch, IndexSearch);
  4575. if (Search >= Wall)
  4576. Right = IndexSearch;
  4577. else
  4578. Left = IndexSearch;
  4579. }
  4580. IndexNewWall = Left;
  4581. }
  4582. if ((IndexNewWall & 1) == Inside)
  4583. {
  4584. // There is a region directly above xWall. We can't
  4585. // move up if its right side is more than the right
  4586. // side of our space:
  4587. if ((IndexWall < (XCOUNT(YScan) - 1)) &&
  4588. (XOFFSET(YSearch, IndexNewWall + 1) >
  4589. XOFFSET(YScan, IndexWall + 1)) )
  4590. {
  4591. Turn = +1;
  4592. break; // =====>
  4593. }
  4594. IndexNewWall++;
  4595. }
  4596. else
  4597. {
  4598. // There is a space directly above xWall. We can't
  4599. // move up if its left side is <= the left side
  4600. // of our region:
  4601. if (XOFFSET(YSearch, IndexNewWall) <=
  4602. XOFFSET(YScan, IndexWall - 1))
  4603. break; // =====>
  4604. }
  4605. NewWall = XOFFSET(YSearch, IndexNewWall);
  4606. // Don't bother outputing multiple in-line straight lines:
  4607. if (Wall != NewWall ||
  4608. XOFFSET(YScan, IndexWall) != NewWall ||
  4609. XOFFSET(YSearch, IndexNewWall) != NewWall)
  4610. {
  4611. pt[0].X = Wall;
  4612. pt[0].Y = *(YScan + YSPAN_YMIN);
  4613. pt[1].Y = *(YScan + YSPAN_YMIN);
  4614. pt[1].X = NewWall;
  4615. points.Add(pt[0]);
  4616. points.Add(pt[1]);
  4617. ADDTYPE(PathPointTypeLine);
  4618. ADDTYPE(PathPointTypeLine);
  4619. #ifdef DEBUG_REGION
  4620. DbgPrint("Points: (%d,%d), (%d,%d)\n",
  4621. pt[0].X, pt[0].Y, pt[1].X, pt[1].Y);
  4622. #endif
  4623. }
  4624. YScan = YSearch;
  4625. IndexWall = IndexNewWall;
  4626. YSearch = YScan - YSPAN_SIZE;
  4627. MARKXOFFSET(YScan, IndexWall);
  4628. }
  4629. // Check if we've returned to where we started from:
  4630. if ((CurYScan != YScan) || (XIndex != IndexWall - 1))
  4631. {
  4632. // Setup to go down other side:
  4633. pt[0].X = XOFFSET(YScan, IndexWall);
  4634. pt[0].Y = *(YScan + YSPAN_YMIN);
  4635. pt[1].Y = *(YScan + YSPAN_YMIN);
  4636. pt[1].X = XOFFSET(YScan, IndexWall + Turn);
  4637. points.Add(pt[0]);
  4638. points.Add(pt[1]);
  4639. ADDTYPE(PathPointTypeLine);
  4640. ADDTYPE(PathPointTypeLine);
  4641. #ifdef DEBUG_REGION
  4642. DbgPrint("Points: (%d,%d), (%d,%d)\n",
  4643. pt[0].X, pt[0].Y, pt[1].X, pt[1].Y);
  4644. #endif
  4645. YSearch = YScan + YSPAN_SIZE;
  4646. IndexWall += Turn;
  4647. MARKXOFFSET(YScan, IndexWall);
  4648. goto GoDown; // =====>
  4649. }
  4650. // We're all done with this outline!
  4651. pt[0].X = XOFFSET(YScan, IndexWall);
  4652. pt[0].Y = *(YScan + YSPAN_YMIN);
  4653. points.Add(pt[0]);
  4654. ADDTYPE(PathPointTypeLine | PathPointTypeCloseSubpath);
  4655. #ifdef DEBUG_REGION
  4656. DbgPrint("Point: (%d,%d)\n", pt[0].X, pt[0].Y);
  4657. #endif
  4658. }
  4659. }
  4660. CurYScan = CurYScan + YSPAN_SIZE;
  4661. }
  4662. // we must untrash the region by removing our MarkWallBits
  4663. BYTE* TypesPtr = types.GetDataBuffer();
  4664. INT XCnt = ComplexData->XCoordsCount;
  4665. while (XCnt--)
  4666. {
  4667. *TypesPtr++ &= ~MarkWallBit;
  4668. }
  4669. return TRUE;
  4670. }