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.

5052 lines
152 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: rgnobj.cxx
  3. *
  4. * Non inline RGNOBJ methods
  5. *
  6. * Created: 02-Jul-1990 12:36:30
  7. * Author: Donald Sidoroff [donalds]
  8. *
  9. * Copyright (c) 1990-1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. // Region is expanded by this size when the size is too small.
  13. // Used by bAddScans().
  14. #define FILL_REGION_SIZE 10 * QUANTUM_REGION_SIZE
  15. extern RECTL rclEmpty;
  16. #if DBG
  17. RGNOBJ *gprgn = NULL;
  18. #define VALIDATE(ro) {gprgn = &ro; (ro).bValidateFramedRegion(); }
  19. #else
  20. #define VALIDATE(ro)
  21. #endif
  22. //
  23. // The following declarations are required by the native c8 compiler.
  24. //
  25. ULONG REGION::ulUniqueREGION;
  26. HRGN hrgnDefault;
  27. REGION *prgnDefault;
  28. /**************************************************************************\
  29. *
  30. \**************************************************************************/
  31. #if DBG
  32. #define MAXRGNLOG 1000
  33. extern "C"
  34. {
  35. int gMaxRgnLog = MAXRGNLOG;
  36. RGNLOGENTRY argnlog[MAXRGNLOG];
  37. LONG iLog = 0;
  38. LONG iPass = 0;
  39. };
  40. BOOL bDispRgn = 0;
  41. BOOL bLogRgn = 1;
  42. VOID vPrintRgn(RGNLOGENTRY& rl)
  43. {
  44. DbgPrint("%p,%p,(%8lx),%8lx,%8lx,%4lx, %s, %p, %p\n",
  45. rl.hrgn,rl.prgn,rl.lRes,rl.lParm1,rl.lParm2,rl.lParm3,
  46. rl.pszOperation,rl.pvCaller,rl.pvCallersCaller);
  47. }
  48. RGNLOG::RGNLOG(HRGN hrgn,PREGION prgn,PSZ psz,ULONG_PTR l1, ULONG_PTR l2, ULONG_PTR l3)
  49. {
  50. if (!bLogRgn)
  51. return;
  52. plog = &argnlog[iLog++];
  53. if (iLog >= MAXRGNLOG)
  54. {
  55. iLog = 0;
  56. ++iPass;
  57. }
  58. if (plog >= argnlog+MAXRGNLOG)
  59. plog = &argnlog[0];
  60. plog->hrgn = (HOBJ) hrgn;
  61. plog->prgn = prgn;
  62. plog->pszOperation = psz;
  63. plog->lRes = 0xff;
  64. plog->lParm1 = l1;
  65. plog->lParm2 = l2;
  66. plog->lParm3 = l3;
  67. plog->teb = (PVOID)W32GetCurrentThread();
  68. RtlGetCallersAddress(&plog->pvCaller,&plog->pvCallersCaller);
  69. if (bDispRgn)
  70. vPrintRgn(*plog);
  71. }
  72. RGNLOG::RGNLOG(PREGION prgn,PSZ psz,ULONG_PTR l1, ULONG_PTR l2, ULONG_PTR l3)
  73. {
  74. if (!bLogRgn)
  75. return;
  76. plog = &argnlog[iLog++];
  77. if (iLog >= MAXRGNLOG)
  78. {
  79. iLog = 0;
  80. ++iPass;
  81. }
  82. if (plog >= argnlog+MAXRGNLOG)
  83. plog = &argnlog[0];
  84. plog->hrgn = (HOBJ) 1;
  85. plog->prgn = prgn;
  86. plog->pszOperation = psz;
  87. plog->lRes = 0xff;
  88. plog->lParm1 = l1;
  89. plog->lParm2 = l2;
  90. plog->lParm3 = l3;
  91. plog->teb = (PVOID)W32GetCurrentThread();
  92. RtlGetCallersAddress(&plog->pvCaller,&plog->pvCallersCaller);
  93. if (bDispRgn)
  94. vPrintRgn(*plog);
  95. }
  96. #endif
  97. /******************************Public*Routine******************************\
  98. * RGNOBJ::vGetSubRect
  99. *
  100. * Return largest rectange completely within the region.
  101. *
  102. * History:
  103. * 09-Sep-1992 -by- Patrick Haluptzok patrickh
  104. * Wrote it.
  105. \**************************************************************************/
  106. VOID RGNOBJ::vGetSubRect(PRECTL prcl)
  107. {
  108. // We should try and do better here but this will solve 80% of our
  109. // performance goal. We should try and return the biggest rectangle
  110. // completely contained within the region that we can quickly compute.
  111. if (prgn->sizeRgn <= SINGLE_REGION_SIZE)
  112. {
  113. // Bounding rect == rect region
  114. *prcl = prgn->rcl;
  115. return;
  116. }
  117. *prcl = rclEmpty;
  118. }
  119. /******************************Public*Routine******************************\
  120. *
  121. *
  122. * History:
  123. * 05-Jul-1995 -by- Eric Kutter [erick]
  124. * Wrote it.
  125. \**************************************************************************/
  126. RGNOBJAPI::RGNOBJAPI(HRGN hrgn,BOOL bSelect)
  127. {
  128. prgn = (REGION *)HmgLock((HOBJ)hrgn, RGN_TYPE);
  129. RGNLOG rl(hrgn,prgn,"RGNOBJAPI::RGNOBJAPI");
  130. hrgn_ = hrgn;
  131. bSelect_ = bSelect;
  132. if (prgn != (PREGION)NULL)
  133. {
  134. BOOL bStatus = TRUE;
  135. //
  136. // Does this region have valid user-mode data? If there is
  137. // any problem with the user-mode state, then the contructor
  138. // must unlock the region set prgn to NULL.
  139. //
  140. PRGNATTR prRegion = (PRGNATTR)(PENTRY_FROM_POBJ(prgn)->pUser);
  141. if (prRegion != (PRGNATTR)NULL)
  142. {
  143. //
  144. // update a valid rgn, we can get an invalid
  145. // region here because gdi32!DeleteRegion must
  146. // clear the VALID flag before calling the
  147. // kernel.
  148. //
  149. if (
  150. (prRegion->AttrFlags & ATTR_RGN_VALID) &&
  151. !(prRegion->AttrFlags & ATTR_CACHED)
  152. )
  153. {
  154. if (prRegion->AttrFlags & ATTR_RGN_DIRTY)
  155. {
  156. if (prRegion->Flags == NULLREGION)
  157. {
  158. vSet();
  159. prRegion->AttrFlags &= ~ATTR_RGN_DIRTY;
  160. }
  161. else if (prRegion->Flags == SIMPLEREGION)
  162. {
  163. vSet(&prRegion->Rect);
  164. prRegion->AttrFlags &= ~ATTR_RGN_DIRTY;
  165. }
  166. }
  167. }
  168. else
  169. {
  170. bStatus = FALSE;
  171. }
  172. }
  173. if (!bStatus)
  174. {
  175. DEC_EXCLUSIVE_REF_CNT(prgn);
  176. prgn = NULL;
  177. hrgn_ = NULL;
  178. }
  179. }
  180. }
  181. /******************************Member*Function*****************************\
  182. *
  183. * History:
  184. * 22-Oct-1993 -by- Eric Kutter [erick]
  185. * Wrote it.
  186. \**************************************************************************/
  187. BOOL RGNOBJAPI::bDeleteHandle()
  188. {
  189. RGNLOG rl(hrgn_,prgn,"RGNOBJAPI::bDeleteHandle");
  190. ASSERTGDI(hrgn_ != (HRGN) NULL, "Delete NULL\n");
  191. if (hrgn_ == hrgnDefault)
  192. {
  193. rl.vRet(0);
  194. return(FALSE);
  195. }
  196. PREGION prgn1 = (PREGION)HmgRemoveObject((HOBJ) hrgn_, 1, 0, FALSE, RGN_TYPE);
  197. if (prgn1 != prgn)
  198. {
  199. rl.vRet(-1);
  200. #if DBG
  201. DbgPrint("couldn't delete api rgn - %p, prgn1 = %p\n",hrgn_,prgn1);
  202. DbgBreakPoint();
  203. #endif
  204. return(FALSE);
  205. }
  206. hrgn_ = NULL;
  207. rl.vRet(1);
  208. return(TRUE);
  209. }
  210. /******************************Member*Function*****************************\
  211. *
  212. * History:
  213. * 22-Oct-1993 -by- Eric Kutter [erick]
  214. * Wrote it.
  215. \**************************************************************************/
  216. BOOL RGNOBJAPI::bDeleteRGNOBJAPI()
  217. {
  218. RGNLOG rl(hrgn_,prgn,"RGNOBJAPI::bDelete");
  219. BOOL bRes = FALSE;
  220. POBJECTATTR pRgnattr = NULL;
  221. //
  222. // if this region has user-mode memory, try to place in cache
  223. //
  224. if (prgn)
  225. {
  226. PENTRY pEntry = PENTRY_FROM_POBJ(prgn);
  227. pRgnattr = (POBJECTATTR)pEntry->pUser;
  228. if (pRgnattr)
  229. {
  230. bRes = bPEBCacheHandle(prgn->hGet(),RegionHandle,pRgnattr,pEntry);
  231. }
  232. }
  233. if (!bRes)
  234. {
  235. bRes = bDeleteHandle() && bDeleteRGNOBJ();
  236. if (bRes && (pRgnattr != NULL))
  237. {
  238. HmgFreeObjectAttr((POBJECTATTR)pRgnattr);
  239. }
  240. }
  241. rl.vRet(bRes);
  242. return(bRes);
  243. }
  244. VOID RGNOBJ::vDeleteRGNOBJ()
  245. {
  246. //
  247. // Deletes the region and sets it to NULL.
  248. //
  249. RGNLOG rl(prgn,"RGNOBJ::vDeleteRGNOBJ");
  250. prgn->vDeleteREGION();
  251. prgn = NULL;
  252. }
  253. /******************************Member*Function*****************************\
  254. *
  255. * History:
  256. * 22-Oct-1993 -by- Eric Kutter [erick]
  257. * Wrote it.
  258. \**************************************************************************/
  259. //
  260. // This struct and the following union can be thrown away
  261. // when someone fixes the BASEOBJECT cExclusiveLock and BaseFlags sharing
  262. // the same DWORD.
  263. //
  264. struct SplitLockAndFlags {
  265. USHORT c_cExclusiveLock;
  266. USHORT c_BaseFlags;
  267. };
  268. union SplitOrCombinedLockAndFlags {
  269. SplitLockAndFlags S;
  270. ULONG W;
  271. };
  272. BOOL RGNOBJ::bSwap(RGNOBJ *pro)
  273. {
  274. RGNLOG rl(prgn,"RGNOBJ::bSwap",(ULONG_PTR)pro,(ULONG_PTR)pro->prgn);
  275. //
  276. // Swap the BASEOBJECT info at the start of the region.
  277. // Ensuring that when cExclusiveLock is swapped, the BaseFlags
  278. // is not swapped with it.
  279. // BaseFlags contains information about how the
  280. // object was allocated (and therefore, how it must be deallocated). Thus,
  281. // it represents state associated with the actual memory, not the object,
  282. // and should not be swapped.
  283. //
  284. // See comments regarding BASEOBJECT in inc\hmgshare.h for more details.
  285. // Also, there is swapping code in HmgSwapLockedHandleContents (hmgrapi.cxx).
  286. //
  287. BASEOBJECT *proB = (BASEOBJECT *)pro->prgnGet();
  288. BASEOBJECT obj = *proB;
  289. SplitOrCombinedLockAndFlags lfTmp;
  290. proB->hHmgr = prgn->hHmgr;
  291. lfTmp.S.c_cExclusiveLock = prgn->cExclusiveLock;
  292. lfTmp.S.c_BaseFlags = proB->BaseFlags;
  293. InterlockedExchange((LONG *) &(proB->cExclusiveLock), lfTmp.W);
  294. proB->Tid = prgn->Tid;
  295. prgn->hHmgr = obj.hHmgr;
  296. lfTmp.S.c_cExclusiveLock = obj.cExclusiveLock;
  297. lfTmp.S.c_BaseFlags = prgn->BaseFlags;
  298. InterlockedExchange((LONG *) &(prgn->cExclusiveLock), lfTmp.W);
  299. prgn->Tid = obj.Tid;
  300. // Swap the selection data.
  301. COUNT cRefsTemp = prgn->cRefs;
  302. prgn->cRefs = pro->prgn->cRefs;
  303. pro->prgn->cRefs = cRefsTemp;
  304. // swap the pointers in the objects
  305. PREGION prgnTmp = prgn;
  306. prgn = pro->prgnGet();
  307. pro->vSetRgn(prgnTmp);
  308. return(TRUE);
  309. }
  310. /******************************Member*Function*****************************\
  311. *
  312. * History:
  313. * 22-Oct-1993 -by- Eric Kutter [erick]
  314. * Wrote it.
  315. \**************************************************************************/
  316. BOOL RGNOBJAPI::bSwap(RGNOBJ *pro)
  317. {
  318. RGNLOG rl(hrgn_,prgn,"RGNOBJAPI::bSwap",(ULONG_PTR)pro,(ULONG_PTR)pro->prgn);
  319. ASSERTGDI(hrgn_ != NULL,"RGNOBJAPI::bSwap - hrgn is null\n");
  320. //
  321. // dunno if this is safe without grabbing the handle lock first
  322. //
  323. //
  324. // This increments the lock count so that between the HmgReplace and
  325. // the bSwap we're guaranteed a cExclusiveLock > 0 for both objects.
  326. //
  327. INC_EXCLUSIVE_REF_CNT(pro->prgnGet());
  328. INC_EXCLUSIVE_REF_CNT(prgn);
  329. // swap the pointer in the handle
  330. PREGION prgnRet = (PREGION)HmgReplace((HOBJ) hrgn_,(POBJ) pro->prgnGet(),0,1,RGN_TYPE);
  331. if (prgnRet != prgn)
  332. {
  333. rl.vRet((ULONG_PTR)prgnRet);
  334. RIP("RGNOBJ::bSwap - swapping invalid rgn\n");
  335. return(FALSE);
  336. }
  337. // swap the objects
  338. rl.vRet(1);
  339. BOOL retVal = RGNOBJ::bSwap(pro);
  340. //
  341. // Decrementing the cExclusiveLock for both objects in this way ensures
  342. // that after the swap the Lock status is restored for _both_ objects.
  343. //
  344. DEC_EXCLUSIVE_REF_CNT(pro->prgnGet());
  345. DEC_EXCLUSIVE_REF_CNT(prgn);
  346. return retVal;
  347. }
  348. /******************************Public*Routine******************************\
  349. * VOID RGNOBJ::vCopy()
  350. *
  351. * Copy region. There are some fields like the object size that don't need
  352. * copying. This deals with them appropriately
  353. *
  354. * History:
  355. * 22-Jul-1993 -by- Eric Kutter [erick]
  356. * reorged region structure so don't have to deal with individual
  357. * fields that may not need copying.
  358. *
  359. * 04-Jul-1990 -by- Donald Sidoroff [donalds]
  360. * Wrote it.
  361. \**************************************************************************/
  362. VOID RGNOBJ::vCopy(RGNOBJ& roSrc)
  363. {
  364. RGNLOG rl(prgn,"RGNOBJ::vCopy",(ULONG_PTR)roSrc.prgn);
  365. ASSERTGDI(prgn->sizeObj >= roSrc.prgn->sizeRgn, "sizeObj Src > sizeRgn Trg\n");
  366. RtlCopyMemory ((PBYTE) prgn + RGN_COPYOFFSET,
  367. (PBYTE) roSrc.prgn + RGN_COPYOFFSET,
  368. roSrc.prgn->sizeRgn - RGN_COPYOFFSET);
  369. // Get the difference and add it to the pscnTail pointer. This is faster
  370. // than running through the list to find it.
  371. prgn->pscnTail = (SCAN *) ((BYTE *) prgn->pscnHead() +
  372. (LONG) ((BYTE *) roSrc.prgn->pscnTail -
  373. (BYTE *) roSrc.prgn->pscnHead()));
  374. }
  375. /******************************Public*Routine******************************\
  376. * BOOL RGNOBJ::bCopy(roSrc)
  377. *
  378. * Copy region.
  379. *
  380. * NOTE: This is significantly different than vCopy. This routine will
  381. * create a new region if the source and target are of different
  382. * complexities.
  383. *
  384. * WARNING: the prgn may change. If this rgn is associated with a handle,
  385. * the handle's version will not have changed.
  386. *
  387. * History:
  388. * 04-Jul-1990 -by- Donald Sidoroff [donalds]
  389. * Wrote it.
  390. \**************************************************************************/
  391. BOOL RGNOBJ::bCopy(RGNOBJ& roSrc)
  392. {
  393. RGNLOG rl(prgn,"RGNOBJ::bCopy",(ULONG_PTR)roSrc.prgn);
  394. if (prgn->sizeObj <= QUANTUM_REGION_SIZE)
  395. {
  396. if (roSrc.prgn->sizeObj <= QUANTUM_REGION_SIZE)
  397. {
  398. rl.vRet(1);
  399. vCopy(roSrc);
  400. return(TRUE);
  401. }
  402. else
  403. {
  404. rl.vRet(2);
  405. RGNMEMOBJTMP rmo(roSrc.prgn->sizeRgn);
  406. if (!rmo.bValid())
  407. return(FALSE);
  408. rmo.vCopy(roSrc);
  409. return(bSwap(&rmo));
  410. }
  411. }
  412. if (roSrc.prgn->sizeObj <= QUANTUM_REGION_SIZE)
  413. {
  414. rl.vRet(3);
  415. RGNMEMOBJTMP rmo2;
  416. if (!rmo2.bValid())
  417. return(FALSE);
  418. rmo2.vCopy(roSrc);
  419. return(bSwap(&rmo2));
  420. }
  421. if (prgn->sizeObj >= roSrc.prgn->sizeRgn)
  422. {
  423. rl.vRet(4);
  424. vCopy(roSrc);
  425. return(TRUE);
  426. }
  427. RGNMEMOBJTMP rmo3(roSrc.prgn->sizeRgn);
  428. rl.vRet(5);
  429. if (!rmo3.bValid())
  430. return(FALSE);
  431. rmo3.vCopy(roSrc);
  432. return(bSwap(&rmo3));
  433. }
  434. /******************************Member*Function*****************************\
  435. * bCopy
  436. *
  437. * This should be used if you want any prgn change reflected in the handle.
  438. *
  439. * History:
  440. * 22-Oct-1993 -by- Eric Kutter [erick]
  441. * Wrote it.
  442. \**************************************************************************/
  443. BOOL RGNOBJAPI::bCopy(RGNOBJ& roSrc)
  444. {
  445. RGNLOG rl(hrgn_,prgn,"RGNOBJAPI::bCopy",(ULONG_PTR)roSrc.prgn);
  446. ASSERTGDI(hrgn_ != NULL,"RGNOBJAPI::bCopy\n");
  447. PREGION prgnOrg = prgn;
  448. // lock the handle so no one can reference it while the pobj may be invalid
  449. OBJLOCK ol((HOBJ) hrgn_);
  450. BOOL bRes = RGNOBJ::bCopy(roSrc);
  451. rl.vRet(0);
  452. if (bRes)
  453. {
  454. rl.vRet(1);
  455. if (prgn != prgnOrg)
  456. {
  457. rl.vRet((ULONG_PTR)prgn);
  458. PVOID pv = HmgReplace((HOBJ) hrgn_,(POBJ) prgn,0,1,OBJLOCK_TYPE);
  459. ASSERTGDI(pv != NULL,"RGNOBJAPI::bCopy - HmgReplace failed\n");
  460. }
  461. }
  462. return(bRes);
  463. }
  464. /******************************Public*Routine******************************\
  465. * BOOL RGNOBJ::bExpand(size)
  466. *
  467. * Expand the object to the given size
  468. *
  469. * History:
  470. * 10-Jul-1990 -by- Donald Sidoroff [donalds]
  471. * Wrote it.
  472. \**************************************************************************/
  473. BOOL RGNOBJ::bExpand(ULONGSIZE_T size)
  474. {
  475. RGNLOG rl(prgn,"RGNOBJ::bExpand",size);
  476. ASSERTGDI(size > prgn->sizeObj, "Expanded size <= original size\n");
  477. RGNMEMOBJTMP rmo(size);
  478. rl.vRet((ULONG_PTR)rmo.prgnGet());
  479. if (!rmo.bValid())
  480. {
  481. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  482. return(FALSE);
  483. }
  484. rmo.vCopy(*this);
  485. return(bSwap(&rmo));
  486. }
  487. /******************************Public*Routine******************************\
  488. * BOOL RGNOBJ::bInside(pptl)
  489. *
  490. * Is the point inside the region?
  491. *
  492. * Returns:
  493. * ERROR 0L
  494. * REGION_POINT_OUTSIDE 1L
  495. * REGION_POINT_INSIDE 2L
  496. *
  497. * History:
  498. * 02-Jul-1990 -by- Donald Sidoroff [donalds]
  499. * Wrote it.
  500. \**************************************************************************/
  501. BOOL RGNOBJ::bInside(PPOINTL pptl)
  502. {
  503. // First check if the point is in the bounding box
  504. if (!bBounded(pptl))
  505. return(REGION_POINT_OUTSIDE);
  506. BOOL b = REGION_POINT_OUTSIDE; // Assume point is outside
  507. PSCAN pscn;
  508. COUNT cScan;
  509. COUNT cWall;
  510. COUNT iWall;
  511. pscn = prgn->pscnHead(); // Get first scan
  512. cScan = prgn->cScans; // Get scan count
  513. while (cScan--)
  514. {
  515. if (pscn->yTop > pptl->y) // Have we passed the point?
  516. return(b); // Yes, exit.
  517. if (pscn->yBottom > pptl->y) // Does this scan overlap the point?
  518. { // Yes, test walls/lines.
  519. ASSERTGDI(!(pscn->cWalls & 1), "Invalid cWalls\n");
  520. iWall = 0;
  521. cWall = pscn->cWalls;
  522. while (iWall != cWall)
  523. if (xGet(pscn, (PTRDIFF)iWall++) > pptl->x)
  524. return(b);
  525. else
  526. b ^= (REGION_POINT_INSIDE | REGION_POINT_OUTSIDE);
  527. }
  528. pscn = pscnGet(pscn);
  529. ASSERTGDI( pscn <= prgn->pscnTail, "bInside:Went past end of region\n");
  530. }
  531. WARNING("********** RGNOBJ::bInside *****************\n");
  532. return(b);
  533. }
  534. /******************************Public*Routine******************************\
  535. * RGNOBJ::bInside (prcl) *
  536. * *
  537. * Does the rectangle intersect the region? *
  538. * *
  539. * Returns: *
  540. * ERROR 0L *
  541. * REGION_RECT_OUTSIDE 1L *
  542. * REGION_RECT_INTERSECT 2L *
  543. * *
  544. * History: *
  545. * Tue 12-May-1992 22:23:10 -by- Charles Whitmer [chuckwh] *
  546. * Rewrote the scan search. I want this zippy fast since I'm going to use *
  547. * it for pointer exclusion. *
  548. * *
  549. * 11-May-1991 -by- Kent Diamond [kentd] *
  550. * Rewrote. No more support for partial intersection. *
  551. * *
  552. * 02-Jul-1990 -by- Donald Sidoroff [donalds] *
  553. * Wrote it. *
  554. \**************************************************************************/
  555. BOOL RGNOBJ::bInside(PRECTL prcl)
  556. {
  557. // First check if the rectangle is outside the bounding box
  558. if ((prcl->left >= prgn->rcl.right) ||
  559. (prcl->right <= prgn->rcl.left) ||
  560. (prcl->top >= prgn->rcl.bottom) ||
  561. (prcl->bottom <= prgn->rcl.top))
  562. return(REGION_RECT_OUTSIDE);
  563. // Skip scans above the rectangle.
  564. PSCAN pscn = prgn->pscnHead();
  565. COUNT cScan = prgn->cScans;
  566. while (cScan && (prcl->top >= pscn->yBottom))
  567. {
  568. pscn = pscnGet(pscn);
  569. cScan--;
  570. }
  571. // Examine all interesting scans.
  572. INDEX_LONG *pix,*pixEnd;
  573. while (cScan && (prcl->bottom > pscn->yTop))
  574. {
  575. pix = pscn->ai_x;
  576. pixEnd = pix + 2 * pscn->cWalls;
  577. // Skip segments to the left.
  578. while ((pix < pixEnd) && (prcl->left >= pix[1].x))
  579. pix += 2;
  580. // It's this segment or nothing!
  581. if ((pix < pixEnd) && (prcl->right > pix[0].x))
  582. return(REGION_RECT_INTERSECT);
  583. // Move to the next scan.
  584. pscn = pscnGet(pscn);
  585. cScan--;
  586. }
  587. return(REGION_RECT_OUTSIDE); // Did not find an intersection
  588. }
  589. /******************************Public*Routine******************************\
  590. * RGNOBJ::bEqual(roSrc)
  591. *
  592. * Are the two regions equal?
  593. *
  594. * NOTE: The handle and sizeObj maybe different even though the regions
  595. * are the same, so these are skipped.
  596. *
  597. * Returns:
  598. * TRUE if they are equal.
  599. * FALSE if they are not.
  600. *
  601. * History:
  602. * 13-May-1991 -by- Donald Sidoroff [donalds]
  603. * Rewrote it.
  604. * 02-Jul-1990 -by- Donald Sidoroff [donalds]
  605. * Wrote it.
  606. \**************************************************************************/
  607. BOOL RGNOBJ::bEqual(RGNOBJ& roSrc)
  608. {
  609. // In the region header, only cScans need to be similar for
  610. // a region to equal another region
  611. // Now run thru the scans and determine if they are the same
  612. ASSERT4GB((LONGLONG)((BYTE *)prgn->pscnTail - (BYTE *)prgn->pscnHead()));
  613. return(
  614. (prgn->cScans == roSrc.prgn->cScans) &&
  615. (!memcmp(prgn->pscnHead(), roSrc.prgn->pscnHead(),
  616. (ULONG)((BYTE *)prgn->pscnTail - (BYTE *)prgn->pscnHead()))));
  617. }
  618. /******************************Public*Routine******************************\
  619. * BOOL RGNOBJ::bOffset(pptl)
  620. *
  621. * Offset the region by the point.
  622. *
  623. * Note:
  624. * Since the point is in DEVICE coords it will have to be converted to
  625. * FIX notation before it can be added to endpoints of trapezoid lines.
  626. *
  627. * History:
  628. * 02-Jul-1990 -by- Donald Sidoroff [donalds]
  629. * Wrote it.
  630. \**************************************************************************/
  631. BOOL RGNOBJ::bOffset(PPOINTL pptl)
  632. {
  633. COUNT cscn;
  634. COUNT cwll;
  635. PSCAN pscn;
  636. int x = (int)pptl->x;
  637. int y = (int)pptl->y;
  638. // Can't fail to offset a NULL region
  639. if (prgn->cScans == 1)
  640. return(TRUE);
  641. // First try to update the bounding box. If we are successful here then
  642. // all the other offsets will be successful. This eliminates the need
  643. // for checking for overflow/underflow on every offset operation.
  644. ERECTL ercl(prgn->rcl); // Get the current bounding box
  645. if (ercl.bWrapped())
  646. return(TRUE);
  647. ercl.left += x;
  648. ercl.bottom += y;
  649. ercl.right += x;
  650. ercl.top += y;
  651. if (!VALID_SCRRC(ercl))
  652. {
  653. // Foo, we over/under flowed.
  654. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  655. return(FALSE);
  656. }
  657. prgn->rcl = *((RECTL *)&ercl); // Set the current bounding box
  658. cscn = prgn->cScans; // Number of scans;
  659. pscn = prgn->pscnHead(); // First scan
  660. while (cscn--)
  661. {
  662. pscn->yTop += y;
  663. pscn->yBottom += y;
  664. cwll = pscn->cWalls;
  665. while (cwll)
  666. pscn->ai_x[--cwll].x += x;
  667. pscn = pscnGet(pscn); // Get next scan
  668. ASSERTGDI(pscn <= prgn->pscnTail, "bOffset:Went past end of region\n");
  669. }
  670. pscn = pscnGot(pscn); // Fix top ...
  671. pscn->yBottom = POS_INFINITY;
  672. pscn = prgn->pscnHead(); // ... and bottom.
  673. pscn->yTop = NEG_INFINITY;
  674. return(TRUE);
  675. }
  676. /******************************Public*Routine******************************\
  677. * VOID RGNOBJ::vSet()
  678. *
  679. * Set region to null region
  680. *
  681. * History:
  682. * 05-Jul-1990 -by- Donald Sidoroff [donalds]
  683. * Wrote it.
  684. \**************************************************************************/
  685. VOID RGNOBJ::vSet()
  686. {
  687. RGNLOG rl(prgn,"RGNOBJ::vSet");
  688. PREGION prgn1 = prgn;
  689. prgn1->sizeRgn = NULL_REGION_SIZE;
  690. prgn1->cScans = 1;
  691. prgn1->rcl.left = 0;
  692. prgn1->rcl.top = 0;
  693. prgn1->rcl.right = 0;
  694. prgn1->rcl.bottom = 0;
  695. PSCAN pscn = prgn1->pscnHead();
  696. pscn->cWalls = 0;
  697. pscn->yTop = NEG_INFINITY;
  698. pscn->yBottom = POS_INFINITY;
  699. pscn->ai_x[0].x = 0; // This sets cWalls2
  700. prgn1->pscnTail = pscnGet(pscn);
  701. }
  702. /******************************Public*Routine******************************\
  703. * VOID RGNOBJ::vSet()
  704. *
  705. * Set region from list of rectangles
  706. *
  707. * History:
  708. * 7-18-2000 bhouse Wrote it
  709. * Wrote it.
  710. \**************************************************************************/
  711. BOOL RGNOBJ::bSet(ULONG cRect, RECTL * prcl)
  712. {
  713. RGNMEMOBJTMP rmoTmp1, rmoTmp2;
  714. if (!rmoTmp1.bValid() || !rmoTmp2.bValid())
  715. {
  716. return(FALSE);
  717. }
  718. // NOTE: the iCombine call below is O(n*n) so
  719. // we want to only call it with small n. We use
  720. // merge sort which is O(n*log n) to handle larger n.
  721. //
  722. // The limit of 20 was picked as a reasonable number which
  723. // balances the cost of the RGNMEMOBJ creation
  724. // with the cost of the n squared algorithm.
  725. //
  726. if(cRect < 20)
  727. {
  728. BOOL bDoneFirst=FALSE;
  729. for (ULONG i=0; i < cRect; i++, prcl++)
  730. {
  731. // ignore bad rectangles
  732. if (!((prcl->left>=prcl->right) ||
  733. (prcl->top>=prcl->bottom) ||
  734. (prcl->left<MIN_REGION_COORD) ||
  735. (prcl->right>MAX_REGION_COORD)||
  736. (prcl->top<MIN_REGION_COORD) ||
  737. (prcl->bottom>MAX_REGION_COORD)))
  738. {
  739. if(!bDoneFirst)
  740. {
  741. // Do the first rectangle
  742. vSet(prcl);
  743. bDoneFirst=TRUE;
  744. }
  745. else
  746. {
  747. // Now get the rest of the rectangles, one by one
  748. rmoTmp1.vSet(prcl);
  749. rmoTmp2.iCombine(*this, rmoTmp1, RGN_OR); // put result of merge into rmoTmp2
  750. bSwap(&rmoTmp2); // now move into rmo
  751. }
  752. }
  753. }
  754. }
  755. else
  756. {
  757. RGNMEMOBJTMP rmoTmp3;
  758. ULONG cTmp1 = cRect >> 1;
  759. ULONG cTmp2 = cRect - cTmp1;
  760. if(!rmoTmp1.bSet(cTmp1, prcl) || !rmoTmp2.bSet(cTmp2, prcl+cTmp1))
  761. {
  762. return FALSE;
  763. }
  764. rmoTmp3.iCombine(rmoTmp2, rmoTmp1, RGN_OR);
  765. bSwap(&rmoTmp3);
  766. }
  767. return TRUE;
  768. }
  769. /******************************Public*Routine******************************\
  770. * VOID RGNOBJ::vSet(prcl)
  771. *
  772. * Set region to single rect
  773. *
  774. * History:
  775. * 09-Jul-1990 -by- Donald Sidoroff [donalds]
  776. * Wrote it.
  777. \**************************************************************************/
  778. VOID RGNOBJ::vSet(PRECTL prcl)
  779. {
  780. RGNLOG rl(prgn,"RGNOBJ::vSet prcl");
  781. PSCAN pscn;
  782. if ((prcl->left == prcl->right) || (prcl->top == prcl->bottom))
  783. {
  784. vSet();
  785. return;
  786. }
  787. // If the region is already a RECT region, this can be much faster
  788. PREGION prgn1 = prgn;
  789. prgn1->rcl = *prcl;
  790. if (prgn1->sizeRgn == SINGLE_REGION_SIZE)
  791. {
  792. rl.vRet(0);
  793. ASSERTGDI(prgn1->cScans == 3,"RGNOBJ::vSet - cScans != 3\n");
  794. // scan 0
  795. pscn = prgn1->pscnHead();
  796. ASSERTGDI(pscn->yTop == NEG_INFINITY,"RGNOBJ::vSet - yTop0\n");
  797. pscn->yBottom = prcl->top;
  798. // scan 1
  799. pscn = pscnGet(pscn);
  800. ASSERTGDI(pscn->cWalls == 2,"RGNOBJ::vSet - cWalls1 != 2\n");
  801. pscn->yTop = prcl->top;
  802. pscn->yBottom = prcl->bottom;
  803. pscn->ai_x[0].x = prcl->left;
  804. pscn->ai_x[1].x = prcl->right;
  805. // scan 2
  806. pscn = pscnGet(pscn);
  807. ASSERTGDI(pscn->cWalls == 0,"RGNOBJ::vSet - cWalls2 != 0\n");
  808. ASSERTGDI(pscn->yBottom == POS_INFINITY,"RGNOBJ::vSet - yBottom2\n");
  809. pscn->yTop = prcl->bottom;
  810. // tail
  811. prgn1->pscnTail = pscnGet(pscn);
  812. }
  813. else
  814. {
  815. rl.vRet(0);
  816. prgn1->sizeRgn = SINGLE_REGION_SIZE;
  817. prgn1->cScans = 3;
  818. pscn = prgn1->pscnHead();
  819. pscn->cWalls = 0;
  820. pscn->yTop = NEG_INFINITY;
  821. pscn->yBottom = prcl->top;
  822. pscn->ai_x[0].x = 0; // This sets cWalls2
  823. pscn = pscnGet(pscn);
  824. pscn->cWalls = 2;
  825. pscn->yTop = prcl->top;
  826. pscn->yBottom = prcl->bottom;
  827. pscn->ai_x[0].x = prcl->left;
  828. pscn->ai_x[1].x = prcl->right;
  829. pscn->ai_x[2].x = 2; // This sets cWalls2
  830. pscn = pscnGet(pscn);
  831. pscn->cWalls = 0;
  832. pscn->yTop = prcl->bottom;
  833. pscn->yBottom = POS_INFINITY;
  834. pscn->ai_x[0].x = 0; // This sets cWalls2
  835. prgn1->pscnTail = pscnGet(pscn);
  836. }
  837. VALIDATE(*(RGNOBJ *)this);
  838. }
  839. /******************************Public*Routine******************************\
  840. * VOID SCAN::vMerge(pscnSrcA, pscnSrcB, fj)
  841. *
  842. * Merge the scans.
  843. *
  844. * The algorithm takes advantage of the pre-sorted nature of the source
  845. * scans. We define the 'events' to be the merged sorted list of X values
  846. * from both A and B. The 'op' is referenced to determine if the event
  847. * is worth recording in the destination.
  848. *
  849. * There are a few tricks used in this routine. The first is the way that
  850. * the state is recorded. There are four states possible, since
  851. * we can either be IN or OUT of A or B. These states are:
  852. *
  853. * 0001b OUT A, OUT B
  854. * 0010b OUT A, IN B
  855. * 0100b IN A, OUT B
  856. * 1000b IN A, IN B
  857. *
  858. * From this we can see A is equal to 1100 (IN_A_OUT_B | IN_A_IN_B) and
  859. * that B is equal to 1010 (OUT_A_IN_B | IN_A_IN_B).
  860. *
  861. * We use a state table to find the next state. The index into the table
  862. * is the current state and the value we get out the new state.
  863. *
  864. * We always begin with an initial state OUT A, OUT B. We then take the
  865. * lowest X value from either A or B. We then map through the table of
  866. * which ever scan we pulled an X value from and so the state always
  867. * indicates whether we are in (entering) or out (leaving) of either scan.
  868. *
  869. * The second trick is in the similar way that the logical operation
  870. * to be used for the merge is encoded in the 'op'. This is done as a
  871. * simple logical truth table that can be tested against the state to
  872. * see if we are IN or OUT of the result. The frequently used ops are:
  873. *
  874. * 1110 OR
  875. * 1000 AND
  876. * 0110 XOR
  877. * 0100 DIFF
  878. *
  879. * These ops are seen to be the OR of the appropriate state definitions
  880. * needed for the boolean operation. For example the op for 'A OR B' is
  881. * derived from (1100 | 1010).
  882. *
  883. * In fact, any op whose lower bit is 0 is allowed. This gives eight
  884. * possible operations.
  885. *
  886. * The final trick we use to determine when an event worthy of recording
  887. * has occured. When we are not in a destination rectangle, we just
  888. * test the new state against the op to see if we've just changed to IN.
  889. * If so, we invert the op. Now we only need to test the state against
  890. * this inverted op to determine when we pop OUT again! So whenever we
  891. * record a point we invert the op.
  892. *
  893. * History:
  894. * 11-Nov-1992 -by- Donald Sidoroff [donalds]
  895. * Merged into RGNOBJ::bMerge for speed.
  896. *
  897. * 09-Jul-1990 -by- Donald Sidoroff [donalds]
  898. * Wrote it.
  899. \**************************************************************************/
  900. #define MERGE_OUT_OUT 0x01
  901. #define MERGE_OUT_IN 0x02
  902. #define MERGE_IN_OUT 0x04
  903. #define MERGE_IN_IN 0x08
  904. #define MERGE_INITIAL_STATE MERGE_OUT_OUT
  905. static FCHAR afjA[16] =
  906. {
  907. 0x00, //
  908. MERGE_IN_OUT, // OUT OUT -> IN OUT
  909. MERGE_IN_IN, // OUT IN -> IN IN
  910. 0x00, //
  911. MERGE_OUT_OUT, // IN OUT -> OUT OUT
  912. 0x00, //
  913. 0x00, //
  914. 0x00, //
  915. MERGE_OUT_IN // IN IN -> OUT IN
  916. };
  917. static FCHAR afjB[16] =
  918. {
  919. 0x00, //
  920. MERGE_OUT_IN, // OUT OUT -> OUT IN
  921. MERGE_OUT_OUT, // OUT IN -> OUT OUT
  922. 0x00, //
  923. MERGE_IN_IN, // IN OUT -> IN IN
  924. 0x00, //
  925. 0x00, //
  926. 0x00, //
  927. MERGE_IN_OUT // IN IN -> IN OUT
  928. };
  929. static FCHAR afjAB[16] =
  930. {
  931. 0x00, //
  932. MERGE_IN_IN, // OUT OUT -> IN IN
  933. MERGE_IN_OUT, // OUT IN -> IN OUT
  934. 0x00, //
  935. MERGE_OUT_IN, // IN OUT -> OUT IN
  936. 0x00, //
  937. 0x00, //
  938. 0x00, //
  939. MERGE_OUT_OUT // IN IN -> OUT OUT
  940. };
  941. /******************************Public*Routine******************************\
  942. * BOOL RGNOBJ::bMerge(proSrc1, proSrc2, fjOp)
  943. *
  944. * Merge two regions together.
  945. *
  946. * WARNING: If this function returns FALSE, the region may be inconsistent.
  947. * The caller must discard or reset the region. (See bug #343770)
  948. *
  949. * History:
  950. * 11-Nov-1992 -by- Donald Sidoroff [donalds]
  951. * Merged SCAN::vMerge into code for speed up. More aggressive memory
  952. * usage scheme and other optimizations.
  953. *
  954. * 09-Jul-1990 -by- Donald Sidoroff [donalds]
  955. * Wrote it.
  956. \**************************************************************************/
  957. BOOL RGNOBJ::bMerge(RGNOBJ& roSrc1,
  958. RGNOBJ& roSrc2,
  959. FCHAR fjOp)
  960. {
  961. RGNLOG rl(prgn,"RGNOBJ::bMerge",(ULONG_PTR)roSrc1.prgn,(ULONG_PTR)roSrc2.prgn,(ULONG_PTR)fjOp);
  962. SCAN *pscnSrc1 = roSrc1.prgn->pscnHead();
  963. SCAN *pscnSrc2 = roSrc2.prgn->pscnHead();
  964. SCAN *pscnOld = (SCAN *) NULL;
  965. SCAN *pscnTrg;
  966. LONG yTop;
  967. LONG yBottom;
  968. ULONG size;
  969. // Set target region to be TOTALLY empty, yet valid.
  970. prgn->pscnTail = prgn->pscnHead();
  971. prgn->sizeRgn = NULL_REGION_SIZE - NULL_SCAN_SIZE;
  972. prgn->cScans = 0;
  973. // Ensure the bounding box gets updated later on.
  974. prgn->rcl.left = POS_INFINITY;
  975. prgn->rcl.top = POS_INFINITY;
  976. prgn->rcl.right = NEG_INFINITY;
  977. prgn->rcl.bottom = NEG_INFINITY;
  978. // Merge the source scans into the target
  979. for(;;)
  980. {
  981. pscnTrg = prgn->pscnTail;
  982. // Check for nearly full region
  983. size = (pscnSrc1->cWalls + pscnSrc2->cWalls) * sizeof(INDEX_LONG) +
  984. NULL_SCAN_SIZE;
  985. if (size > prgn->sizeObj - prgn->sizeRgn)
  986. {
  987. // OK, we need to realloc this region. Lets be fairly aggressive
  988. // on the allocate to cut down on realloc's
  989. if (!bExpand(prgn->sizeRgn * 2 + (ULONGSIZE_T)size))
  990. return(FALSE);
  991. pscnTrg = prgn->pscnTail; // Get the updated object's tail.
  992. if (pscnOld) // If we had an old scan
  993. pscnOld = pscnGot(pscnTrg); // Get the updated old scan.
  994. }
  995. yTop = MAX(pscnSrc1->yTop, pscnSrc2->yTop);
  996. yBottom = MIN(pscnSrc1->yBottom, pscnSrc2->yBottom);
  997. ASSERTGDI(yBottom > yTop, "Bottom <= Top\n");
  998. // Merge the current scans
  999. pscnTrg->yBottom = yBottom;
  1000. pscnTrg->yTop = yTop;
  1001. {
  1002. register INDEX_LONG *plTrg = &pscnTrg->ai_x[0];
  1003. register INDEX_LONG *plSrc1 = &pscnSrc1->ai_x[0];
  1004. register INDEX_LONG *plSrc2 = &pscnSrc2->ai_x[0];
  1005. COUNT cSrc1 = pscnSrc1->cWalls;
  1006. COUNT cSrc2 = pscnSrc2->cWalls;
  1007. LONG xEvent;
  1008. FCHAR fjState = MERGE_INITIAL_STATE;
  1009. FCHAR fjOpTmp = fjOp;
  1010. pscnTrg->cWalls = 0; // Init the wall count to zero
  1011. // Continue to loop as long as either cSrc1 or cSrc2 (or both) are non-zero.
  1012. // We terminate the loop via a break statement because this causes the compiler
  1013. // to generate more efficient code (fewer branches). I believe this is a key loop
  1014. // that is worth optimizing at a minor cost to readability.
  1015. while (1)
  1016. {
  1017. if (cSrc1)
  1018. {
  1019. if (cSrc2)
  1020. {
  1021. // Both cSrc1 and cSrc2 are non-zero, so the next xEvent
  1022. // will come from whichever is smaller: *plSrc1 or *plSrc2
  1023. if (plSrc1->x < plSrc2->x)
  1024. {
  1025. xEvent = plSrc1->x, plSrc1++, cSrc1--, fjState = afjA[fjState];
  1026. }
  1027. else if (plSrc1->x > plSrc2->x)
  1028. {
  1029. xEvent = plSrc2->x, plSrc2++, cSrc2--, fjState = afjB[fjState];
  1030. }
  1031. else
  1032. {
  1033. // *plSrc1 and *plSrc2 are equal so advance both pointers
  1034. xEvent = plSrc1->x, plSrc1++, cSrc1--, plSrc2++, cSrc2--, fjState = afjAB[fjState];
  1035. }
  1036. }
  1037. else
  1038. {
  1039. // cSrc1 is non-zero, but cSrc2 is zero: the next xEvent is
  1040. // at *plSrc1
  1041. xEvent=plSrc1->x, plSrc1++, cSrc1--, fjState = afjA[fjState];
  1042. }
  1043. }
  1044. else
  1045. {
  1046. if (cSrc2)
  1047. {
  1048. // cSrc1 is zero and cSrc2 is non-zero: the next xEvent is
  1049. // at *plSrc2
  1050. xEvent = plSrc2->x, plSrc2++, cSrc2--, fjState = afjB[fjState];
  1051. }
  1052. else
  1053. {
  1054. // both cSrc1 and cSrc2 are zero. We are done with the loop.
  1055. break;
  1056. }
  1057. }
  1058. // We now have the next event and a new state
  1059. if (fjOpTmp & fjState)
  1060. pscnTrg->cWalls++, plTrg->x = xEvent, plTrg++, fjOpTmp ^= 0x0f;
  1061. }
  1062. pscnTrg->ai_x[pscnTrg->cWalls].x = pscnTrg->cWalls;
  1063. }
  1064. ASSERTGDI(!(pscnTrg->cWalls & 1), "Odd cWalls\n");
  1065. // Try to coalesce the current scan with the previous scan
  1066. if (pscnOld != (SCAN *) NULL)
  1067. {
  1068. // If the wall counts are the same, compare the walls
  1069. if (pscnOld->cWalls == pscnTrg->cWalls)
  1070. if (!memcmp(&pscnOld->ai_x[0], &pscnTrg->ai_x[0], (UINT)pscnOld->cWalls * sizeof(INDEX_LONG)))
  1071. {
  1072. pscnOld->yBottom = pscnTrg->yBottom;
  1073. pscnTrg = pscnOld;
  1074. }
  1075. }
  1076. // If the scans didn't coalesce, update size and count information
  1077. if (pscnOld != pscnTrg)
  1078. {
  1079. prgn->pscnTail = pscnGet(pscnTrg);
  1080. prgn->sizeRgn += pscnTrg->sizeGet();
  1081. prgn->cScans++;
  1082. }
  1083. // We might be done
  1084. if (pscnTrg->yBottom == POS_INFINITY)
  1085. {
  1086. ASSERTGDI((prgn->sizeRgn <= prgn->sizeObj),"bMerge: sizeRgn > sizeObj\n");
  1087. ASSERTGDI(prgn->sizeRgn == (SIZE_T)((BYTE *)prgn->pscnTail - (BYTE *)prgn),
  1088. "bMerge:sizeRgn != size of region\n");
  1089. return(TRUE);
  1090. }
  1091. // Maybe update the bounding rectangle
  1092. if (pscnTrg->cWalls)
  1093. {
  1094. if (pscnTrg->ai_x[0].x < prgn->rcl.left)
  1095. prgn->rcl.left = pscnTrg->ai_x[0].x;
  1096. if (pscnTrg->yTop < prgn->rcl.top)
  1097. prgn->rcl.top = pscnTrg->yTop;
  1098. if (pscnTrg->ai_x[pscnTrg->cWalls - 1].x > prgn->rcl.right)
  1099. prgn->rcl.right = pscnTrg->ai_x[pscnTrg->cWalls - 1].x;
  1100. if (pscnTrg->yBottom > prgn->rcl.bottom)
  1101. prgn->rcl.bottom = pscnTrg->yBottom;
  1102. }
  1103. // Decide which source pointers need to be advanced
  1104. if (yBottom == pscnSrc1->yBottom)
  1105. pscnSrc1 = pscnGet(pscnSrc1);
  1106. if (yBottom == pscnSrc2->yBottom)
  1107. pscnSrc2 = pscnGet(pscnSrc2);
  1108. // Set the pscnOld to the current scan
  1109. pscnOld = pscnTrg;
  1110. }
  1111. }
  1112. /******************************Public*Routine******************************\
  1113. * LONG RGNOBJ::iCombine(proSrc1, proSrc2, iMode)
  1114. *
  1115. * Combine the two regions by the mode and update the objects region.
  1116. * Return the complexity of the resulting region.
  1117. *
  1118. * History:
  1119. * 09-Jul-1990 -by- Donald Sidoroff [donalds]
  1120. * Wrote it.
  1121. \**************************************************************************/
  1122. FCHAR gafjRgnOp[] =
  1123. {
  1124. 0x00, //
  1125. 0x08, // RGN_AND
  1126. 0x0e, // RGN_OR
  1127. 0x06, // RGN_XOR
  1128. 0x04, // RGN_DIFF
  1129. };
  1130. LONG RGNOBJ::iCombine(RGNOBJ& roSrc1,
  1131. RGNOBJ& roSrc2,
  1132. LONG iMode)
  1133. {
  1134. RGNLOG rl(prgn,"RGNOBJ::iCombine",(ULONG_PTR)roSrc1.prgn,(ULONG_PTR)roSrc2.prgn,iMode);
  1135. // The target region MUST NOT be either of the source regions
  1136. ASSERTGDI(prgn != roSrc1.prgn, "Trg == Src1\n");
  1137. ASSERTGDI(prgn != roSrc2.prgn, "Trg == Src2\n");
  1138. // if this is the global empty one, we don't want to mess with it.
  1139. if (prgn == prgnDefault)
  1140. return(iComplexity());
  1141. // Check for the special case of merging one big single region with others.
  1142. if ((iMode == RGN_AND)||(iMode == RGN_OR))
  1143. {
  1144. if (roSrc1.bRectl())
  1145. {
  1146. // if roSrc2.prgn's bounding box is smaller or equal
  1147. if (roSrc1.bContain(roSrc2))
  1148. {
  1149. // The result will be identical to one region
  1150. if (!bCopy((iMode == RGN_AND) ? roSrc2 : roSrc1))
  1151. {
  1152. WARNING("Unable to copy region!!");
  1153. vSet();
  1154. return(ERROR);
  1155. }
  1156. rl.vRet((ULONG_PTR)prgn);
  1157. return(iComplexity());
  1158. }
  1159. }
  1160. if (roSrc2.bRectl())
  1161. {
  1162. // if roSrc1.prgn's bounding box is smaller or equal
  1163. if (roSrc2.bContain(roSrc1))
  1164. {
  1165. // The result will be identical to one region
  1166. if (!bCopy((iMode == RGN_AND) ? roSrc1 : roSrc2))
  1167. {
  1168. WARNING("Unable to copy region!!");
  1169. vSet();
  1170. rl.vRet((ULONG_PTR)prgn);
  1171. return(ERROR);
  1172. }
  1173. rl.vRet((ULONG_PTR)prgn);
  1174. return(iComplexity());
  1175. }
  1176. }
  1177. }
  1178. // Check for the special case of ANDing two single regions together.
  1179. if ((iMode == RGN_AND) &&
  1180. (roSrc1.prgn->sizeRgn == SINGLE_REGION_SIZE) &&
  1181. (roSrc2.prgn->sizeRgn == SINGLE_REGION_SIZE))
  1182. {
  1183. // Cool, all we have to do is AND the bounding boxes and we're done.
  1184. RECTL rclSrc1;
  1185. RECTL rclSrc2;
  1186. RECTL rclTrg;
  1187. rclSrc1 = roSrc1.prgn->rcl;
  1188. rclSrc2 = roSrc2.prgn->rcl;
  1189. rclTrg.left = MAX(rclSrc1.left, rclSrc2.left);
  1190. rclTrg.right = MIN(rclSrc1.right, rclSrc2.right);
  1191. rclTrg.top = MAX(rclSrc1.top, rclSrc2.top);
  1192. rclTrg.bottom = MIN(rclSrc1.bottom, rclSrc2.bottom);
  1193. // Was the resulting region NULL?
  1194. if ((rclTrg.left >= rclTrg.right) ||
  1195. (rclTrg.top >= rclTrg.bottom))
  1196. vSet(); // Make target NULL;
  1197. else
  1198. vSet(&rclTrg); // Make target a rect
  1199. rl.vRet((ULONG_PTR)prgn);
  1200. return(SIMPLEREGION); // Since we know what we get
  1201. }
  1202. // Do the general cases.
  1203. if (!bMerge(roSrc1, roSrc2, gafjRgnOp[iMode]))
  1204. {
  1205. vSet();
  1206. rl.vRet((ULONG_PTR)prgn);
  1207. return(ERROR);
  1208. }
  1209. rl.vRet((ULONG_PTR)prgn);
  1210. return(iComplexity());
  1211. }
  1212. /******************************Member*Function*****************************\
  1213. *
  1214. * History:
  1215. * 22-Oct-1993 -by- Eric Kutter [erick]
  1216. * Wrote it.
  1217. \**************************************************************************/
  1218. LONG RGNOBJAPI::iCombine(
  1219. RGNOBJ& roSrc1,
  1220. RGNOBJ& roSrc2,
  1221. LONG iMode)
  1222. {
  1223. RGNLOG rl(hrgn_,prgn,"RGNOBJAPI::iCombine",(ULONG_PTR)roSrc1.prgn,(ULONG_PTR)roSrc2.prgn,iMode);
  1224. PREGION prgnOrg = prgn;
  1225. // lock the handle so no one can reference it while the pobj may be invalid
  1226. OBJLOCK ol((HOBJ) hrgn_);
  1227. LONG iRet = RGNOBJ::iCombine(roSrc1,roSrc2,iMode);
  1228. if (prgn != prgnOrg)
  1229. {
  1230. rl.vRet((ULONG_PTR)prgn);
  1231. PVOID pv = HmgReplace((HOBJ) hrgn_,(POBJ) prgn,0,1,OBJLOCK_TYPE);
  1232. ASSERTGDI(pv != NULL,"RGNOBJAPI::iCombine - HmgReplace failed\n");
  1233. }
  1234. return(iRet);
  1235. }
  1236. /******************************Member*Function*****************************\
  1237. * RGNOBJ::iReduce()
  1238. *
  1239. * copy the roSrc into this reducing the size of the region if possible.
  1240. *
  1241. * History:
  1242. * 13-Aug-1992 -by- Eric Kutter [erick]
  1243. * Wrote it.
  1244. \**************************************************************************/
  1245. LONG RGNMEMOBJ::iReduce(RGNOBJ& roSrc)
  1246. {
  1247. RGNLOG rl(prgn,"RGNMEMOBJ::iReduce",(ULONG_PTR)roSrc.prgn);
  1248. RGNMEMOBJTMP rmoBigRect;
  1249. RECTL rcl;
  1250. rcl.left = MIN_REGION_COORD;
  1251. rcl.right = MAX_REGION_COORD;
  1252. rcl.top = MIN_REGION_COORD;
  1253. rcl.bottom = MAX_REGION_COORD;
  1254. rmoBigRect.vSet(&rcl);
  1255. // Set the bounding box to be maximally crossed (left > right, top > bottom)
  1256. prgn->rcl.left = POS_INFINITY;
  1257. prgn->rcl.top = POS_INFINITY;
  1258. prgn->rcl.right = NEG_INFINITY;
  1259. prgn->rcl.bottom = NEG_INFINITY;
  1260. if (!bMerge(rmoBigRect, roSrc, gafjRgnOp[RGN_AND]))
  1261. {
  1262. vSet();
  1263. rl.vRet((ULONG_PTR)prgn);
  1264. return(ERROR);
  1265. }
  1266. rl.vRet((ULONG_PTR)prgn);
  1267. return(iComplexity());
  1268. }
  1269. /******************************Public*Routine******************************\
  1270. * SIZE_T RGNOBJ::sizeSave()
  1271. *
  1272. * Compute the size of the save data for this region
  1273. *
  1274. * History:
  1275. * 26-Oct-1991 -by- Donald Sidoroff [donalds]
  1276. * Wrote it.
  1277. \**************************************************************************/
  1278. ULONGSIZE_T RGNOBJ::sizeSave()
  1279. {
  1280. COUNT cscn = prgn->cScans;
  1281. PSCAN pscn = prgn->pscnHead();
  1282. COUNT crcl = 0;
  1283. // The number of rectangles per scan is:
  1284. //
  1285. // For RECT regions -- (# of walls / 2)
  1286. // For TRAP regions -- (# of walls / 2) * (height of scan)
  1287. while (cscn--)
  1288. {
  1289. crcl += (pscn->cWalls / 2);
  1290. pscn = pscnGet(pscn);
  1291. ASSERTGDI(pscn <= prgn->pscnTail, "sizeSave:Went past end of region\n");
  1292. }
  1293. return(crcl * sizeof(RECTL));
  1294. }
  1295. /******************************Public*Routine******************************\
  1296. * VOID RGNOBJ::vDownload(pv)
  1297. *
  1298. * Download the region to the buffer
  1299. *
  1300. * History:
  1301. * 26-Oct-1991 -by- Donald Sidoroff [donalds]
  1302. * Wrote it.
  1303. \**************************************************************************/
  1304. VOID RGNOBJ::vDownload(PVOID pv)
  1305. {
  1306. PRECTL prcl = (PRECTL) pv;
  1307. PSCAN pscn = prgn->pscnHead();
  1308. COUNT cscn = prgn->cScans;
  1309. RECTL rclTmp;
  1310. LONG lPrevBottom = NEG_INFINITY;
  1311. LONG lPrevRight;
  1312. while (cscn--)
  1313. {
  1314. #if DBG
  1315. if (pscn->yTop < lPrevBottom)
  1316. DbgPrint("top < prev bottom, scan %ld, pscn @ 0x%lx\n",
  1317. prgn->cScans - cscn, (BYTE *)pscn - (BYTE *)prgn->pscnHead());
  1318. if (pscn->yTop > pscn->yBottom)
  1319. DbgPrint("top > bottom, scan %ld, pscn @ 0x%lx\n",
  1320. prgn->cScans - cscn, (BYTE *)pscn - (BYTE *)prgn->pscnHead());
  1321. #endif
  1322. lPrevBottom = pscn->yBottom;
  1323. rclTmp.top = pscn->yTop;
  1324. rclTmp.bottom = pscn->yBottom;
  1325. COUNT iWall = 0;
  1326. lPrevRight = NEG_INFINITY;
  1327. while (iWall < pscn->cWalls)
  1328. {
  1329. rclTmp.left = xGet(pscn, (PTRDIFF) iWall);
  1330. rclTmp.right = xGet(pscn, (PTRDIFF) iWall + 1);
  1331. #if DBG
  1332. if ((rclTmp.left <= lPrevRight) || (rclTmp.right <= rclTmp.left))
  1333. DbgPrint("left[i] < left[i+1], pscn @ 0x%lx, iWall = 0x%lx\n",
  1334. (BYTE *)pscn - (BYTE *)prgn->pscnHead(),iWall);
  1335. #endif
  1336. lPrevRight = rclTmp.right;
  1337. *prcl++ = rclTmp;
  1338. iWall += 2;
  1339. }
  1340. #if DBG
  1341. if (pscn->cWalls != (COUNT)xGet(pscn,(PTRDIFF)iWall))
  1342. DbgPrint("cWalls != cWalls2 @ 0x%lx\n",
  1343. (BYTE *)pscn - (BYTE *)prgn->pscnHead());
  1344. #endif
  1345. pscn = pscnGet(pscn);
  1346. #if DBG
  1347. if (pscn > prgn->pscnTail)
  1348. {
  1349. DbgPrint("vDownload1:Went past end of region\n");
  1350. return;
  1351. }
  1352. #endif
  1353. }
  1354. return;
  1355. }
  1356. /******************************Public*Routine******************************\
  1357. * VOID RGNOBJ::vComputeUncoveredSpriteRegion(po)
  1358. *
  1359. * Upload the region describing the parts of the screen not covered by
  1360. * sprites. Derived from 'bupload'.
  1361. *
  1362. * History:
  1363. * 28-Nov-1997 -by- J. Andrew Goossen [andrewgo]
  1364. * Wrote it.
  1365. \**************************************************************************/
  1366. VOID RGNOBJ::vComputeUncoveredSpriteRegion(PDEVOBJ& po)
  1367. {
  1368. SPRITESTATE* pState = po.pSpriteState();
  1369. PSCAN pscn = prgn->pscnHead();
  1370. LONG yTop;
  1371. LONG yBottom;
  1372. ULONG cScans;
  1373. ULONG cWalls;
  1374. RECTL rcl;
  1375. // First, reset to an empty region:
  1376. vSet();
  1377. // Find the first non-covered range:
  1378. ENUMUNCOVERED Enum(pState);
  1379. if (!Enum.bEnum(&rcl))
  1380. return; // Empty region
  1381. cScans = prgn->cScans;
  1382. // Setup variables for first scan:
  1383. yTop = NEG_INFINITY;
  1384. yBottom = rcl.top;
  1385. cWalls = 0;
  1386. do {
  1387. if (rcl.top != yTop)
  1388. {
  1389. cScans++;
  1390. // Close off current scan:
  1391. pscn->yTop = yTop;
  1392. pscn->yBottom = yBottom;
  1393. pscn->cWalls = cWalls;
  1394. pscn->ai_x[cWalls].x = cWalls;
  1395. // Add a null scan if the top of the new rectangle and
  1396. // the bottom of the old don't overlap:
  1397. if (rcl.top != yBottom)
  1398. {
  1399. cScans++;
  1400. pscn = pscnGet(pscn);
  1401. pscn->yTop = yBottom;
  1402. pscn->yBottom = rcl.top;
  1403. pscn->cWalls = 0;
  1404. pscn->ai_x[0].x = 0;
  1405. }
  1406. // Advance to the next scan:
  1407. pscn = pscnGet(pscn);
  1408. // Open up current scan:
  1409. yTop = rcl.top;
  1410. yBottom = rcl.bottom;
  1411. cWalls = 0;
  1412. }
  1413. pscn->ai_x[cWalls].x = rcl.left;
  1414. pscn->ai_x[cWalls + 1].x = rcl.right;
  1415. cWalls += 2;
  1416. } while (Enum.bEnum(&rcl));
  1417. // Close off current scan:
  1418. pscn->yTop = yTop;
  1419. pscn->yBottom = yBottom;
  1420. pscn->cWalls = cWalls;
  1421. pscn->ai_x[cWalls].x = cWalls;
  1422. // Build final scan:
  1423. cScans++;
  1424. pscn = pscnGet(pscn);
  1425. pscn->cWalls = 0;
  1426. pscn->yTop = yBottom;
  1427. pscn->yBottom = POS_INFINITY;
  1428. pscn->ai_x[0].x = 0;
  1429. prgn->pscnTail = pscnGet(pscn);
  1430. prgn->cScans = cScans;
  1431. prgn->sizeRgn = NULL_REGION_SIZE - NULL_SCAN_SIZE;
  1432. prgn->sizeRgn += (ULONGSIZE_T) (((BYTE *) prgn->pscnTail - (BYTE *) prgn->pscnHead()));
  1433. }
  1434. /******************************Public*Routine******************************\
  1435. *
  1436. * History:
  1437. * 24-Sep-1993 -by- Eric Kutter [erick]
  1438. * Wrote it.
  1439. \**************************************************************************/
  1440. RGNMEMOBJ::RGNMEMOBJ()
  1441. {
  1442. vInitialize(QUANTUM_REGION_SIZE);
  1443. }
  1444. /******************************Public*Routine******************************\
  1445. * RGNMEMOBJ::RGNMEMOBJ(size)
  1446. *
  1447. * Create a new region object
  1448. *
  1449. * History:
  1450. * 02-Jul-1990 -by- Donald Sidoroff [donalds]
  1451. * Wrote it.
  1452. \**************************************************************************/
  1453. RGNMEMOBJ::RGNMEMOBJ(ULONGSIZE_T size)
  1454. {
  1455. vInitialize(size);
  1456. }
  1457. /******************************Public*Routine******************************\
  1458. * RGNMEMOBJ::vInitialize(size)
  1459. *
  1460. * Create a new region object
  1461. *
  1462. * History:
  1463. * 02-Jul-1990 -by- Donald Sidoroff [donalds]
  1464. * Wrote it.
  1465. \**************************************************************************/
  1466. VOID
  1467. RGNMEMOBJ::vInitialize(ULONGSIZE_T size)
  1468. {
  1469. RGNLOG rl((PREGION)0,"RGNMEMOBJ::vInitialize(sz)",(ULONG_PTR)size);
  1470. // don't bother with anything smaller than a QUANTUM_REGION_SIZE
  1471. if (size < QUANTUM_REGION_SIZE)
  1472. size = QUANTUM_REGION_SIZE;
  1473. // Got to allocate a new one.
  1474. prgn = (PREGION)ALLOCOBJ(size,RGN_TYPE,FALSE);
  1475. rl.vRet((ULONG_PTR)prgn);
  1476. if (prgn)
  1477. {
  1478. vInit(size);
  1479. }
  1480. }
  1481. /******************************Public*Routine******************************\
  1482. * RGNMEMOBJ::RGNMEMOBJ(bInit)
  1483. *
  1484. * Create a new region object
  1485. *
  1486. * History:
  1487. * 02-Jul-1990 -by- Donald Sidoroff [donalds]
  1488. * Wrote it.
  1489. \**************************************************************************/
  1490. RGNMEMOBJ::RGNMEMOBJ(BOOL bInit)
  1491. {
  1492. RGNLOG rl((PREGION)0,"RGNMEMOBJ::RGNMEMOBJ(b)",(ULONG_PTR)bInit);
  1493. ASSERTGDI(bInit == FALSE,"RGNMEMOBJ::RGNMEMOBJ - bInit == TRUE\n");
  1494. prgn = (PREGION)ALLOCOBJ(QUANTUM_REGION_SIZE,RGN_TYPE,FALSE);
  1495. rl.vRet((ULONG_PTR)prgn);
  1496. if (prgn)
  1497. {
  1498. prgn->sizeObj = QUANTUM_REGION_SIZE;
  1499. prgn->sizeRgn = 0;
  1500. prgn->cRefs = 0;
  1501. prgn->iUnique = 0;
  1502. }
  1503. }
  1504. /******************************Public*Function*****************************\
  1505. * AddEdgeToGET
  1506. *
  1507. * Adds the edge described by the two passed-in points to the Global Edge
  1508. * Table, if the edge spans at least one pixel vertically.
  1509. *
  1510. * History:
  1511. * 09-Sep-1993 -by- Wendy Wu [wendywu]
  1512. * Stolen from DrvFillPath.
  1513. \**************************************************************************/
  1514. PEDGE AddEdgeToGET(EDGE *pGETHead, EDGE *pFreeEdge,
  1515. POINTFIX *ppfxEdgeStart, POINTFIX *ppfxEdgeEnd, RECTL *pBound)
  1516. {
  1517. LONG lyStart, lyEnd, lxStart, lxEnd, lyHeight, lxWidth,lyStartSave;
  1518. BOOL bTopClip;
  1519. // Set the winding-rule direction of the edge, and put the endpoints in
  1520. // top-to-bottom order
  1521. lyHeight = ppfxEdgeEnd->y - ppfxEdgeStart->y;
  1522. if (lyHeight >= 0)
  1523. {
  1524. lxStart = ppfxEdgeStart->x;
  1525. lyStart = ppfxEdgeStart->y;
  1526. lxEnd = ppfxEdgeEnd->x;
  1527. lyEnd = ppfxEdgeEnd->y;
  1528. pFreeEdge->lWindingDirection = 1;
  1529. }
  1530. else
  1531. {
  1532. lyHeight = -lyHeight;
  1533. lxEnd = ppfxEdgeStart->x;
  1534. lyEnd = ppfxEdgeStart->y;
  1535. lxStart = ppfxEdgeEnd->x;
  1536. lyStart = ppfxEdgeEnd->y;
  1537. pFreeEdge->lWindingDirection = -1;
  1538. }
  1539. bTopClip = FALSE;
  1540. if( pBound != NULL )
  1541. {
  1542. if( ( lyEnd < pBound->top ) || ( lyStart > pBound->bottom ) )
  1543. {
  1544. // completely above or below the bound rectangle so skip this segment
  1545. return(pFreeEdge);
  1546. }
  1547. if( lyStart < pBound->top )
  1548. {
  1549. // starts above the rect so clip to the top of the rect
  1550. bTopClip = TRUE;
  1551. lyStartSave = lyStart;
  1552. lyStart = pBound->top;
  1553. }
  1554. if( lyEnd > pBound->bottom )
  1555. {
  1556. // ends below the rect so clip to the bottom of the rect
  1557. lyEnd = pBound->bottom;
  1558. }
  1559. }
  1560. // First pixel scan line (non-fractional GIQ Y coordinate) edge intersects.
  1561. // Dividing by 16 with a shift is okay because Y is always positive
  1562. pFreeEdge->Y = (lyStart + 15) >> 4;
  1563. // Calculate the number of pixels spanned by this edge
  1564. pFreeEdge->lScansLeft = ((lyEnd + 15) >> 4) - pFreeEdge->Y;
  1565. if (pFreeEdge->lScansLeft <= 0)
  1566. return(pFreeEdge); // no pixels at all are spanned, so we can ignore
  1567. // this edge
  1568. // Set the error term and adjustment factors, all in GIQ coordinates for new.
  1569. lxWidth = lxEnd - lxStart;
  1570. if (lxWidth >= 0)
  1571. {
  1572. // Left to right, so we change X as soon as we move at all.
  1573. pFreeEdge->lXDirection = 1;
  1574. pFreeEdge->lErrorTerm = -1;
  1575. }
  1576. else
  1577. {
  1578. // Right to left, so we don't change X until we've moved a full GIQ
  1579. // coordinate.
  1580. lxWidth = -lxWidth;
  1581. pFreeEdge->lXDirection = -1;
  1582. pFreeEdge->lErrorTerm = -lyHeight;
  1583. }
  1584. if (lxWidth >= lyHeight)
  1585. {
  1586. // Calculate base run length (minimum distance advanced in X for a 1-
  1587. // scan advance in Y)
  1588. pFreeEdge->lXWhole = lxWidth / lyHeight;
  1589. // Add sign back into base run length if going right to left
  1590. if (pFreeEdge->lXDirection == -1)
  1591. pFreeEdge->lXWhole = -pFreeEdge->lXWhole;
  1592. pFreeEdge->lErrorAdjustUp = lxWidth % lyHeight;
  1593. }
  1594. else
  1595. {
  1596. // Base run length is 0, because line is closer to vertical than
  1597. // horizontal.
  1598. pFreeEdge->lXWhole = 0;
  1599. pFreeEdge->lErrorAdjustUp = lxWidth;
  1600. }
  1601. pFreeEdge->lErrorAdjustDown = lyHeight;
  1602. // If the edge doesn't start on a pixel scan (that is, it starts at a
  1603. // fractional GIQ coordinate), advance it to the first pixel scan it
  1604. // intersects or to the top of the clip rectangle if we are top clipped
  1605. LONG lyAdjust;
  1606. if( bTopClip )
  1607. {
  1608. lyAdjust = pBound->top;
  1609. lyStart = lyStartSave;
  1610. }
  1611. else
  1612. {
  1613. lyAdjust = ( lyStart + 15 ) & ~15;
  1614. }
  1615. while( lyStart != lyAdjust )
  1616. {
  1617. // Starts at a fractional GIQ coordinate, not exactly on a pixel scan
  1618. // Advance the edge's GIQ X coordinate for a 1-GIQ-pixel Y advance
  1619. // Advance by the minimum amount
  1620. lxStart += pFreeEdge->lXWhole;
  1621. // Advance the error term and see if we got one extra pixel this time.
  1622. pFreeEdge->lErrorTerm += pFreeEdge->lErrorAdjustUp;
  1623. if (pFreeEdge->lErrorTerm >= 0)
  1624. {
  1625. // The error term turned over, so adjust the error term and
  1626. // advance the extra pixel.
  1627. pFreeEdge->lErrorTerm -= pFreeEdge->lErrorAdjustDown;
  1628. lxStart += pFreeEdge->lXDirection;
  1629. }
  1630. lyStart++; // advance to the next GIQ Y coordinate
  1631. }
  1632. // Turn the calculations into pixel rather than GIQ calculations
  1633. // Move the X coordinate to the nearest pixel, and adjust the error term
  1634. // accordingly
  1635. // Dividing by 16 with a shift is okay because X is always positive
  1636. pFreeEdge->X = (lxStart + 15) >> 4; // convert from GIQ to pixel coordinates
  1637. if (pFreeEdge->lXDirection == 1)
  1638. {
  1639. // Left to right
  1640. pFreeEdge->lErrorTerm -= pFreeEdge->lErrorAdjustDown *
  1641. (((lxStart + 15) & ~0x0F) - lxStart);
  1642. }
  1643. else
  1644. {
  1645. // Right to left
  1646. pFreeEdge->lErrorTerm -= pFreeEdge->lErrorAdjustDown *
  1647. ((lxStart - 1) & 0x0F);
  1648. }
  1649. // Scale the error adjusts up by 16 times, to move 16 GIQ pixels at a time.
  1650. // Shifts work to do the multiplying because these values are always
  1651. // non-negative
  1652. pFreeEdge->lErrorAdjustUp <<= 4;
  1653. pFreeEdge->lErrorAdjustDown <<= 4;
  1654. // Insert the edge into the GET in YX-sorted order. The search always ends
  1655. // because the GET has a sentinel with a greater-than-possible Y value
  1656. while ((pFreeEdge->Y > ((EDGE *)pGETHead->pNext)->Y) ||
  1657. ((pFreeEdge->Y == ((EDGE *)pGETHead->pNext)->Y) &&
  1658. (pFreeEdge->X > ((EDGE *)pGETHead->pNext)->X)))
  1659. {
  1660. pGETHead = pGETHead->pNext;
  1661. }
  1662. pFreeEdge->pNext = pGETHead->pNext; // link the edge into the GET
  1663. pGETHead->pNext = pFreeEdge;
  1664. return(++pFreeEdge); // point to the next edge storage location for next
  1665. // time
  1666. }
  1667. /******************************Public*Function*****************************\
  1668. * vConstructGET
  1669. *
  1670. * Build the Global Edge Table from the path. The GET is constructed in
  1671. * Y-X order, and has a head/tail/sentinel node at pGETHead.
  1672. *
  1673. * History:
  1674. * 09-Sep-1993 -by- Wendy Wu [wendywu]
  1675. * Stolen from DrvFillPath.
  1676. \**************************************************************************/
  1677. VOID vConstructGET(EPATHOBJ& po, EDGE *pGETHead, EDGE *pFreeEdges,RECTL *pBound)
  1678. {
  1679. // Create an empty GET with the head node also a tail sentinel
  1680. pGETHead->pNext = pGETHead; // mark that the GET is empty
  1681. pGETHead->Y = 0x7FFFFFFF; // this is greater than any valid Y value, so
  1682. // searches will always terminate
  1683. PPATH ppath = po.ppath;
  1684. PPOINTFIX pptfxStart, pptfxEnd, pptfx;
  1685. PPOINTFIX pptfxPrev = NULL;
  1686. for (PATHRECORD *ppr = ppath->pprfirst;
  1687. ppr != (PPATHREC) NULL;
  1688. ppr = ppr->pprnext)
  1689. {
  1690. // If first point starts a subpath, remember it as such
  1691. // and go on to the next point, so we can get an edge.
  1692. pptfx = ppr->aptfx;
  1693. if (ppr->flags & PD_BEGINSUBPATH)
  1694. {
  1695. pptfxStart = ppr->aptfx; // the subpath starts here
  1696. pptfxPrev = ppr->aptfx; // this points starts next edge
  1697. pptfx++; // advance to the next point
  1698. }
  1699. // Add edges in PATH to GET, in Y-X sorted order.
  1700. pptfxEnd = ppr->aptfx + ppr->count;
  1701. while (pptfx < pptfxEnd)
  1702. {
  1703. ASSERTGDI(pptfxPrev != NULL, "No path record with PD_BEGINSUBPATH");
  1704. pFreeEdges =
  1705. AddEdgeToGET(pGETHead, pFreeEdges,pptfxPrev,pptfx,pBound);
  1706. pptfxPrev = pptfx;
  1707. pptfx++; // advance to the next point
  1708. }
  1709. // If last point ends the subpath, insert the edge that
  1710. // connects to first point.
  1711. if (ppr->flags & PD_ENDSUBPATH)
  1712. {
  1713. pFreeEdges =
  1714. AddEdgeToGET(pGETHead, pFreeEdges,pptfxPrev, pptfxStart,pBound);
  1715. pptfxPrev = NULL;
  1716. }
  1717. }
  1718. }
  1719. /******************************Public*Function*****************************\
  1720. * vAdvanceAETEdges
  1721. *
  1722. * Advance the edges in the AET to the next scan, dropping any for which we've
  1723. * done all scans. Assumes there is at least one edge in the AET.
  1724. *
  1725. * History:
  1726. * 09-Sep-1993 -by- Wendy Wu [wendywu]
  1727. * Stolen from DrvFillPath.
  1728. \**************************************************************************/
  1729. VOID vAdvanceAETEdges(EDGE *pAETHead)
  1730. {
  1731. EDGE *pLastEdge, *pCurrentEdge;
  1732. COUNT c = pAETHead->Y; // Y is used as edge count in AET
  1733. pLastEdge = pAETHead;
  1734. pCurrentEdge = pLastEdge->pNext;
  1735. do
  1736. {
  1737. // Count down this edge's remaining scans
  1738. if (--pCurrentEdge->lScansLeft == 0)
  1739. {
  1740. // We've done all scans for this edge; drop this edge from the AET
  1741. pLastEdge->pNext = pCurrentEdge->pNext;
  1742. c--;
  1743. }
  1744. else
  1745. {
  1746. // Advance the edge's X coordinate for a 1-scan Y advance
  1747. // Advance by the minimum amount
  1748. pCurrentEdge->X += pCurrentEdge->lXWhole;
  1749. // Advance the error term and see if we got one extra pixel this time.
  1750. pCurrentEdge->lErrorTerm += pCurrentEdge->lErrorAdjustUp;
  1751. if (pCurrentEdge->lErrorTerm >= 0)
  1752. {
  1753. // The error term turned over, so adjust the error term and
  1754. // advance the extra pixel.
  1755. pCurrentEdge->lErrorTerm -= pCurrentEdge->lErrorAdjustDown;
  1756. pCurrentEdge->X += pCurrentEdge->lXDirection;
  1757. }
  1758. pLastEdge = pCurrentEdge;
  1759. }
  1760. } while ((pCurrentEdge = pLastEdge->pNext) != pAETHead);
  1761. pAETHead->Y = c; // Y is used as edge count in AET
  1762. }
  1763. /******************************Public*Function*****************************\
  1764. * vXSortAETEdges
  1765. *
  1766. * X-sort the AET, because the edges may have moved around relative to
  1767. * one another when we advanced them. We'll use a multipass bubble
  1768. * sort, which is actually okay for this application because edges
  1769. * rarely move relative to one another, so we usually do just one pass.
  1770. * Also, this makes it easy to keep just a singly-linked list. Assumes there
  1771. * are at least two edges in the AET.
  1772. *
  1773. * History:
  1774. * 09-Sep-1993 -by- Wendy Wu [wendywu]
  1775. * Stolen from DrvFillPath.
  1776. \**************************************************************************/
  1777. VOID vXSortAETEdges(EDGE *pAETHead)
  1778. {
  1779. BOOL bEdgesSwapped;
  1780. EDGE *pLastEdge, *pCurrentEdge, *pNextEdge;
  1781. do
  1782. {
  1783. bEdgesSwapped = FALSE;
  1784. pLastEdge = pAETHead;
  1785. pCurrentEdge = pLastEdge->pNext;
  1786. pNextEdge = pCurrentEdge->pNext;
  1787. do {
  1788. if (pNextEdge->X < pCurrentEdge->X)
  1789. {
  1790. // Next edge is to the left of the current edge; swap them.
  1791. pLastEdge->pNext = pNextEdge;
  1792. pCurrentEdge->pNext = pNextEdge->pNext;
  1793. pNextEdge->pNext = pCurrentEdge;
  1794. bEdgesSwapped = TRUE;
  1795. pCurrentEdge = pNextEdge; // continue sorting before the edge
  1796. // we just swapped; it might move
  1797. // farther yet
  1798. }
  1799. pLastEdge = pCurrentEdge;
  1800. pCurrentEdge = pLastEdge->pNext;
  1801. } while ((pNextEdge = pCurrentEdge->pNext) != pAETHead);
  1802. } while (bEdgesSwapped);
  1803. }
  1804. /******************************Public*Function*****************************\
  1805. * vMoveNewEdges
  1806. *
  1807. * Moves all edges that start on the current scan from the GET to the AET in
  1808. * X-sorted order. Parameters are pointer to head of GET and pointer to dummy
  1809. * edge at head of AET, plus current scan line. Assumes there's at least one
  1810. * edge to be moved.
  1811. *
  1812. * History:
  1813. * 09-Sep-1993 -by- Wendy Wu [wendywu]
  1814. * Stolen from DrvFillPath.
  1815. \**************************************************************************/
  1816. VOID vMoveNewEdges(EDGE *pGETHead, EDGE *pAETHead, LONG lyCurrent)
  1817. {
  1818. EDGE *pCurrentEdge = pAETHead;
  1819. EDGE *pGETNext = pGETHead->pNext;
  1820. COUNT c = pAETHead->Y; // Y is used as edge count in AET
  1821. do
  1822. {
  1823. // Scan through the AET until the X-sorted insertion point for this
  1824. // edge is found. We can continue from where the last search left
  1825. // off because the edges in the GET are in X sorted order, as is
  1826. // the AET. The search always terminates because the AET sentinel
  1827. // is greater than any valid X
  1828. while (pGETNext->X > ((EDGE *)pCurrentEdge->pNext)->X)
  1829. pCurrentEdge = pCurrentEdge->pNext;
  1830. // We've found the insertion point; add the GET edge to the AET, and
  1831. // remove it from the GET.
  1832. pGETHead->pNext = pGETNext->pNext;
  1833. pGETNext->pNext = pCurrentEdge->pNext;
  1834. pCurrentEdge->pNext = pGETNext;
  1835. pCurrentEdge = pGETNext; // continue insertion search for the next
  1836. // GET edge after the edge we just added
  1837. pGETNext = pGETHead->pNext;
  1838. c++;
  1839. } while (pGETNext->Y == lyCurrent);
  1840. pAETHead->Y = c; // Y is used as edge count in AET
  1841. }
  1842. /******************************Member*Function*****************************\
  1843. * BOOL RGNOBJ::bAddScans
  1844. *
  1845. * Add a new scan into the region.
  1846. *
  1847. * History:
  1848. * 16-Sep-1993 -by- Wendy Wu [wendywu]
  1849. * Wrote it.
  1850. \**************************************************************************/
  1851. BOOL RGNMEMOBJ::bAddScans(LONG yTop, PEDGE pAETHead, FLONG flOptions)
  1852. {
  1853. ULONGSIZE_T cWalls = (ULONGSIZE_T)pAETHead->Y; // Y is used as edge count in AET
  1854. ULONGSIZE_T size = cWalls * sizeof(INDEX_LONG) + NULL_SCAN_SIZE;
  1855. // Check for nearly full region
  1856. if (size > prgn->sizeObj - prgn->sizeRgn)
  1857. {
  1858. // There isn't enough space for this scan, lets try to realloc this region.
  1859. // We want to expand to a big enough size to avoid reallocation in the near
  1860. // future.
  1861. if (!bExpand(prgn->sizeObj + size + FILL_REGION_SIZE))
  1862. return(FALSE);
  1863. }
  1864. PSCAN pscn = (SCAN *) prgn->pscnTail; // points pass last scan
  1865. ASSERTGDI(yTop == pscnGot(pscn)->yBottom, "bAddNullScan: bad yTop\n");
  1866. PEDGE pCurrentEdge = pAETHead->pNext; // point to the first edge
  1867. // yBottom is the dword before ai_x[0] in the SCAN structure.
  1868. // Stuff NEG_INFINITY there so the first wall is bigger than
  1869. // the "previous" wall. yBottom will be initialized later on.
  1870. PLONG pWallStart = (LONG *)&pscn->yBottom;
  1871. PLONG pWall = pWallStart;
  1872. *pWall = NEG_INFINITY;
  1873. if (flOptions & WINDING)
  1874. {
  1875. // Do winding fill; scan across until we've found equal numbers
  1876. // of up and down edges.
  1877. while (pCurrentEdge != pAETHead)
  1878. {
  1879. if (*pWall < pCurrentEdge->X)
  1880. {
  1881. pWall++;
  1882. *pWall = pCurrentEdge->X;
  1883. }
  1884. else
  1885. pWall--;
  1886. LONG lWindingCount = pCurrentEdge->lWindingDirection;
  1887. do
  1888. {
  1889. pCurrentEdge = pCurrentEdge->pNext;
  1890. lWindingCount += pCurrentEdge->lWindingDirection;
  1891. } while (lWindingCount != 0);
  1892. if (*pWall < pCurrentEdge->X)
  1893. {
  1894. pWall++;
  1895. *pWall = pCurrentEdge->X;
  1896. }
  1897. else
  1898. pWall--;
  1899. pCurrentEdge = pCurrentEdge->pNext;
  1900. }
  1901. }
  1902. else
  1903. {
  1904. while (pCurrentEdge != pAETHead)
  1905. {
  1906. if (*pWall < pCurrentEdge->X)
  1907. {
  1908. pWall++;
  1909. *pWall = pCurrentEdge->X;
  1910. }
  1911. else
  1912. pWall--;
  1913. pCurrentEdge = pCurrentEdge->pNext;
  1914. }
  1915. }
  1916. ASSERT4GB ((LONGLONG)(((BYTE *)pWall - (BYTE *)pWallStart) / sizeof(LONG)));
  1917. cWalls = (ULONGSIZE_T)(((BYTE *)pWall - (BYTE *)pWallStart) / sizeof(LONG));
  1918. PSCAN pscnPrev = pscnGot(pscn);
  1919. if ((pscnPrev->cWalls == cWalls) &&
  1920. !memcmp(pscnPrev->ai_x, pscn->ai_x,cWalls * sizeof(LONG)))
  1921. {
  1922. pscnPrev->yBottom = yTop+1;
  1923. }
  1924. else
  1925. {
  1926. prgn->cScans += 1;
  1927. prgn->sizeRgn += (ULONGSIZE_T)(NULL_SCAN_SIZE + sizeof(INDEX_LONG) * cWalls);
  1928. ASSERTGDI(prgn->sizeRgn <= prgn->sizeObj, "bAddScans: sizeRgn > sizeObj\n");
  1929. ASSERTGDI((cWalls & 1) == 0,"bAddScan error: cWalls odd number\n");
  1930. pscn->yTop = yTop;
  1931. pscn->yBottom = yTop+1;
  1932. pscn->cWalls = cWalls;
  1933. pscn->ai_x[cWalls].x = cWalls; // This sets cWalls2
  1934. prgn->pscnTail = pscnGet(pscn);
  1935. }
  1936. return(TRUE);
  1937. }
  1938. /******************************Member*Function*****************************\
  1939. * BOOL RGNOBJ::bAddNullScan
  1940. *
  1941. * Add a null scan into the region.
  1942. *
  1943. * History:
  1944. * 16-Sep-1993 -by- Wendy Wu [wendywu]
  1945. * Wrote it.
  1946. \**************************************************************************/
  1947. BOOL RGNMEMOBJ::bAddNullScan(LONG yTop, LONG yBottom)
  1948. {
  1949. // Check for nearly full region
  1950. if (NULL_SCAN_SIZE > prgn->sizeObj - prgn->sizeRgn)
  1951. {
  1952. // There isn't enough space for this scan, lets try to realloc this region.
  1953. // We want to expand to a big enough size to avoid reallocation in the near
  1954. // future.
  1955. if (!bExpand(prgn->sizeObj + NULL_SCAN_SIZE + FILL_REGION_SIZE))
  1956. return(FALSE);
  1957. }
  1958. PSCAN pscn = (SCAN *) prgn->pscnTail; // points pass last scan
  1959. ASSERTGDI(prgn->cScans == 0 || yTop == pscnGot(pscn)->yBottom,
  1960. "bAddNullScan: bad yTop\n");
  1961. prgn->cScans += 1;
  1962. pscn->yTop = yTop;
  1963. pscn->yBottom = yBottom;
  1964. prgn->sizeRgn += (ULONGSIZE_T)NULL_SCAN_SIZE;
  1965. ASSERTGDI(prgn->sizeRgn <= prgn->sizeObj, "bAddNullScan: sizeRgn > sizeObj\n");
  1966. pscn->cWalls = pscn->ai_x[0].x = 0;
  1967. prgn->pscnTail = pscnGet(pscn);
  1968. return(TRUE);
  1969. }
  1970. /******************************Member*Function*****************************\
  1971. * VOID RGNMEMOBJ::vCreate(po, fl)
  1972. *
  1973. * Routine for constructing a region from a path.
  1974. *
  1975. * History:
  1976. * 16-Sep-1993 -by- Wendy Wu [wendywu]
  1977. * Removed trapazoidal regions.
  1978. * 04-Apr-1991 -by- Wendy Wu [wendywu]
  1979. * Wrote it.
  1980. \**************************************************************************/
  1981. VOID RGNMEMOBJ::vCreate(
  1982. EPATHOBJ& po,
  1983. FLONG flOptions, // ALTERNATE or WINDING
  1984. RECTL *pBound
  1985. )
  1986. {
  1987. GDIFunctionID(RGNMEMOBJ::vCreate);
  1988. RGNLOG rl((PREGION)NULL,"RGNMEMOBJ::vCreate");
  1989. rl.vRet(0);
  1990. if (!po.bValid())
  1991. {
  1992. RIP("Invalid EPATHOBJ");
  1993. }
  1994. else
  1995. {
  1996. ULONG count;
  1997. EDGE AETHead; // dummy head/tail node & sentinel for Active Edge Table
  1998. EDGE *pAETHead; // pointer to AETHead
  1999. EDGE GETHead; // dummy head/tail node & sentinel for Global Edge Table
  2000. EDGE *pGETHead; // pointer to GETHead
  2001. EDGE aEdge[MAX_POINTS];
  2002. prgn = (REGION *) NULL; // Assume failure.
  2003. if (po.bBeziers() && !po.bFlatten())
  2004. return;
  2005. // The given path should be closed when create region from path
  2006. // then make sure it here.
  2007. po.vCloseAllFigures();
  2008. if ((count = po.cCurves) < 2)
  2009. return;
  2010. // Is path contained in a bounding rectangle?
  2011. //
  2012. // If there is no bound (pBound = NULL) or
  2013. // the bound won't shrink the current BoundBox
  2014. // then try bFastFillWrapper.
  2015. //
  2016. // Many calling sites only initialize the top and bottom of the
  2017. // pBound rectange because the underlying clipping code only
  2018. // uses the top and bottom.
  2019. // Also, they always initialize them in FIX coordinate.
  2020. if ( (pBound==NULL) ||
  2021. ( ( pBound->top < po.rcfxBoundBox().yTop ) &&
  2022. ( pBound->bottom > po.rcfxBoundBox().yBottom)
  2023. ) )
  2024. {
  2025. if (bFastFillWrapper(po))
  2026. {
  2027. vTighten();
  2028. rl.vRet((ULONG_PTR)prgn);
  2029. return;
  2030. }
  2031. }
  2032. // Allocate memory for edge storage.
  2033. BOOL bAlloc;
  2034. EDGE *pFreeEdges; // pointer to memory free for use to store edges
  2035. if (count < MAX_POINTS)
  2036. {
  2037. pFreeEdges = &aEdge[0];
  2038. bAlloc = FALSE;
  2039. }
  2040. else
  2041. {
  2042. pFreeEdges = (PEDGE)PALLOCNOZ(sizeof(EDGE) * (count + 1), 'ngrG');
  2043. if (pFreeEdges == (PEDGE)NULL)
  2044. return;
  2045. bAlloc = TRUE;
  2046. }
  2047. // This is a size of random guess...
  2048. // Given a path of n points, assume there are n scans with 4 walls on each
  2049. // scan. The region will be expanded later if this size is too small.
  2050. ULONG size;
  2051. LONGLONG llSize;
  2052. FIX top = po.rcfxBoundBox().yTop;
  2053. FIX bottom = po.rcfxBoundBox().yBottom;
  2054. if (bottom < top)
  2055. {
  2056. // WINBUG #178736 claudebe 9-7-2000 we should check for math overflow where the path is created/offset/scaled see stress #178262
  2057. // when this is done, we can chage this test back into an assert
  2058. WARNING("PATHOBJ BoundBox is invalid.\n");
  2059. if (bAlloc)
  2060. VFREEMEM(pFreeEdges);
  2061. return;
  2062. }
  2063. // Make sure we account for the clipping in our estimate.
  2064. // Without this code, we could overestimate by many orders
  2065. // of magnitude.
  2066. if (pBound)
  2067. {
  2068. top = MAX(top, pBound->top);
  2069. bottom = MIN(bottom, pBound->bottom);
  2070. }
  2071. // The smallest region we should have from bounding is zero.
  2072. // Note this also takes care of the conversion issue of using
  2073. // FXTOL and assigning the result to an unsigned long.
  2074. // using LONGLONG because bottom-top may overflow a ULONG
  2075. llSize = MAX((LONGLONG)bottom-(LONGLONG)top, 0);
  2076. // we know that after >> 4, the result will fit in a ULONG
  2077. size = (ULONG)(FXTOL(llSize)) + 10;
  2078. if (size < 0x00ffffff)
  2079. {
  2080. size = QUANTUM_REGION_SIZE + (sizeof(INDEX_LONG) * 4 + NULL_SCAN_SIZE) * size;
  2081. prgn = (PREGION)ALLOCOBJ(size,RGN_TYPE,FALSE);
  2082. }
  2083. if (!prgn)
  2084. {
  2085. if (bAlloc)
  2086. VFREEMEM(pFreeEdges);
  2087. return;
  2088. }
  2089. prgn->sizeObj = size;
  2090. prgn->sizeRgn = offsetof(REGION,scan);
  2091. prgn->cRefs = 0;
  2092. prgn->iUnique = 0;
  2093. prgn->cScans = 0; // start from scratch, assume no scans
  2094. prgn->pscnTail = prgn->pscnHead();
  2095. // Construct the global edge list.
  2096. pGETHead = &GETHead;
  2097. vConstructGET(po, pGETHead, pFreeEdges,pBound); // bad line coordinates or
  2098. BOOL bSucceed = TRUE;
  2099. LONG yTop = NEG_INFINITY; // scan line for which we're currently scanning
  2100. // Create an empty AET with the head node also a tail sentinel
  2101. pAETHead = &AETHead;
  2102. AETHead.pNext = pAETHead; // mark that the AET is empty
  2103. AETHead.Y = 0; // used as a count for number of edges in AET
  2104. AETHead.X = 0x7FFFFFFF; // this is greater than any valid X value, so
  2105. // searches will always terminate
  2106. // Loop through all the scans in the polygon, adding edges from the GET to
  2107. // the Active Edge Table (AET) as we come to their starts, and scanning out
  2108. // the AET at each scan into a rectangle list. Each time it fills up, the
  2109. // rectangle list is passed to the filling routine, and then once again at
  2110. // the end if any rectangles remain undrawn. We continue so long as there
  2111. // are edges to be scanned out.
  2112. while (bSucceed)
  2113. {
  2114. // Advance the edges in the AET one scan, discarding any that have
  2115. // reached the end (if there are any edges in the AET)
  2116. if (AETHead.pNext != pAETHead)
  2117. vAdvanceAETEdges(pAETHead);
  2118. // If the AET is empty, done if the GET is empty, else jump ahead to
  2119. // the next edge in the GET; if the AET isn't empty, re-sort the AET
  2120. if (AETHead.pNext == pAETHead)
  2121. {
  2122. // Done if there are no edges in either the AET or the GET
  2123. if (GETHead.pNext == pGETHead)
  2124. break;
  2125. // There are no edges in the AET, so jump ahead to the next edge in
  2126. // the GET.
  2127. LONG yTopOld = yTop;
  2128. yTop = ((EDGE *)GETHead.pNext)->Y;
  2129. if (yTop != yTopOld)
  2130. {
  2131. // Fill in NULL scan between rectangles.
  2132. if (!(bSucceed = bAddNullScan(yTopOld, yTop)))
  2133. break;
  2134. }
  2135. }
  2136. else
  2137. {
  2138. // Re-sort the edges in the AET by X coordinate, if there are at
  2139. // least two edges in the AET (there could be one edge if the
  2140. // balancing edge hasn't yet been added from the GET)
  2141. if (((EDGE *)AETHead.pNext)->pNext != pAETHead)
  2142. vXSortAETEdges(pAETHead);
  2143. }
  2144. // Move any new edges that start on this scan from the GET to the AET;
  2145. // bother calling only if there's at least one edge to add
  2146. if (((EDGE *)GETHead.pNext)->Y == yTop)
  2147. vMoveNewEdges(pGETHead, pAETHead, yTop);
  2148. // Scan the AET into region scans (there's always at least one
  2149. // edge pair in the AET)
  2150. bSucceed = bAddScans(yTop, pAETHead, flOptions);
  2151. yTop++; // next scan
  2152. }
  2153. if (!bSucceed ||
  2154. !bAddNullScan(yTop, POS_INFINITY))
  2155. {
  2156. bDeleteRGNOBJ();
  2157. bSucceed = FALSE;
  2158. }
  2159. else
  2160. {
  2161. vTighten();
  2162. }
  2163. if (bAlloc)
  2164. VFREEMEM(pFreeEdges);
  2165. rl.vRet((ULONG_PTR)prgn);
  2166. }
  2167. }
  2168. /******************************Member*Function*****************************\
  2169. * RGNMEMOBJ::bFastFillWrapper
  2170. *
  2171. * create a rgn from a convex polygon.
  2172. *
  2173. * History:
  2174. * 27-Sep-1993 -by- Eric Kutter [erick]
  2175. * Wrote it.
  2176. \**************************************************************************/
  2177. #define QUICKPOINTS 40
  2178. BOOL RGNMEMOBJ::bFastFillWrapper(
  2179. EPATHOBJ& epo)
  2180. {
  2181. PATHDATA pd;
  2182. BOOL bRes = FALSE;
  2183. ASSERTGDI(!(epo.fl & PO_BEZIERS),"RGNMEMOBJ::bFastFill - bez\n");
  2184. ASSERTGDI(epo.cCurves == epo.cTotalPts(),"RGNMEMOBJ::cCurves != cTotalPts\n");
  2185. epo.vEnumStart();
  2186. if (epo.bEnum(&pd))
  2187. {
  2188. // if this ends the sub path, that means there is more than one sub path.
  2189. // also don't handle if we can't copy points onto stack
  2190. if (!(pd.flags & PD_ENDSUBPATH) && (epo.cCurves <= QUICKPOINTS))
  2191. {
  2192. POINTFIX aptfx[QUICKPOINTS];
  2193. LONG cPoints;
  2194. BOOL bMore;
  2195. RtlCopyMemory(aptfx,pd.pptfx,(SIZE_T)pd.count*sizeof(POINTFIX));
  2196. cPoints = pd.count;
  2197. do {
  2198. bMore = epo.bEnum(&pd);
  2199. if (pd.flags & PD_BEGINSUBPATH)
  2200. goto DoStart;
  2201. RtlCopyMemory(aptfx+cPoints,pd.pptfx,(SIZE_T)pd.count*sizeof(POINTFIX));
  2202. cPoints += pd.count;
  2203. } while(bMore);
  2204. // Should never hit this assert. if hit, the stack is already broken...
  2205. ASSERTGDI(cPoints <= QUICKPOINTS,"RGNMEMOBJ::bFastFillWrapper - too many points\n");
  2206. bRes = bFastFill(epo,cPoints,aptfx);
  2207. }
  2208. }
  2209. else if (pd.count > 1)
  2210. {
  2211. bRes = bFastFill(epo,pd.count,pd.pptfx);
  2212. }
  2213. else
  2214. {
  2215. bRes = TRUE;
  2216. }
  2217. DoStart:
  2218. epo.vEnumStart();
  2219. return(bRes);
  2220. }
  2221. /******************************Member*Function*****************************\
  2222. * RGNMEMOBJ::bFastFill
  2223. *
  2224. * create a rgn from a convex polygon.
  2225. * this routine is very similar to bFastFill in fastfill.cxx
  2226. *
  2227. * History:
  2228. * 14-Oct-1993 -by- Eric Kutter [erick]
  2229. * initial code stolen from s3 driver.
  2230. \**************************************************************************/
  2231. BOOL RGNMEMOBJ::bFastFill(
  2232. EPATHOBJ& po,
  2233. LONG cEdges, // Includes close figure edge
  2234. POINTFIX* pptfxFirst)
  2235. {
  2236. LONG cyTrapezoid; // Number of scans in current trapezoid
  2237. LONG yStart; // y-position of start point in current edge
  2238. LONG dM; // Edge delta in FIX units in x direction
  2239. LONG dN; // Edge delta in FIX units in y direction
  2240. LONG i;
  2241. POINTFIX* pptfxLast; // Points to the last point in the polygon array
  2242. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  2243. POINTFIX* pptfxOld; // Start point in current edge
  2244. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  2245. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  2246. // (doesn't include the closefigure edge)
  2247. LONG iEdge;
  2248. LONG lQuotient;
  2249. LONG lRemainder;
  2250. EDGEDATA aed[2]; // DDA terms and stuff
  2251. EDGEDATA* ped;
  2252. pptfxScan = pptfxFirst;
  2253. pptfxTop = pptfxFirst; // Assume for now that the first
  2254. // point in path is the topmost
  2255. pptfxLast = pptfxFirst + cEdges - 1;
  2256. LONG yCurrent;
  2257. // 'pptfxScan' will always point to the first point in the current
  2258. // edge, and 'cScanEdges' will the number of edges remaining, including
  2259. // the current one:
  2260. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  2261. if ((pptfxScan + 1)->y > pptfxScan->y)
  2262. {
  2263. // Collect all downs:
  2264. do {
  2265. if (--cScanEdges == 0)
  2266. goto SetUpForFilling;
  2267. pptfxScan++;
  2268. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  2269. // Collect all ups:
  2270. do {
  2271. if (--cScanEdges == 0)
  2272. goto SetUpForFillingCheck;
  2273. pptfxScan++;
  2274. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  2275. // Collect all downs:
  2276. pptfxTop = pptfxScan;
  2277. do {
  2278. if ((pptfxScan + 1)->y > pptfxFirst->y)
  2279. break;
  2280. if (--cScanEdges == 0)
  2281. goto SetUpForFilling;
  2282. pptfxScan++;
  2283. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  2284. return(FALSE);
  2285. }
  2286. else
  2287. {
  2288. // Collect all ups:
  2289. do {
  2290. pptfxTop++; // We increment this now because we
  2291. // want it to point to the very last
  2292. // point if we early out in the next
  2293. // statement...
  2294. if (--cScanEdges == 0)
  2295. goto SetUpForFilling;
  2296. } while ((pptfxTop + 1)->y <= pptfxTop->y);
  2297. // Collect all downs:
  2298. pptfxScan = pptfxTop;
  2299. do {
  2300. if (--cScanEdges == 0)
  2301. goto SetUpForFilling;
  2302. pptfxScan++;
  2303. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  2304. // Collect all ups:
  2305. do {
  2306. if ((pptfxScan + 1)->y < pptfxFirst->y)
  2307. break;
  2308. if (--cScanEdges == 0)
  2309. goto SetUpForFilling;
  2310. pptfxScan++;
  2311. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  2312. return(FALSE);
  2313. }
  2314. SetUpForFillingCheck:
  2315. // We check to see if the end of the current edge is higher
  2316. // than the top edge we've found so far:
  2317. if ((pptfxScan + 1)->y < pptfxTop->y)
  2318. pptfxTop = pptfxScan + 1;
  2319. SetUpForFilling:
  2320. yCurrent = (pptfxTop->y + 15) >> 4;
  2321. // Make sure we initialize the DDAs appropriately:
  2322. #define RIGHT 0
  2323. #define LEFT 1
  2324. aed[LEFT].cy = 0;
  2325. aed[RIGHT].cy = 0;
  2326. // For now, guess as to which is the left and which is the right edge:
  2327. aed[LEFT].dptfx = -(LONG) sizeof(POINTFIX);
  2328. aed[RIGHT].dptfx = sizeof(POINTFIX);
  2329. aed[LEFT].pptfx = pptfxTop;
  2330. aed[RIGHT].pptfx = pptfxTop;
  2331. // setup the region
  2332. ULONGSIZE_T size = (ULONGSIZE_T)(NULL_REGION_SIZE + NULL_SCAN_SIZE +
  2333. (sizeof(INDEX_LONG) * 2 + NULL_SCAN_SIZE) *
  2334. FXTOL(po.rcfxBoundBox().yBottom - po.rcfxBoundBox().yTop + 15));
  2335. prgn = (PREGION)ALLOCOBJ(size,RGN_TYPE,FALSE);
  2336. if (!prgn)
  2337. return(FALSE);
  2338. prgn->sizeObj = size;
  2339. prgn->sizeRgn = offsetof(REGION,scan);
  2340. prgn->cRefs = 0;
  2341. prgn->cScans = 0; // start from scratch, assume no scans
  2342. prgn->pscnTail = (PSCAN)((PBYTE)prgn + size);
  2343. // setup the scans
  2344. PSCAN pscnPrev= prgn->pscnHead();
  2345. ULONG cScans = 1;
  2346. pscnPrev->yTop = NEG_INFINITY;
  2347. pscnPrev->yBottom = yCurrent;
  2348. pscnPrev->cWalls = 0;
  2349. pscnPrev->ai_x[0].x = 0;
  2350. PSCAN pscn = pscnGet(pscnPrev);
  2351. NextEdge:
  2352. ASSERTGDI(pscn < prgn->pscnTail,"bFastFill - pscn past end\n");
  2353. // We loop through this routine on a per-trapezoid basis.
  2354. for (iEdge = 1; iEdge >= 0; iEdge--)
  2355. {
  2356. ped = &aed[iEdge];
  2357. if (ped->cy == 0)
  2358. {
  2359. // Need a new DDA:
  2360. do {
  2361. cEdges--;
  2362. if (cEdges < 0)
  2363. {
  2364. // the only way out
  2365. if (pscnPrev->cWalls == 0)
  2366. {
  2367. pscnPrev->yBottom = POS_INFINITY;
  2368. }
  2369. else
  2370. {
  2371. pscn->cWalls = 0;
  2372. pscn->ai_x[0].x = 0;
  2373. pscn->yTop = yCurrent;
  2374. pscn->yBottom = POS_INFINITY;
  2375. ++cScans;
  2376. pscn = pscnGet(pscn);
  2377. }
  2378. ASSERTGDI(pscn <= prgn->pscnTail,"bFastFill - pscn past end2\n");
  2379. prgn->cScans = cScans;
  2380. prgn->pscnTail = pscn;
  2381. ASSERT4GB((ULONGLONG)((PBYTE)pscn - (PBYTE)prgn));
  2382. prgn->sizeRgn = (ULONG)((PBYTE)pscn - (PBYTE)prgn);
  2383. return(TRUE);
  2384. }
  2385. // Find the next left edge, accounting for wrapping:
  2386. pptfxOld = ped->pptfx;
  2387. ped->pptfx = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  2388. if (ped->pptfx < pptfxFirst)
  2389. ped->pptfx = pptfxLast;
  2390. else if (ped->pptfx > pptfxLast)
  2391. ped->pptfx = pptfxFirst;
  2392. // Have to find the edge that spans yCurrent:
  2393. ped->cy = ((ped->pptfx->y + 15) >> 4) - yCurrent;
  2394. // With fractional coordinate end points, we may get edges
  2395. // that don't cross any scans, in which case we try the
  2396. // next one:
  2397. } while (ped->cy <= 0);
  2398. // 'pptfx' now points to the end point of the edge spanning
  2399. // the scan 'yCurrent'.
  2400. dN = ped->pptfx->y - pptfxOld->y;
  2401. dM = ped->pptfx->x - pptfxOld->x;
  2402. ASSERTGDI(dN > 0, "Should be going down only");
  2403. // Compute the DDA increment terms:
  2404. if (dM < 0)
  2405. {
  2406. dM = -dM;
  2407. if (dM < dN) // Can't be '<='
  2408. {
  2409. ped->dx = -1;
  2410. ped->lErrorUp = dN - dM;
  2411. }
  2412. else
  2413. {
  2414. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  2415. ped->dx = -lQuotient; // - dM / dN
  2416. ped->lErrorUp = lRemainder; // dM % dN
  2417. if (ped->lErrorUp > 0)
  2418. {
  2419. ped->dx--;
  2420. ped->lErrorUp = dN - ped->lErrorUp;
  2421. }
  2422. }
  2423. }
  2424. else
  2425. {
  2426. if (dM < dN) // Can't be '<='
  2427. {
  2428. ped->dx = 0;
  2429. ped->lErrorUp = dM;
  2430. }
  2431. else
  2432. {
  2433. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  2434. ped->dx = lQuotient; // dM / dN
  2435. ped->lErrorUp = lRemainder; // dM % dN
  2436. }
  2437. }
  2438. ped->lErrorDown = dN; // DDA limit
  2439. ped->lError = -1; // Error is initially zero (add dN - 1 for
  2440. // the ceiling, but subtract off dN so that
  2441. // we can check the sign instead of comparing
  2442. // to dN)
  2443. ped->x = pptfxOld->x;
  2444. yStart = pptfxOld->y;
  2445. if ((yStart & 15) != 0)
  2446. {
  2447. // Advance to the next integer y coordinate
  2448. for (i = 16 - (yStart & 15); i > 0; i--)
  2449. {
  2450. ped->x += ped->dx;
  2451. ped->lError += ped->lErrorUp;
  2452. if (ped->lError >= 0)
  2453. {
  2454. ped->lError -= ped->lErrorDown;
  2455. ped->x++;
  2456. }
  2457. }
  2458. }
  2459. if ((ped->x & 15) != 0)
  2460. {
  2461. ped->lError -= ped->lErrorDown * (16 - (ped->x & 15));
  2462. ped->x += 15; // We'll want the ceiling in just a bit...
  2463. }
  2464. // Chop off those fractional bits:
  2465. ped->x >>= 4;
  2466. ped->lError >>= 4;
  2467. }
  2468. }
  2469. cyTrapezoid = min(aed[LEFT].cy, aed[RIGHT].cy); // # of scans in this trap
  2470. aed[LEFT].cy -= cyTrapezoid;
  2471. aed[RIGHT].cy -= cyTrapezoid;
  2472. // If the left and right edges are vertical, simply output as
  2473. // a rectangle:
  2474. if (((aed[LEFT].lErrorUp | aed[RIGHT].lErrorUp) == 0) &&
  2475. ((aed[LEFT].dx | aed[RIGHT].dx) == 0))
  2476. {
  2477. LONG xL = aed[LEFT].x;
  2478. LONG xR = aed[RIGHT].x;
  2479. if (xL != xR)
  2480. {
  2481. if (xL > xR)
  2482. {
  2483. LONG l = xL;
  2484. xL = xR;
  2485. xR = l;
  2486. }
  2487. // non NULL case
  2488. if ((pscnPrev->cWalls == 2) &&
  2489. (pscnPrev->ai_x[0].x == xL) &&
  2490. (pscnPrev->ai_x[1].x == xR))
  2491. {
  2492. pscnPrev->yBottom = yCurrent+cyTrapezoid;
  2493. }
  2494. else
  2495. {
  2496. pscn->cWalls = 2;
  2497. pscn->ai_x[0].x = xL;
  2498. pscn->ai_x[1].x = xR;
  2499. pscn->ai_x[2].x = 2;
  2500. pscn->yTop = yCurrent;
  2501. pscn->yBottom = yCurrent+cyTrapezoid;
  2502. pscnPrev = pscn;
  2503. pscn = pscnGet(pscn);
  2504. ++cScans;
  2505. }
  2506. }
  2507. else
  2508. {
  2509. // NULL scan case
  2510. if (pscnPrev->cWalls == 0)
  2511. {
  2512. pscnPrev->yBottom = yCurrent+cyTrapezoid;
  2513. }
  2514. else
  2515. {
  2516. pscn->cWalls = 0;
  2517. pscn->ai_x[0].x = 0;
  2518. pscn->yTop = yCurrent;
  2519. pscn->yBottom = yCurrent+cyTrapezoid;
  2520. pscnPrev = pscn;
  2521. pscn = pscnGet(pscn);
  2522. ++cScans;
  2523. }
  2524. }
  2525. yCurrent += cyTrapezoid;
  2526. goto NextEdge;
  2527. }
  2528. while (TRUE)
  2529. {
  2530. LONG lWidth = aed[RIGHT].x - aed[LEFT].x;
  2531. if (lWidth > 0)
  2532. {
  2533. if ((pscnPrev->cWalls == 2) &&
  2534. (pscnPrev->ai_x[0].x == aed[LEFT].x) &&
  2535. (pscnPrev->ai_x[1].x == aed[RIGHT].x))
  2536. {
  2537. // the scans coalesce, just need to change the bottom
  2538. ContinueAfterZeroDup:
  2539. pscnPrev->yBottom = ++yCurrent;
  2540. }
  2541. else
  2542. {
  2543. // need to setup the entire scan
  2544. pscn->cWalls = 2;
  2545. pscn->ai_x[0].x = aed[LEFT].x;
  2546. pscn->ai_x[1].x = aed[RIGHT].x;
  2547. pscn->ai_x[2].x = 2;
  2548. ContinueAfterZero:
  2549. pscn->yTop = yCurrent;
  2550. pscn->yBottom = ++yCurrent;
  2551. pscnPrev = pscn;
  2552. pscn = pscnGet(pscn); // (PBYTE)pscn + NULL_SCAN_SIZE + 2 * sizeof(LONG);
  2553. ++cScans;
  2554. }
  2555. // Advance the right wall:
  2556. aed[RIGHT].x += aed[RIGHT].dx;
  2557. aed[RIGHT].lError += aed[RIGHT].lErrorUp;
  2558. if (aed[RIGHT].lError >= 0)
  2559. {
  2560. aed[RIGHT].lError -= aed[RIGHT].lErrorDown;
  2561. aed[RIGHT].x++;
  2562. }
  2563. // Advance the left wall:
  2564. aed[LEFT].x += aed[LEFT].dx;
  2565. aed[LEFT].lError += aed[LEFT].lErrorUp;
  2566. if (aed[LEFT].lError >= 0)
  2567. {
  2568. aed[LEFT].lError -= aed[LEFT].lErrorDown;
  2569. aed[LEFT].x++;
  2570. }
  2571. cyTrapezoid--;
  2572. if (cyTrapezoid == 0)
  2573. goto NextEdge;
  2574. }
  2575. else if (lWidth == 0)
  2576. {
  2577. // NULL scan, do null scan specific stuff
  2578. if (pscnPrev->cWalls == 0)
  2579. {
  2580. goto ContinueAfterZeroDup;
  2581. }
  2582. else
  2583. {
  2584. pscn->cWalls = 0;
  2585. pscn->ai_x[0].x = 0;
  2586. goto ContinueAfterZero;
  2587. }
  2588. }
  2589. else
  2590. {
  2591. #define SWAP(a, b, tmp) { tmp = a; a = b; b = tmp; }
  2592. // We certainly don't want to optimize for this case because we
  2593. // should rarely get self-intersecting polygons (if we're slow,
  2594. // the app gets what it deserves):
  2595. EDGEDATA edTmp;
  2596. SWAP(aed[LEFT],aed[RIGHT],edTmp);
  2597. continue;
  2598. }
  2599. }
  2600. }
  2601. #if DBG
  2602. /******************************Member*Function*****************************\
  2603. * VOID RGNOBJ::vPrintScans()
  2604. *
  2605. * DbgPrint the walls of every scan of the given region. This is
  2606. * for debugging only.
  2607. *
  2608. * History:
  2609. * 08-Mar-1991 -by- Wendy Wu [wendywu]
  2610. * Wrote it.
  2611. \**************************************************************************/
  2612. VOID RGNOBJ::vPrintScans()
  2613. {
  2614. COUNT cScans = prgn->cScans;
  2615. PSCAN pscn = prgn->pscnHead();
  2616. for (COUNT i = 0;
  2617. i < cScans;
  2618. i++)
  2619. {
  2620. COUNT cWalls = pscn->cWalls;
  2621. DbgPrint("Scan %ld: yTop = %ld, yBottom = %ld, cWalls = %ld\n",
  2622. i, pscn->yTop, pscn->yBottom, cWalls);
  2623. for (COUNT j = 0;
  2624. j < cWalls;
  2625. j+=2)
  2626. {
  2627. DbgPrint(" Left edge: index = %ld\n", pscn->ai_x[j].x);
  2628. DbgPrint(" Right edge: index = %ld\n", pscn->ai_x[j+1].x);
  2629. }
  2630. pscn = pscnGet(pscn);
  2631. }
  2632. }
  2633. #endif
  2634. /******************************Public*Routine******************************\
  2635. * VOID vTighten()
  2636. *
  2637. * Tighten the bounding rectangle
  2638. *
  2639. * History:
  2640. * 21-May-1991 -by- Donald Sidoroff [donalds]
  2641. * Wrote it.
  2642. \**************************************************************************/
  2643. VOID RGNOBJ::vTighten()
  2644. {
  2645. // If this is a NULL region, zero the bounding box and get out of here.
  2646. if (prgn->cScans == 1)
  2647. {
  2648. prgn->rcl.left = 0;
  2649. prgn->rcl.bottom = 0;
  2650. prgn->rcl.right = 0;
  2651. prgn->rcl.top = 0;
  2652. return;
  2653. }
  2654. // Start with a maximally crossed rectangle
  2655. ERECTL ercl(POS_INFINITY, POS_INFINITY, NEG_INFINITY, NEG_INFINITY);
  2656. COUNT cScans = prgn->cScans;
  2657. PSCAN pscn = pscnGot(prgn->pscnTail);
  2658. ercl.bottom = pscn->yTop; // The top of the empty bottom scan
  2659. pscn = prgn->pscnHead();
  2660. ercl.top = pscn->yBottom; // The bottom of the empty top scan
  2661. COUNT cWall;
  2662. while (cScans--)
  2663. {
  2664. // Are there any walls?
  2665. if ((cWall = pscn->cWalls) != 0)
  2666. {
  2667. if (ercl.left > pscn->ai_x[0].x)
  2668. ercl.left = pscn->ai_x[0].x;
  2669. if (ercl.right < pscn->ai_x[cWall - 1].x)
  2670. ercl.right = pscn->ai_x[cWall - 1].x;
  2671. }
  2672. pscn = pscnGet(pscn);
  2673. ASSERTGDI(pscn <= prgn->pscnTail, "vTighten2:Went past end of region\n");
  2674. }
  2675. if (ercl.left >= ercl.right)
  2676. {
  2677. ercl.left = 0;
  2678. ercl.right = 0;
  2679. }
  2680. prgn->rcl = *((RECTL *) &ercl);
  2681. }
  2682. /******************************Public*Routine******************************\
  2683. * BOOL vFramed(pscn, iWall)
  2684. *
  2685. * Marks the given wall as having been added to the frame path.
  2686. *
  2687. * History:
  2688. * 30-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  2689. * Wrote it.
  2690. \**************************************************************************/
  2691. #define REGION_FRAMED_OFFSET 0x10000000L
  2692. #define DIR_UP 0x00000001L
  2693. #define DIR_DOWN 0x00000000L
  2694. inline VOID vFramed(SCAN* pscn, LONG iWall, RGNOBJ* pro)
  2695. {
  2696. #if DBG
  2697. if (!VALID_SCR(pscn->ai_x[iWall].x))
  2698. {
  2699. pro->bValidateFramedRegion();
  2700. RIP("Wall revisited");
  2701. }
  2702. #endif
  2703. DONTUSE(pro);
  2704. pscn->ai_x[iWall].x += REGION_FRAMED_OFFSET;
  2705. }
  2706. /******************************Public*Routine******************************\
  2707. * BOOL bFramed(pscn, iWall)
  2708. *
  2709. * Returns TRUE if the wall has already been added to the frame's path.
  2710. *
  2711. * History:
  2712. * 30-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  2713. * Wrote it.
  2714. \**************************************************************************/
  2715. inline BOOL bFramed(SCAN* pscn, LONG iWall)
  2716. {
  2717. return(pscn->ai_x[iWall].x > MAX_REGION_COORD);
  2718. }
  2719. /******************************Public*Routine******************************\
  2720. * BOOL RGNOBJ::xMyGet(pscn, iWall, iDir)
  2721. *
  2722. * Retrieves the x-value of the wall of the given scan, iDir indicating
  2723. * if it should be the top or bottom.
  2724. *
  2725. * History:
  2726. * 31-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  2727. * Wrote it.
  2728. \**************************************************************************/
  2729. inline LONG RGNOBJ::xMyGet(SCAN* pscn, LONG iWall, LONG iDir)
  2730. {
  2731. DONTUSE(iDir);
  2732. INDEX_LONG il = pscn->ai_x[iWall];
  2733. if (il.x > MAX_REGION_COORD)
  2734. il.x -= REGION_FRAMED_OFFSET;
  2735. #if DBG
  2736. if (!VALID_SCR(il.x))
  2737. {
  2738. bValidateFramedRegion();
  2739. RIP("Wall Revisited");
  2740. }
  2741. #endif
  2742. return(il.x);
  2743. }
  2744. /******************************Public*Routine******************************\
  2745. * BOOL RGNOBJ::bOutline(epo, pexo)
  2746. *
  2747. * Create a path from the outline of a region.
  2748. *
  2749. * WARNING: This call destroys the data in the region!
  2750. *
  2751. * Note that this code makes the implicit assumption that the x-value of
  2752. * adjacent walls is not the same (i.e., no empty rectangles).
  2753. *
  2754. * History:
  2755. * 30-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  2756. * Wrote it.
  2757. \**************************************************************************/
  2758. BOOL RGNOBJ::bOutline(
  2759. EPATHOBJ& epo,
  2760. EXFORMOBJ *pexo)
  2761. {
  2762. RGNLOG rl(prgn,"RGNOBJ::bOutline");
  2763. POINTL aptl[2];
  2764. COUNT cScans;
  2765. SCAN* pscnCurrent;
  2766. COUNT iWallCurrent;
  2767. COUNT cWallsCurrent;
  2768. // Now compute the outline:
  2769. pscnCurrent = prgn->pscnHead();
  2770. cScans = prgn->cScans;
  2771. while (cScans--)
  2772. {
  2773. cWallsCurrent = pscnCurrent->cWalls;
  2774. for (iWallCurrent = 0; iWallCurrent != cWallsCurrent; iWallCurrent++)
  2775. {
  2776. // Only start at unvisited walls:
  2777. if (!bFramed(pscnCurrent, iWallCurrent))
  2778. {
  2779. SCAN* pscn = pscnCurrent;
  2780. COUNT iWall = iWallCurrent;
  2781. LONG iTurn;
  2782. aptl[0].x = xMyGet(pscn, iWallCurrent, DIR_UP);
  2783. aptl[0].y = pscn->yTop;
  2784. if (!epo.bMoveTo(pexo, aptl))
  2785. return(FALSE);
  2786. SCAN* pscnSearch = pscnGet(pscn);
  2787. BOOL bInside = (BOOL) (iWallCurrent & 1);
  2788. // Mark that we've visited this wall:
  2789. vFramed(pscn, iWall, this);
  2790. // Loop until the path closes on itself:
  2791. GoDown:
  2792. iTurn = +1;
  2793. while (pscnSearch->cWalls != 0)
  2794. {
  2795. LONG xWall = xMyGet(pscn, iWall, DIR_DOWN);
  2796. LONG iNewWall;
  2797. LONG xNewWall;
  2798. COUNT iLeft = bInside;
  2799. COUNT iRight = pscnSearch->cWalls - 1 - bInside;
  2800. // It would be nice if the first wall in the region structure
  2801. // was minus infinity, but it isn't, so we do this check:
  2802. if (xMyGet(pscnSearch, iLeft, DIR_UP) > xWall)
  2803. iNewWall = iLeft;
  2804. else
  2805. {
  2806. // Check if it's possible to find a wall with the
  2807. // minimum x-value > xWall:
  2808. if (xMyGet(pscnSearch, iRight, DIR_UP) <= xWall)
  2809. break; // =====>
  2810. // Do a binary search to find it:
  2811. while (TRUE)
  2812. {
  2813. COUNT iSearch = (iLeft + iRight) >> 1;
  2814. if (iSearch == iLeft)
  2815. break; // =====>
  2816. LONG xSearch = xMyGet(pscnSearch, iSearch, DIR_UP);
  2817. if (xSearch > xWall)
  2818. iRight = iSearch;
  2819. else
  2820. iLeft = iSearch;
  2821. }
  2822. iNewWall = iRight;
  2823. }
  2824. if ((iNewWall & 1) != bInside)
  2825. {
  2826. // There is a region directly below xWall. We can't
  2827. // move down if its left side is < the left
  2828. // side of our space:
  2829. if (iWall > 0 &&
  2830. xMyGet(pscnSearch, iNewWall - 1, DIR_UP) <
  2831. xMyGet(pscn, iWall - 1, DIR_DOWN))
  2832. {
  2833. iTurn = -1;
  2834. break; // =====>
  2835. }
  2836. iNewWall--;
  2837. }
  2838. else
  2839. {
  2840. // There is a space directly below xWall. We can't
  2841. // move down if its right side is more than the
  2842. // right side of our region:
  2843. if (xMyGet(pscnSearch, iNewWall, DIR_UP) >=
  2844. xMyGet(pscn, iWall + 1, DIR_DOWN))
  2845. break; // =====>
  2846. }
  2847. xNewWall = xMyGet(pscnSearch, iNewWall, DIR_UP);
  2848. // Don't bother outputing multiple in-line straight lines:
  2849. if (xWall != xNewWall ||
  2850. xMyGet(pscn, iWall, DIR_UP) != xNewWall ||
  2851. xMyGet(pscnSearch, iNewWall, DIR_DOWN) != xNewWall)
  2852. {
  2853. aptl[0].x = xWall;
  2854. aptl[0].y = pscn->yBottom;
  2855. aptl[1].y = pscn->yBottom;
  2856. aptl[1].x = xNewWall;
  2857. if (!epo.bPolyLineTo(pexo, aptl, 2))
  2858. return(FALSE);
  2859. }
  2860. pscn = pscnSearch;
  2861. iWall = iNewWall;
  2862. pscnSearch = pscnGet(pscn);
  2863. vFramed(pscn, iWall, this);
  2864. }
  2865. // Setup to go up other side:
  2866. aptl[0].x = xMyGet(pscn, iWall, DIR_DOWN);
  2867. aptl[0].y = pscn->yBottom;
  2868. aptl[1].y = pscn->yBottom;
  2869. aptl[1].x = xMyGet(pscn, iWall + iTurn, DIR_DOWN);
  2870. if (!epo.bPolyLineTo(pexo, aptl, 2))
  2871. return(FALSE);
  2872. pscnSearch = pscnGot(pscn);
  2873. iWall += iTurn;
  2874. vFramed(pscn, iWall, this);
  2875. // Go up:
  2876. iTurn = -1;
  2877. while (pscnSearch->cWalls != 0)
  2878. {
  2879. LONG xWall = xMyGet(pscn, iWall, DIR_UP);
  2880. LONG iNewWall;
  2881. LONG xNewWall;
  2882. COUNT iLeft = bInside;
  2883. COUNT iRight = pscnSearch->cWalls - 1 - bInside;
  2884. // It would be nice if the last wall in the region structure
  2885. // was plus infinity, but it isn't, so we do this check:
  2886. if (xMyGet(pscnSearch, iRight, DIR_DOWN) < xWall)
  2887. iNewWall = iRight;
  2888. else
  2889. {
  2890. // Check if it's possible to find a wall with the
  2891. // maximum x-value < xWall:
  2892. if (xMyGet(pscnSearch, iLeft, DIR_DOWN) >= xWall)
  2893. break; // =====>
  2894. // Binary search to find it:
  2895. while (TRUE)
  2896. {
  2897. COUNT iSearch = (iLeft + iRight) >> 1;
  2898. if (iSearch == iLeft)
  2899. break; // =====>
  2900. LONG xSearch = xMyGet(pscnSearch, iSearch, DIR_DOWN);
  2901. if (xSearch >= xWall)
  2902. iRight = iSearch;
  2903. else
  2904. iLeft = iSearch;
  2905. }
  2906. iNewWall = iLeft;
  2907. }
  2908. if ((iNewWall & 1) == bInside)
  2909. {
  2910. // There is a region directly above xWall. We can't
  2911. // move up if its right side is more than the right
  2912. // side of our space:
  2913. if (iWall < pscn->cWalls - 1 &&
  2914. xMyGet(pscnSearch, iNewWall + 1, DIR_DOWN) >
  2915. xMyGet(pscn, iWall + 1, DIR_UP))
  2916. {
  2917. iTurn = +1;
  2918. break; // =====>
  2919. }
  2920. iNewWall++;
  2921. }
  2922. else
  2923. {
  2924. // There is a space directly above xWall. We can't
  2925. // move up if its left side is <= the left side
  2926. // of our region:
  2927. if (xMyGet(pscnSearch, iNewWall, DIR_DOWN) <=
  2928. xMyGet(pscn, iWall - 1, DIR_UP))
  2929. break; // =====>
  2930. }
  2931. xNewWall = xMyGet(pscnSearch, iNewWall, DIR_DOWN);
  2932. // Don't bother outputing multiple in-line straight lines:
  2933. if (xWall != xNewWall ||
  2934. xMyGet(pscn, iWall, DIR_DOWN) != xNewWall ||
  2935. xMyGet(pscnSearch, iNewWall, DIR_UP) != xNewWall)
  2936. {
  2937. aptl[0].x = xWall;
  2938. aptl[0].y = pscn->yTop;
  2939. aptl[1].y = pscn->yTop;
  2940. aptl[1].x = xNewWall;
  2941. if (!epo.bPolyLineTo(pexo, aptl, 2))
  2942. return(FALSE);
  2943. }
  2944. pscn = pscnSearch;
  2945. iWall = iNewWall;
  2946. pscnSearch = pscnGot(pscn);
  2947. vFramed(pscn, iWall, this);
  2948. }
  2949. // Check if we've returned to where we started from:
  2950. if (pscnCurrent != pscn || iWallCurrent != iWall - 1)
  2951. {
  2952. // Setup to go down other side:
  2953. aptl[0].x = xMyGet(pscn, iWall, DIR_UP);
  2954. aptl[0].y = pscn->yTop;
  2955. aptl[1].y = pscn->yTop;
  2956. aptl[1].x = xMyGet(pscn, iWall + iTurn, DIR_UP);
  2957. if (!epo.bPolyLineTo(pexo, aptl, 2))
  2958. return(FALSE);
  2959. pscnSearch = pscnGet(pscn);
  2960. iWall += iTurn;
  2961. vFramed(pscn, iWall, this);
  2962. goto GoDown; // =====>
  2963. }
  2964. // We're all done with this outline!
  2965. aptl[0].x = xMyGet(pscn, iWall, DIR_UP);
  2966. aptl[0].y = pscn->yTop;
  2967. if (!epo.bPolyLineTo(pexo, aptl, 1) ||
  2968. !epo.bCloseFigure())
  2969. return(FALSE);
  2970. }
  2971. }
  2972. pscnCurrent = pscnGet(pscnCurrent);
  2973. }
  2974. return(TRUE);
  2975. }
  2976. /******************************Public*Routine******************************\
  2977. * BOOL RGNOBJ::bCreate(epo, pexo)
  2978. *
  2979. * Create a path from the frame of a region without destroying the region.
  2980. *
  2981. * History:
  2982. * 30-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  2983. * Wrote it.
  2984. \**************************************************************************/
  2985. BOOL RGNOBJ::bCreate(
  2986. EPATHOBJ& epo,
  2987. EXFORMOBJ *pexo)
  2988. {
  2989. // When converting the region to a path, bCreate() destroys the region's
  2990. // data, which would be sort of rude, so make a copy of the region first:
  2991. BOOL bRes;
  2992. RGNMEMOBJTMP rmoCopy(sizeRgn());
  2993. if (!rmoCopy.bValid())
  2994. {
  2995. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2996. bRes = FALSE;
  2997. }
  2998. else
  2999. {
  3000. rmoCopy.vCopy(*this);
  3001. VALIDATE(rmoCopy);
  3002. bRes = rmoCopy.bOutline(epo, pexo);
  3003. VALIDATE(*(RGNOBJ *)this);
  3004. }
  3005. return(bRes);
  3006. }
  3007. /******************************Public*Routine******************************\
  3008. * BOOL RGNOBJ::bSubtract(prcl, arcl, crcl)
  3009. *
  3010. * Subtract a list of rectangles from a rectangle to produce a region.
  3011. * This is just a special case of bMerge and is written to speed up
  3012. * USER's computation of VisRgns for obscured windows.
  3013. *
  3014. * WARNING: If this function returns FALSE, the region may be inconsistent.
  3015. * The caller must discard or reset the region. (See bug #343770)
  3016. *
  3017. * History:
  3018. * 10-Aug-1993 -by- Eric Kutter [erick]
  3019. * rewrote the complex case. (accounts for 50% of operations)
  3020. *
  3021. * 18-Nov-1992 -by- Donald Sidoroff [donalds]
  3022. * Wrote it.
  3023. \**************************************************************************/
  3024. BOOL RGNOBJAPI::bSubtract(RECTL *prcl, RECTL *arcl, int crcl)
  3025. {
  3026. RGNLOG rl(hrgn_,prgn,"RGNOBJAPI::bSubtract");
  3027. rl.vRet(0);
  3028. PREGION prgn1 = prgn;
  3029. ASSERTGDI(crcl > 0, "Zero rectangles in RGNOBJ::bSubtract\n");
  3030. // Since we are really pressed for speed, we special case ONE rectangle being
  3031. // subtracted. There are only a few cases to deal with and the result always
  3032. // fits into a quantum region.
  3033. #if DBG
  3034. for (int i = 0; i < crcl; ++i)
  3035. {
  3036. if ((arcl[i].left >= arcl[i].right) || (arcl[i].top >= arcl[i].bottom))
  3037. {
  3038. RIP("RGNOBJAPI::bSubtract - invalid rectangle from USER\n");
  3039. arcl[i].left = -10001;
  3040. arcl[i].right = -10000;
  3041. arcl[i].top = -10001;
  3042. arcl[i].bottom = -10000;
  3043. }
  3044. }
  3045. #endif
  3046. // Handle empty rectangles here. Otherwise if we pass them to
  3047. // bSubtractComplex they can cause an AV with the sentinel case
  3048. // (see bug 299398 for details).
  3049. if (((ERECTL *) prcl)->bEmpty())
  3050. {
  3051. vSet();
  3052. return TRUE;
  3053. }
  3054. if (crcl == 1)
  3055. {
  3056. // First discard total misses
  3057. if ((arcl[0].top >= prcl->bottom) ||
  3058. (arcl[0].left >= prcl->right) ||
  3059. (arcl[0].bottom <= prcl->top) ||
  3060. (arcl[0].right <= prcl->left))
  3061. {
  3062. vSet(prcl);
  3063. return(TRUE);
  3064. }
  3065. /*
  3066. OK, this gets a little tricky. There are 16 distinct ways that
  3067. two rectangles can overlap. In the diagram below, 1 and 2 are
  3068. rectangle boundaries and asterisks represent areas of overlap.
  3069. 22 22222 2 22
  3070. 2*11 2***2 1*1 11*2
  3071. 1 1 1 1 1 1 1 1 TOP_NOTCH
  3072. 111 111 111 111
  3073. 22 22222 2 22
  3074. 2*11 2***2 1*1 11*2
  3075. 2* 1 2***2 1*1 1 *2 VERT_CLIP
  3076. 2*11 2***2 1*1 11*2
  3077. 22 22222 2 22
  3078. 111 111 111 111
  3079. 2* 1 2***2 1*1 1 *2 VERT_NOTCH
  3080. 111 111 111 111
  3081. 111 111 111 111
  3082. 1 1 1 1 1 1 1 1 BOTTOM_NOTCH
  3083. 2*11 2***2 1*1 11*2
  3084. LEFT_NOTCH HORIZ_CLIP HORIZ_NOTCH RIGHT_NOTCH
  3085. I have given each of the rows and columns names. By simply finding
  3086. out which state I'm in, I can produce the correct output region.
  3087. */
  3088. RECTL rcl;
  3089. SCAN *pscn;
  3090. int iState;
  3091. if (arcl[0].left <= prcl->left)
  3092. iState = arcl[0].right < prcl->right ? SR_LEFT_NOTCH : SR_HORIZ_CLIP ;
  3093. else
  3094. iState = arcl[0].right < prcl->right ? SR_HORIZ_NOTCH : SR_RIGHT_NOTCH;
  3095. if (arcl[0].top <= prcl->top)
  3096. iState += arcl[0].bottom < prcl->bottom ? SR_TOP_NOTCH : SR_VERT_CLIP ;
  3097. else
  3098. iState += arcl[0].bottom < prcl->bottom ? SR_VERT_NOTCH : SR_BOTTOM_NOTCH;
  3099. switch(iState)
  3100. {
  3101. // NULL case
  3102. case SR_VERT_CLIP | SR_HORIZ_CLIP:
  3103. vSet();
  3104. break;
  3105. // SINGLE cases
  3106. case SR_TOP_NOTCH | SR_HORIZ_CLIP:
  3107. rcl = *prcl;
  3108. rcl.top = arcl[0].bottom;
  3109. vSet(&rcl);
  3110. break;
  3111. case SR_VERT_CLIP | SR_LEFT_NOTCH:
  3112. rcl = *prcl;
  3113. rcl.left = arcl[0].right;
  3114. vSet(&rcl);
  3115. break;
  3116. case SR_VERT_CLIP | SR_RIGHT_NOTCH:
  3117. rcl = *prcl;
  3118. rcl.right = arcl[0].left;
  3119. vSet(&rcl);
  3120. break;
  3121. case SR_BOTTOM_NOTCH | SR_HORIZ_CLIP:
  3122. rcl = *prcl;
  3123. rcl.bottom = arcl[0].top;
  3124. vSet(&rcl);
  3125. break;
  3126. // 2 scans (Corner notch)
  3127. case SR_TOP_NOTCH | SR_LEFT_NOTCH:
  3128. prgn1->sizeRgn = NULL_REGION_SIZE + 3 * NULL_SCAN_SIZE + 4 * sizeof(INDEX_LONG);
  3129. prgn1->cScans = 4;
  3130. prgn1->rcl = *prcl;
  3131. pscn = prgn1->pscnHead();
  3132. pscn->cWalls = 0;
  3133. pscn->yTop = NEG_INFINITY;
  3134. pscn->yBottom = prcl->top;
  3135. pscn->ai_x[0].x = 0; // This sets cWalls2
  3136. pscn = pscnGet(pscn);
  3137. pscn->cWalls = 2;
  3138. pscn->yTop = prcl->top;
  3139. pscn->yBottom = arcl[0].bottom;
  3140. pscn->ai_x[0].x = arcl[0].right;
  3141. pscn->ai_x[1].x = prcl->right;
  3142. pscn->ai_x[2].x = 2; // This sets cWalls2
  3143. pscn = pscnGet(pscn);
  3144. pscn->cWalls = 2;
  3145. pscn->yTop = arcl[0].bottom;
  3146. pscn->yBottom = prcl->bottom;
  3147. pscn->ai_x[0].x = prcl->left;
  3148. pscn->ai_x[1].x = prcl->right;
  3149. pscn->ai_x[2].x = 2; // This sets cWalls2
  3150. pscn = pscnGet(pscn);
  3151. pscn->cWalls = 0;
  3152. pscn->yTop = prcl->bottom;
  3153. pscn->yBottom = POS_INFINITY;
  3154. pscn->ai_x[0].x = 0; // This sets cWalls2
  3155. prgn1->pscnTail = pscnGet(pscn);
  3156. break;
  3157. case SR_TOP_NOTCH | SR_RIGHT_NOTCH:
  3158. prgn1->sizeRgn = NULL_REGION_SIZE + 3 * NULL_SCAN_SIZE + 4 * sizeof(INDEX_LONG);
  3159. prgn1->cScans = 4;
  3160. prgn1->rcl = *prcl;
  3161. pscn = prgn1->pscnHead();
  3162. pscn->cWalls = 0;
  3163. pscn->yTop = NEG_INFINITY;
  3164. pscn->yBottom = prcl->top;
  3165. pscn->ai_x[0].x = 0; // This sets cWalls2
  3166. pscn = pscnGet(pscn);
  3167. pscn->cWalls = 2;
  3168. pscn->yTop = prcl->top;
  3169. pscn->yBottom = arcl[0].bottom;
  3170. pscn->ai_x[0].x = prcl->left;
  3171. pscn->ai_x[1].x = arcl[0].left;
  3172. pscn->ai_x[2].x = 2; // This sets cWalls2
  3173. pscn = pscnGet(pscn);
  3174. pscn->cWalls = 2;
  3175. pscn->yTop = arcl[0].bottom;
  3176. pscn->yBottom = prcl->bottom;
  3177. pscn->ai_x[0].x = prcl->left;
  3178. pscn->ai_x[1].x = prcl->right;
  3179. pscn->ai_x[2].x = 2; // This sets cWalls2
  3180. pscn = pscnGet(pscn);
  3181. pscn->cWalls = 0;
  3182. pscn->yTop = prcl->bottom;
  3183. pscn->yBottom = POS_INFINITY;
  3184. pscn->ai_x[0].x = 0; // This sets cWalls2
  3185. prgn1->pscnTail = pscnGet(pscn);
  3186. break;
  3187. case SR_BOTTOM_NOTCH | SR_LEFT_NOTCH:
  3188. prgn1->sizeRgn = NULL_REGION_SIZE + 3 * NULL_SCAN_SIZE + 4 * sizeof(INDEX_LONG);
  3189. prgn1->cScans = 4;
  3190. prgn1->rcl = *prcl;
  3191. pscn = prgn1->pscnHead();
  3192. pscn->cWalls = 0;
  3193. pscn->yTop = NEG_INFINITY;
  3194. pscn->yBottom = prcl->top;
  3195. pscn->ai_x[0].x = 0; // This sets cWalls2
  3196. pscn = pscnGet(pscn);
  3197. pscn->cWalls = 2;
  3198. pscn->yTop = prcl->top;
  3199. pscn->yBottom = arcl[0].top;
  3200. pscn->ai_x[0].x = prcl->left;
  3201. pscn->ai_x[1].x = prcl->right;
  3202. pscn->ai_x[2].x = 2; // This sets cWalls2
  3203. pscn = pscnGet(pscn);
  3204. pscn->cWalls = 2;
  3205. pscn->yTop = arcl[0].top;
  3206. pscn->yBottom = prcl->bottom;
  3207. pscn->ai_x[0].x = arcl[0].right;
  3208. pscn->ai_x[1].x = prcl->right;
  3209. pscn->ai_x[2].x = 2; // This sets cWalls2
  3210. pscn = pscnGet(pscn);
  3211. pscn->cWalls = 0;
  3212. pscn->yTop = prcl->bottom;
  3213. pscn->yBottom = POS_INFINITY;
  3214. pscn->ai_x[0].x = 0; // This sets cWalls2
  3215. prgn1->pscnTail = pscnGet(pscn);
  3216. break;
  3217. case SR_BOTTOM_NOTCH | SR_RIGHT_NOTCH:
  3218. prgn1->sizeRgn = NULL_REGION_SIZE + 3 * NULL_SCAN_SIZE + 4 * sizeof(INDEX_LONG);
  3219. prgn1->cScans = 4;
  3220. prgn1->rcl = *prcl;
  3221. pscn = prgn1->pscnHead();
  3222. pscn->cWalls = 0;
  3223. pscn->yTop = NEG_INFINITY;
  3224. pscn->yBottom = prcl->top;
  3225. pscn->ai_x[0].x = 0; // This sets cWalls2
  3226. pscn = pscnGet(pscn);
  3227. pscn->cWalls = 2;
  3228. pscn->yTop = prcl->top;
  3229. pscn->yBottom = arcl[0].top;
  3230. pscn->ai_x[0].x = prcl->left;
  3231. pscn->ai_x[1].x = prcl->right;
  3232. pscn->ai_x[2].x = 2; // This sets cWalls2
  3233. pscn = pscnGet(pscn);
  3234. pscn->cWalls = 2;
  3235. pscn->yTop = arcl[0].top;
  3236. pscn->yBottom = prcl->bottom;
  3237. pscn->ai_x[0].x = prcl->left;
  3238. pscn->ai_x[1].x = arcl[0].left;
  3239. pscn->ai_x[2].x = 2; // This sets cWalls2
  3240. pscn = pscnGet(pscn);
  3241. pscn->cWalls = 0;
  3242. pscn->yTop = prcl->bottom;
  3243. pscn->yBottom = POS_INFINITY;
  3244. pscn->ai_x[0].x = 0; // This sets cWalls2
  3245. prgn1->pscnTail = pscnGet(pscn);
  3246. break;
  3247. // 3 scans
  3248. case SR_VERT_CLIP | SR_HORIZ_NOTCH:
  3249. prgn1->sizeRgn = NULL_REGION_SIZE + 2 * NULL_SCAN_SIZE + 4 * sizeof(INDEX_LONG);
  3250. prgn1->cScans = 3;
  3251. prgn1->rcl = *prcl;
  3252. pscn = prgn1->pscnHead();
  3253. pscn->cWalls = 0;
  3254. pscn->yTop = NEG_INFINITY;
  3255. pscn->yBottom = prcl->top;
  3256. pscn->ai_x[0].x = 0; // This sets cWalls2
  3257. pscn = pscnGet(pscn);
  3258. pscn->cWalls = 4;
  3259. pscn->yTop = prcl->top;
  3260. pscn->yBottom = prcl->bottom;
  3261. pscn->ai_x[0].x = prcl->left;
  3262. pscn->ai_x[1].x = arcl[0].left;
  3263. pscn->ai_x[2].x = arcl[0].right;
  3264. pscn->ai_x[3].x = prcl->right;
  3265. pscn->ai_x[4].x = 4; // This sets cWalls2
  3266. pscn = pscnGet(pscn);
  3267. pscn->cWalls = 0;
  3268. pscn->yTop = prcl->bottom;
  3269. pscn->yBottom = POS_INFINITY;
  3270. pscn->ai_x[0].x = 0; // This sets cWalls2
  3271. prgn1->pscnTail = pscnGet(pscn);
  3272. break;
  3273. // 4 scans (Edge notch)
  3274. case SR_TOP_NOTCH | SR_HORIZ_NOTCH:
  3275. prgn1->sizeRgn = NULL_REGION_SIZE + 3 * NULL_SCAN_SIZE + 6 * sizeof(INDEX_LONG);
  3276. prgn1->cScans = 4;
  3277. prgn1->rcl = *prcl;
  3278. pscn = prgn1->pscnHead();
  3279. pscn->cWalls = 0;
  3280. pscn->yTop = NEG_INFINITY;
  3281. pscn->yBottom = prcl->top;
  3282. pscn->ai_x[0].x = 0; // This sets cWalls2
  3283. pscn = pscnGet(pscn);
  3284. pscn->cWalls = 4;
  3285. pscn->yTop = prcl->top;
  3286. pscn->yBottom = arcl[0].bottom;
  3287. pscn->ai_x[0].x = prcl->left;
  3288. pscn->ai_x[1].x = arcl[0].left;
  3289. pscn->ai_x[2].x = arcl[0].right;
  3290. pscn->ai_x[3].x = prcl->right;
  3291. pscn->ai_x[4].x = 4; // This sets cWalls2
  3292. pscn = pscnGet(pscn);
  3293. pscn->cWalls = 2;
  3294. pscn->yTop = arcl[0].bottom;
  3295. pscn->yBottom = prcl->bottom;
  3296. pscn->ai_x[0].x = prcl->left;
  3297. pscn->ai_x[1].x = prcl->right;
  3298. pscn->ai_x[2].x = 2; // This sets cWalls2
  3299. pscn = pscnGet(pscn);
  3300. pscn->cWalls = 0;
  3301. pscn->yTop = prcl->bottom;
  3302. pscn->yBottom = POS_INFINITY;
  3303. pscn->ai_x[0].x = 0; // This sets cWalls2
  3304. prgn1->pscnTail = pscnGet(pscn);
  3305. break;
  3306. case SR_BOTTOM_NOTCH | SR_HORIZ_NOTCH:
  3307. prgn1->sizeRgn = NULL_REGION_SIZE + 3 * NULL_SCAN_SIZE + 6 * sizeof(INDEX_LONG);
  3308. prgn1->cScans = 4;
  3309. prgn1->rcl = *prcl;
  3310. pscn = prgn1->pscnHead();
  3311. pscn->cWalls = 0;
  3312. pscn->yTop = NEG_INFINITY;
  3313. pscn->yBottom = prcl->top;
  3314. pscn->ai_x[0].x = 0; // This sets cWalls2
  3315. pscn = pscnGet(pscn);
  3316. pscn->cWalls = 2;
  3317. pscn->yTop = prcl->top;
  3318. pscn->yBottom = arcl[0].top;
  3319. pscn->ai_x[0].x = prcl->left;
  3320. pscn->ai_x[1].x = prcl->right;
  3321. pscn->ai_x[2].x = 2; // This sets cWalls2
  3322. pscn = pscnGet(pscn);
  3323. pscn->cWalls = 4;
  3324. pscn->yTop = arcl[0].top;
  3325. pscn->yBottom = prcl->bottom;
  3326. pscn->ai_x[0].x = prcl->left;
  3327. pscn->ai_x[1].x = arcl[0].left;
  3328. pscn->ai_x[2].x = arcl[0].right;
  3329. pscn->ai_x[3].x = prcl->right;
  3330. pscn->ai_x[4].x = 4; // This sets cWalls2
  3331. pscn = pscnGet(pscn);
  3332. pscn->cWalls = 0;
  3333. pscn->yTop = prcl->bottom;
  3334. pscn->yBottom = POS_INFINITY;
  3335. pscn->ai_x[0].x = 0; // This sets cWalls2
  3336. prgn1->pscnTail = pscnGet(pscn);
  3337. break;
  3338. // 5 scans
  3339. case SR_VERT_NOTCH | SR_HORIZ_CLIP:
  3340. prgn1->sizeRgn = NULL_REGION_SIZE + 4 * NULL_SCAN_SIZE + 4 * sizeof(INDEX_LONG);
  3341. prgn1->cScans = 5;
  3342. prgn1->rcl = *prcl;
  3343. pscn = prgn1->pscnHead();
  3344. pscn->cWalls = 0;
  3345. pscn->yTop = NEG_INFINITY;
  3346. pscn->yBottom = prcl->top;
  3347. pscn->ai_x[0].x = 0; // This sets cWalls2
  3348. pscn = pscnGet(pscn);
  3349. pscn->cWalls = 2;
  3350. pscn->yTop = prcl->top;
  3351. pscn->yBottom = arcl[0].top;
  3352. pscn->ai_x[0].x = prcl->left;
  3353. pscn->ai_x[1].x = prcl->right;
  3354. pscn->ai_x[2].x = 2; // This sets cWalls2
  3355. pscn = pscnGet(pscn);
  3356. pscn->cWalls = 0;
  3357. pscn->yTop = arcl[0].top;
  3358. pscn->yBottom = arcl[0].bottom;
  3359. pscn->ai_x[0].x = 0; // This sets cWalls2
  3360. pscn = pscnGet(pscn);
  3361. pscn->cWalls = 2;
  3362. pscn->yTop = arcl[0].bottom;
  3363. pscn->yBottom = prcl->bottom;
  3364. pscn->ai_x[0].x = prcl->left;
  3365. pscn->ai_x[1].x = prcl->right;
  3366. pscn->ai_x[2].x = 2; // This sets cWalls2
  3367. pscn = pscnGet(pscn);
  3368. pscn->cWalls = 0;
  3369. pscn->yTop = prcl->bottom;
  3370. pscn->yBottom = POS_INFINITY;
  3371. pscn->ai_x[0].x = 0; // This sets cWalls2
  3372. prgn1->pscnTail = pscnGet(pscn);
  3373. break;
  3374. case SR_VERT_NOTCH | SR_LEFT_NOTCH:
  3375. prgn1->sizeRgn = NULL_REGION_SIZE + 4 * NULL_SCAN_SIZE + 6 * sizeof(INDEX_LONG);
  3376. prgn1->cScans = 5;
  3377. prgn1->rcl = *prcl;
  3378. pscn = prgn1->pscnHead();
  3379. pscn->cWalls = 0;
  3380. pscn->yTop = NEG_INFINITY;
  3381. pscn->yBottom = prcl->top;
  3382. pscn->ai_x[0].x = 0; // This sets cWalls2
  3383. pscn = pscnGet(pscn);
  3384. pscn->cWalls = 2;
  3385. pscn->yTop = prcl->top;
  3386. pscn->yBottom = arcl[0].top;
  3387. pscn->ai_x[0].x = prcl->left;
  3388. pscn->ai_x[1].x = prcl->right;
  3389. pscn->ai_x[2].x = 2; // This sets cWalls2
  3390. pscn = pscnGet(pscn);
  3391. pscn->cWalls = 2;
  3392. pscn->yTop = arcl[0].top;
  3393. pscn->yBottom = arcl[0].bottom;
  3394. pscn->ai_x[0].x = arcl[0].right;
  3395. pscn->ai_x[1].x = prcl->right;
  3396. pscn->ai_x[2].x = 2; // This sets cWalls2
  3397. pscn = pscnGet(pscn);
  3398. pscn->cWalls = 2;
  3399. pscn->yTop = arcl[0].bottom;
  3400. pscn->yBottom = prcl->bottom;
  3401. pscn->ai_x[0].x = prcl->left;
  3402. pscn->ai_x[1].x = prcl->right;
  3403. pscn->ai_x[2].x = 2; // This sets cWalls2
  3404. pscn = pscnGet(pscn);
  3405. pscn->cWalls = 0;
  3406. pscn->yTop = prcl->bottom;
  3407. pscn->yBottom = POS_INFINITY;
  3408. pscn->ai_x[0].x = 0; // This sets cWalls2
  3409. prgn1->pscnTail = pscnGet(pscn);
  3410. break;
  3411. case SR_VERT_NOTCH | SR_RIGHT_NOTCH:
  3412. prgn1->sizeRgn = NULL_REGION_SIZE + 4 * NULL_SCAN_SIZE + 6 * sizeof(INDEX_LONG);
  3413. prgn1->cScans = 5;
  3414. prgn1->rcl = *prcl;
  3415. pscn = prgn1->pscnHead();
  3416. pscn->cWalls = 0;
  3417. pscn->yTop = NEG_INFINITY;
  3418. pscn->yBottom = prcl->top;
  3419. pscn->ai_x[0].x = 0; // This sets cWalls2
  3420. pscn = pscnGet(pscn);
  3421. pscn->cWalls = 2;
  3422. pscn->yTop = prcl->top;
  3423. pscn->yBottom = arcl[0].top;
  3424. pscn->ai_x[0].x = prcl->left;
  3425. pscn->ai_x[1].x = prcl->right;
  3426. pscn->ai_x[2].x = 2; // This sets cWalls2
  3427. pscn = pscnGet(pscn);
  3428. pscn->cWalls = 2;
  3429. pscn->yTop = arcl[0].top;
  3430. pscn->yBottom = arcl[0].bottom;
  3431. pscn->ai_x[0].x = prcl->left;
  3432. pscn->ai_x[1].x = arcl[0].left;
  3433. pscn->ai_x[2].x = 2; // This sets cWalls2
  3434. pscn = pscnGet(pscn);
  3435. pscn->cWalls = 2;
  3436. pscn->yTop = arcl[0].bottom;
  3437. pscn->yBottom = prcl->bottom;
  3438. pscn->ai_x[0].x = prcl->left;
  3439. pscn->ai_x[1].x = prcl->right;
  3440. pscn->ai_x[2].x = 2; // This sets cWalls2
  3441. pscn = pscnGet(pscn);
  3442. pscn->cWalls = 0;
  3443. pscn->yTop = prcl->bottom;
  3444. pscn->yBottom = POS_INFINITY;
  3445. pscn->ai_x[0].x = 0; // This sets cWalls2
  3446. prgn1->pscnTail = pscnGet(pscn);
  3447. break;
  3448. // The classic toroidal region
  3449. case SR_VERT_NOTCH | SR_HORIZ_NOTCH:
  3450. prgn1->sizeRgn = NULL_REGION_SIZE + 4 * NULL_SCAN_SIZE + 8 * sizeof(INDEX_LONG);
  3451. prgn1->cScans = 5;
  3452. prgn1->rcl = *prcl;
  3453. pscn = prgn1->pscnHead();
  3454. pscn->cWalls = 0;
  3455. pscn->yTop = NEG_INFINITY;
  3456. pscn->yBottom = prcl->top;
  3457. pscn->ai_x[0].x = 0; // This sets cWalls2
  3458. pscn = pscnGet(pscn);
  3459. pscn->cWalls = 2;
  3460. pscn->yTop = prcl->top;
  3461. pscn->yBottom = arcl[0].top;
  3462. pscn->ai_x[0].x = prcl->left;
  3463. pscn->ai_x[1].x = prcl->right;
  3464. pscn->ai_x[2].x = 2; // This sets cWalls2
  3465. pscn = pscnGet(pscn);
  3466. pscn->cWalls = 4;
  3467. pscn->yTop = arcl[0].top;
  3468. pscn->yBottom = arcl[0].bottom;
  3469. pscn->ai_x[0].x = prcl->left;
  3470. pscn->ai_x[1].x = arcl[0].left;
  3471. pscn->ai_x[2].x = arcl[0].right;
  3472. pscn->ai_x[3].x = prcl->right;
  3473. pscn->ai_x[4].x = 4; // This sets cWalls2
  3474. pscn = pscnGet(pscn);
  3475. pscn->cWalls = 2;
  3476. pscn->yTop = arcl[0].bottom;
  3477. pscn->yBottom = prcl->bottom;
  3478. pscn->ai_x[0].x = prcl->left;
  3479. pscn->ai_x[1].x = prcl->right;
  3480. pscn->ai_x[2].x = 2; // This sets cWalls2
  3481. pscn = pscnGet(pscn);
  3482. pscn->cWalls = 0;
  3483. pscn->yTop = prcl->bottom;
  3484. pscn->yBottom = POS_INFINITY;
  3485. pscn->ai_x[0].x = 0; // This sets cWalls2
  3486. prgn1->pscnTail = pscnGet(pscn);
  3487. break;
  3488. }
  3489. return(TRUE);
  3490. }
  3491. // its complex, do it the hard way
  3492. PREGION prgnOrg = prgn;
  3493. // lock the handle so no one can reference it while the pobj may be invalid
  3494. OBJLOCK ol((HOBJ) hrgn_);
  3495. BOOL b = bSubtractComplex(prcl,arcl,crcl);
  3496. if (prgn != prgnOrg)
  3497. {
  3498. PVOID pv = HmgReplace((HOBJ) hrgn_,(POBJ) prgn,0,1,OBJLOCK_TYPE);
  3499. ASSERTGDI(pv != NULL,"RGNOBJAPI::bSubtract - HmgReplace failed\n");
  3500. }
  3501. rl.vRet((ULONG_PTR)prgn);
  3502. return(b);
  3503. }
  3504. /******************************Member*Function*****************************\
  3505. * RGNOBJ::bSubtractComplex()
  3506. *
  3507. * Handle the complex cases of subtracting a list of rectangles from another
  3508. * rectangle to generate a region.
  3509. *
  3510. * The alogrithm used here requires that the list of rectangles is always
  3511. * sorted by both ytop and ybottom within the range of rectangles overlaping
  3512. * the current scan. To have both of these true, ytop refers to the max of
  3513. * ytop and the top of the current scan. There is no ordering in the
  3514. * horizontal direction. Rectangles that fall below the current scan are still
  3515. * sorted by top but not by bottom. While computing a new scan, all rectangles
  3516. * that are just being added are inserted to keep the bottoms sorted.
  3517. *
  3518. * ..................
  3519. * scan 1 top -->.+-----+ +-----+.
  3520. * .| | | |.
  3521. * .| | | |.
  3522. * .| | | |. +-----+
  3523. * ................. | |
  3524. * | | | | | |
  3525. * | | | | | |
  3526. * | | | | | |
  3527. * | | | | | |
  3528. * +-----+ | | | |
  3529. * | | | |
  3530. * | | +-----+
  3531. * | |
  3532. * +-----+
  3533. *
  3534. *
  3535. *
  3536. * +-----+ +-----+
  3537. * | | | |.
  3538. * ...........................
  3539. * scan 2 top --> .| | +-----+ | |.
  3540. * .| | | | | |.
  3541. * .| | | | | |.
  3542. * .| | | | | |.
  3543. * .| | | | | |.
  3544. * .| | | | | |.
  3545. * .+-----+ | | | |.
  3546. * ...........................
  3547. * +-----+ | |
  3548. * | |
  3549. * +-----+
  3550. *
  3551. *
  3552. * To keep this ordering, a list of pointers to rectangles is used. This reduces
  3553. * the overhead of reordering the rectangles for each scan and reduces the amount
  3554. * of temporary memory required. For each scan, iFirst and iLast bracket the
  3555. * set of rectangles intersecting the current scan.
  3556. *
  3557. * To calculate the walls of a scan, we start assuming the entire with of the
  3558. * dst rectangle and subtract from there. The left to right of each rectangle
  3559. * from iFirst to iLast is subtracted from the scan.
  3560. *
  3561. * iFirst is update to remove any rectangles that are finished after the current
  3562. * scan.
  3563. *
  3564. * iLast is updated to include any new rectangles that lie in the new scan.
  3565. *
  3566. * WARNING: If this function returns FALSE, the region may be inconsistent.
  3567. * The caller must discard or reset the region. (See bug #343770)
  3568. *
  3569. * History:
  3570. * 26-Jul-1993 -by- Eric Kutter [erick]
  3571. * Wrote it.
  3572. \**************************************************************************/
  3573. BOOL RGNOBJAPI::bSubtractComplex(
  3574. RECTL *prcl,
  3575. RECTL *arclRemove,
  3576. int crcl)
  3577. {
  3578. ASSERTGDI(crcl > 0, "Zero rectangles in RGNOBJ::bSubtract\n");
  3579. ASSERTGDI(prcl->bottom >= prcl->top," RGNOBJ::bSubtractComplex - bottom > top\n");
  3580. // allocate array for temporary storage
  3581. PRECTL aprclStack[100];
  3582. PRECTL *aprcl;
  3583. if (crcl < 100)
  3584. {
  3585. aprcl = aprclStack;
  3586. }
  3587. else
  3588. {
  3589. aprcl = (PRECTL *)PALLOCNOZ((sizeof(PRECTL) + 1) * crcl, 'ngrG');
  3590. if (aprcl == NULL)
  3591. return(FALSE);
  3592. }
  3593. // sort the array of subtraction rectangles by yTop
  3594. int iInsert;
  3595. int i;
  3596. for (i = 0; i < crcl; ++i)
  3597. {
  3598. // insert rect[i], search from the end so we don't do much in the
  3599. // case of a pre-sorted list and we do the pointer copies while we
  3600. // search backwards if it isn't sorted.
  3601. iInsert = i;
  3602. while (iInsert && (arclRemove[i].top < aprcl[iInsert-1]->top))
  3603. {
  3604. aprcl[iInsert] = aprcl[iInsert-1];
  3605. --iInsert;
  3606. }
  3607. aprcl[iInsert] = &arclRemove[i];
  3608. }
  3609. // add an extra rectangle at the end to make the end case simple
  3610. RECTL rclLast;
  3611. rclLast.left = 0;
  3612. rclLast.right = 0;
  3613. rclLast.top = prcl->bottom;
  3614. rclLast.bottom = POS_INFINITY;
  3615. aprcl[crcl] = &rclLast;
  3616. // partialy setup the first scan, allowing for coalescing of inital empty scans
  3617. PSCAN pscnOld = prgn->pscnHead();
  3618. pscnOld->cWalls = 0;
  3619. pscnOld->yTop = NEG_INFINITY;
  3620. pscnOld->yBottom = POS_INFINITY;
  3621. pscnOld->ai_x[0].x = 0;
  3622. PSCAN pscn = pscnGet(pscnOld);
  3623. prgn->sizeRgn = NULL_REGION_SIZE;
  3624. prgn->cScans = 1;
  3625. prgn->rcl.left = POS_INFINITY;
  3626. prgn->rcl.right = NEG_INFINITY;
  3627. // now do the real work, all rectangles in the range of iFirst to iLast
  3628. // are sorted by bottom. To get in this range, the rectangle must intersect
  3629. // yTop.
  3630. //
  3631. // yTop - top y value for current scan
  3632. // yBottom - bottom y value for current scan
  3633. // iFirst - index first rectangle in current scan
  3634. // iLast - one past index of last rectangle in current scan
  3635. LONG yTop = prcl->top;
  3636. LONG yBottom = prcl->bottom;
  3637. int cWalls = 0;
  3638. // throw out any easy ones
  3639. int iFirst = 0;
  3640. while (aprcl[iFirst]->bottom <= yTop)
  3641. ++iFirst;
  3642. int iLast = iFirst;
  3643. // while we still have scans
  3644. do
  3645. {
  3646. // make sure this scan is going to have enough room, also insure enough space
  3647. // for last scan. The scan will never have more walls than 2 * (num rectangles + 1)
  3648. LONG size = prgn->sizeRgn + 2 * NULL_SCAN_SIZE + 2 * sizeof(INDEX_LONG) * (crcl - iFirst + 1);
  3649. if (size > (LONG)prgn->sizeObj)
  3650. {
  3651. // not big enough, grow it and be aggresive with size because growing is
  3652. // very expensive. Also set any fields need to grow and reset the scans
  3653. // afterwards.
  3654. prgn->pscnTail = pscn;
  3655. if (!bExpand((UINT)(size + (crcl - iFirst) * (NULL_SCAN_SIZE + (crcl - iFirst) * sizeof(INDEX_LONG)))))
  3656. {
  3657. if (aprcl != aprclStack)
  3658. {
  3659. VFREEMEM(aprcl);
  3660. }
  3661. return(FALSE);
  3662. }
  3663. pscn = prgn->pscnTail;
  3664. pscnOld = pscnGot(pscn);
  3665. }
  3666. // setup the new scan, assume the entire width of prcl
  3667. cWalls = 2;
  3668. pscn->ai_x[0].x = prcl->left;
  3669. pscn->ai_x[1].x = prcl->right;
  3670. // check if we need to reduce the scan, do we have any overlapping rects?
  3671. if (aprcl[iFirst]->top > yTop)
  3672. {
  3673. // the bottom of this scan is the top of the next rectangle
  3674. yBottom = aprcl[iFirst]->top;
  3675. }
  3676. else
  3677. {
  3678. // assume the bottom is the bottom of the first rectangle
  3679. yBottom = aprcl[iFirst]->bottom;
  3680. // first find any new rectangles that fit in the new scan, and reduce
  3681. // ybottom appropriately
  3682. while (TRUE)
  3683. {
  3684. // does the next rectangle start below the current top
  3685. if (aprcl[iLast]->top > yTop)
  3686. {
  3687. // stop this scan where the next rectangle starts
  3688. if (aprcl[iLast]->top < yBottom)
  3689. yBottom = aprcl[iLast]->top;
  3690. break;
  3691. }
  3692. if (aprcl[iLast]->bottom < yBottom)
  3693. yBottom = aprcl[iLast]->bottom;
  3694. // perculate it backwards to keep the current rectangles sorted by yBottom
  3695. iInsert = iLast;
  3696. PRECTL prclTmp = aprcl[iLast];
  3697. while ((iInsert > iFirst) && (prclTmp->bottom < aprcl[iInsert-1]->bottom))
  3698. {
  3699. aprcl[iInsert] = aprcl[iInsert-1];
  3700. --iInsert;
  3701. }
  3702. // if we did some shuffling, put the rectangle in the right place.
  3703. // It is possible to have a rectangle that completely lies above
  3704. // the top of this scan if we are on the first scan and the top of
  3705. // this rectangle is greater than one before it but the bottom is
  3706. // less than the top of prcl.
  3707. if (aprcl[iInsert]->bottom <= yTop)
  3708. {
  3709. // the rectangle is completely clipped away
  3710. ASSERTGDI(iInsert == iFirst,"bSubtractComplex - iInsert != iFirst\n");
  3711. ++iFirst;
  3712. }
  3713. else
  3714. {
  3715. aprcl[iInsert] = prclTmp;
  3716. }
  3717. ++iLast;
  3718. }
  3719. // build up the scan, for each new rectangle...
  3720. for (int irc = iFirst; irc < iLast; ++irc)
  3721. {
  3722. LONG xLeft = aprcl[irc]->left;
  3723. LONG xRight = aprcl[irc]->right;
  3724. // merge it into the walls
  3725. for (int iWall = 0; iWall < cWalls; iWall += 2)
  3726. {
  3727. // the walls are before the rectangle, nothing to do yet
  3728. if (xLeft >= pscn->ai_x[iWall+1].x)
  3729. continue;
  3730. // the walls are passed the rectangle, done with this rectangle
  3731. if (xRight <= pscn->ai_x[iWall].x)
  3732. break;
  3733. // compute the overlap, update the walls
  3734. int iHit = 0;
  3735. if (xLeft <= pscn->ai_x[iWall].x)
  3736. iHit = 1;
  3737. if (xRight >= pscn->ai_x[iWall+1].x)
  3738. iHit += 2;
  3739. switch (iHit)
  3740. {
  3741. case 0:
  3742. // completely inside the walls, insert new rectangle
  3743. RtlMoveMemory(&pscn->ai_x[iWall+3],&pscn->ai_x[iWall+1],
  3744. (cWalls - iWall - 1) * sizeof(INDEX_LONG));
  3745. pscn->ai_x[iWall+1].x = xLeft;
  3746. pscn->ai_x[iWall+2].x = xRight;
  3747. cWalls += 2;
  3748. break;
  3749. case 1:
  3750. // overlapped the left wall, just update the left edge
  3751. pscn->ai_x[iWall].x = xRight;
  3752. break;
  3753. case 2:
  3754. // overlapped the right wall, just update the right edge
  3755. pscn->ai_x[iWall+1].x = xLeft;
  3756. break;
  3757. case 3:
  3758. // completely bounds the walls, remove rectangle
  3759. RtlMoveMemory(&pscn->ai_x[iWall],&pscn->ai_x[iWall+2],
  3760. (cWalls - iWall - 2) * sizeof(INDEX_LONG));
  3761. cWalls -= 2;
  3762. iWall -= 2;
  3763. break;
  3764. }
  3765. }
  3766. }
  3767. }
  3768. // make sure yBottom isn't below the original rectangle
  3769. if (yBottom > prcl->bottom)
  3770. yBottom = prcl->bottom;
  3771. // Try to coalesce the current scan with the previous scan
  3772. if (((int)pscnOld->cWalls == cWalls) &&
  3773. !memcmp(pscnOld->ai_x, pscn->ai_x,(UINT)cWalls * sizeof(INDEX_LONG)))
  3774. {
  3775. // the walls are identical to the previous scan, merge them
  3776. pscnOld->yBottom = yBottom;
  3777. }
  3778. else
  3779. {
  3780. // update the x bounds
  3781. if (cWalls)
  3782. {
  3783. if (pscn->ai_x[0].x < prgn->rcl.left)
  3784. prgn->rcl.left = pscn->ai_x[0].x;
  3785. if (pscn->ai_x[cWalls-1].x > prgn->rcl.right)
  3786. prgn->rcl.right = pscn->ai_x[cWalls-1].x;
  3787. }
  3788. // update the rest of the fields
  3789. prgn->cScans++;
  3790. pscn->cWalls = cWalls;
  3791. prgn->sizeRgn += pscn->sizeGet();
  3792. pscn->yTop = yTop;
  3793. pscn->yBottom = yBottom;
  3794. pscn->ai_x[cWalls].x = cWalls;
  3795. pscnOld = pscn;
  3796. pscn = pscnGet(pscn);
  3797. }
  3798. // trim off the finished rectangles
  3799. yTop = yBottom;
  3800. while ((iFirst < iLast) && (aprcl[iFirst]->bottom <= yTop))
  3801. ++iFirst;
  3802. } while (yBottom < prcl->bottom);
  3803. // set the top and bottom bounds and the last scan
  3804. if (prgn->cScans == 1)
  3805. {
  3806. prgn->rcl.top = 0;
  3807. prgn->rcl.bottom = 0;
  3808. prgn->rcl.left = 0;
  3809. prgn->rcl.right = 0;
  3810. pscnOld->yBottom = POS_INFINITY;
  3811. prgn->pscnTail = pscn;
  3812. }
  3813. else
  3814. {
  3815. // was the last scan empty?
  3816. if (pscnOld->cWalls == 0)
  3817. {
  3818. // combine the final scan with the last computed scan
  3819. pscn = pscnOld;
  3820. }
  3821. else
  3822. {
  3823. // set up any fields that wouldn't already be set by an empty scan
  3824. pscn->yTop = pscnOld->yBottom;
  3825. prgn->cScans++;
  3826. pscn->cWalls = 0;
  3827. pscn->ai_x[0].x = 0;
  3828. prgn->sizeRgn += pscn->sizeGet();
  3829. }
  3830. // set vertical bounds
  3831. prgn->pscnHead()->yBottom = pscnGet(prgn->pscnHead())->yTop;
  3832. prgn->rcl.top = prgn->pscnHead()->yBottom;
  3833. prgn->rcl.bottom = pscn->yTop;
  3834. // setup the other region fields
  3835. pscn->yBottom = POS_INFINITY;
  3836. prgn->pscnTail = pscnGet(pscn);
  3837. }
  3838. // if we allocated a buffer, free it
  3839. if (aprcl != aprclStack)
  3840. VFREEMEM(aprcl);
  3841. return(TRUE);
  3842. }
  3843. /******************************Public*Routine******************************\
  3844. *
  3845. * SyncRgn converts a client NULL or SIMPLE rectangle into a normal region
  3846. * for kernel operations
  3847. *
  3848. * Arguments:
  3849. *
  3850. * none
  3851. *
  3852. * Return Value:
  3853. *
  3854. * BOOL
  3855. *
  3856. * History:
  3857. *
  3858. * 22-Jun-1995 -by- Mark Enstrom [marke]
  3859. *
  3860. \**************************************************************************/
  3861. BOOL
  3862. RGNOBJ::SyncUserRgn()
  3863. {
  3864. BOOL bRet = FALSE;
  3865. RGNLOG rl(prgn,"RGNOBJ::SyncUserRgn");
  3866. if (prgn != (PREGION)NULL)
  3867. {
  3868. //
  3869. // does this fine region have valid user-mode data?
  3870. //
  3871. PRGNATTR prRegion = (PRGNATTR)(PENTRY_FROM_POBJ(prgn)->pUser);
  3872. if (prRegion != (PRGNATTR)NULL)
  3873. {
  3874. __try
  3875. {
  3876. if (prRegion->AttrFlags & ATTR_RGN_VALID)
  3877. {
  3878. if (prRegion->AttrFlags & ATTR_RGN_DIRTY)
  3879. {
  3880. if (prRegion->Flags == NULLREGION)
  3881. {
  3882. vSet();
  3883. prRegion->AttrFlags &= ~ATTR_RGN_DIRTY;
  3884. }
  3885. else if (prRegion->Flags == SIMPLEREGION)
  3886. {
  3887. vSet(&prRegion->Rect);
  3888. prRegion->AttrFlags &= ~ATTR_RGN_DIRTY;
  3889. }
  3890. }
  3891. }
  3892. else
  3893. {
  3894. WARNING("RGNOBJ::SyncUserRgn invalid rectregion\n");
  3895. }
  3896. bRet = TRUE;
  3897. }
  3898. __except(EXCEPTION_EXECUTE_HANDLER)
  3899. {
  3900. WARNING("except in RGNOBJ::SyncRgn\n");
  3901. }
  3902. }
  3903. }
  3904. return(bRet);
  3905. }
  3906. VOID
  3907. RGNOBJ::UpdateUserRgn()
  3908. {
  3909. RGNLOG rl(prgn,"RGNOBJ::UpdateUserRgn");
  3910. if (prgn != (PREGION)NULL)
  3911. {
  3912. //
  3913. // does this fine region have valid user-mode data?
  3914. //
  3915. PRGNATTR prRegion = (PRGNATTR)(PENTRY_FROM_POBJ(prgn)->pUser);
  3916. if (prRegion != (PRGNATTR)NULL)
  3917. {
  3918. //
  3919. // check for DCATTR
  3920. //
  3921. __try
  3922. {
  3923. //
  3924. // set user region complexity and bounding box
  3925. //
  3926. if (prRegion->AttrFlags & ATTR_RGN_VALID)
  3927. {
  3928. prRegion->Flags = iComplexity();
  3929. prRegion->Rect = prgn->rcl;
  3930. }
  3931. else
  3932. {
  3933. WARNING("UpdateUserRgn: Invalid region");
  3934. }
  3935. }
  3936. __except(EXCEPTION_EXECUTE_HANDLER)
  3937. {
  3938. WARNING("except in RGNOBJ::UpdateUserRgn\n");
  3939. }
  3940. }
  3941. }
  3942. }
  3943. /******************************Public*Routine******************************\
  3944. * BOOL RGNOBJ::bValidateFramedRegion()
  3945. *
  3946. * Verify the region's integrity. For debugging purposes only.
  3947. *
  3948. * History:
  3949. * 30-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  3950. * Wrote it.
  3951. \**************************************************************************/
  3952. #if DBG
  3953. #define REASONABLE 0x10000L
  3954. #define FX_REASONABLE (0x10000L << 4)
  3955. BOOL RGNOBJ::bValidateFramedRegion()
  3956. {
  3957. #ifdef DEBUGREGIONS
  3958. if (prgn == NULL)
  3959. return(TRUE); // ???
  3960. // ASSERTGDI(prgn->rcl.left <= prgn->rcl.right &&
  3961. // prgn->rcl.top <= prgn->rcl.bottom, "Funky rcl");
  3962. ASSERTGDI(prgn->pscnHead() <= prgn->pscnTail, "Funky head/tail");
  3963. ASSERTGDI(prgn->sizeRgn <= prgn->sizeObj, "sizeRgn > sizeObj");
  3964. ASSERTGDI((BYTE*) prgn->pscnTail <= (BYTE*) prgn + prgn->sizeObj,
  3965. "Tail > prgn + sizeObj");
  3966. ASSERTGDI((BYTE*) prgn->pscnTail <= (BYTE*) prgn + prgn->sizeRgn,
  3967. "Tail > prgn + sizeRgn");
  3968. // ASSERTGDI(prgn->cScans < REASONABLE, "cScans not reasonable");
  3969. ASSERTGDI(prgn->cScans >= 1, "cScans < 1");
  3970. if (prgn->cScans < 2)
  3971. return(TRUE);
  3972. COUNT cScans = prgn->cScans;
  3973. SCAN *pscn = prgn->pscnHead();
  3974. LONG yOldBottom = pscn->yBottom;
  3975. ASSERTGDI(pscn->yTop == NEG_INFINITY, "Very yTop not NEG_INFINITY");
  3976. ASSERTGDI(pscn->cWalls == 0, "Very top cWalls not 0");
  3977. ASSERTGDI(pscn->ai_x[0].x == 0, "Very top cWalls2 not 0");
  3978. // ASSERTGDI(pscn->yBottom == prgn->rcl.top, "Very top yBottom not rcl.top");
  3979. pscn = pscnGet(pscn);
  3980. cScans -= 2;
  3981. while (cScans--)
  3982. {
  3983. LONG iWall;
  3984. LONG cWalls = pscn->cWalls;
  3985. LONG yTop = pscn->yTop;
  3986. LONG yBottom = pscn->yBottom;
  3987. LONG xOld = NEG_INFINITY;
  3988. ASSERTGDI(pscn->ai_x[cWalls].x == cWalls, "cWalls1 != cWalls2");
  3989. ASSERTGDI(yTop < yBottom, "Region corrupted: yTop >= yBottom");
  3990. ASSERTGDI(yOldBottom == yTop, "Region corrupted: yOldBottom != yTop");
  3991. // ASSERTGDI(cWalls < REASONABLE, "cWalls not reasonable");
  3992. ASSERTGDI((cWalls & 1) == 0, "cWalls not even");
  3993. // ASSERTGDI(yTop > -REASONABLE && yTop < REASONABLE,
  3994. // "yTop not reasonable");
  3995. // ASSERTGDI(yBottom > -REASONABLE && yBottom < REASONABLE,
  3996. // "yBottom not reasonable");
  3997. for (iWall = 0; iWall != cWalls; iWall++)
  3998. {
  3999. LONG x = xGet(pscn, (PTRDIFF) iWall);
  4000. // Framed regions make things look weird:
  4001. if (x > MAX_REGION_COORD)
  4002. x -= REGION_FRAMED_OFFSET;
  4003. ASSERTGDI(VALID_SCR(x), "Region corrupted: Invalid x");
  4004. if (x <= xOld)
  4005. DbgPrint("x <= xOld - pscn = %p, iWall = %lx\n",pscn,iWall);
  4006. // ASSERTGDI(x > xOld, "Region corrupted: x <= xOld");
  4007. // ASSERTGDI(x > -REASONABLE && x < REASONABLE, "x not reasonable");
  4008. xOld = x;
  4009. }
  4010. // if (cWalls > 0)
  4011. // {
  4012. // ASSERTGDI(xGet(pscn, (PTRDIFF) 0) >= (prgn->rcl.left - 1),
  4013. // "x < rcl.left");
  4014. // ASSERTGDI(xGet(pscn, (PTRDIFF) (cWalls - 1)) <= (prgn->rcl.right + 1),
  4015. // "x > rcl.right");
  4016. // }
  4017. yOldBottom = yBottom;
  4018. pscn = pscnGet(pscn);
  4019. ASSERTGDI(pscn > prgn->pscnHead() && pscn <= prgn->pscnTail,
  4020. "pscn out of bounds");
  4021. // ASSERTGDI(prgn->rcl.top <= (yBottom + 1) && prgn->rcl.bottom >= (yBottom - 1),
  4022. // "yBottom not in rcl");
  4023. }
  4024. ASSERTGDI(pscn->yBottom == POS_INFINITY, "Very yBottom not POS_INFINITY");
  4025. ASSERTGDI(pscn->cWalls == 0, "Very bottom cWalls not 0");
  4026. ASSERTGDI(pscn->ai_x[0].x == 0, "Very bottom cWalls2 not 0");
  4027. //ASSERTGDI(pscn->yTop == prgn->rcl.bottom, "Very bottom yTop not rcl.bottom");
  4028. #endif
  4029. return(TRUE);
  4030. }
  4031. #endif