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.

3375 lines
87 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: rgngdi.cxx
  3. *
  4. * GDI Region calls
  5. *
  6. * Created: 30-Aug-1990 10:21:11
  7. * Author: Donald Sidoroff [donalds]
  8. *
  9. * Copyright (c) 1990-1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. extern PBRUSH gpbrNull;
  13. #if DBG
  14. extern ULONG dbgrgn;
  15. #endif
  16. // Tracing defines for traces that should ignore class
  17. #define GDITE_GreCreatePolyPolygonRgnInternal_return \
  18. (GDITE_GreCreatePolyPolygonRgnInternal|GDITF_IGNORE_CLASS)
  19. #define GDITE_GreCreateRectRgn_return \
  20. (GDITE_GreCreateRectRgn|GDITF_IGNORE_CLASS)
  21. #define GDITE_GreCreateRectRgnIndirect_return \
  22. (GDITE_GreCreateRectRgnIndirect|GDITF_IGNORE_CLASS)
  23. #define GDITE_GreExtCreateRegion_return \
  24. (GDITE_GreExtCreateRegion|GDITF_IGNORE_CLASS)
  25. #define GDITE_NtGdiCreateEllipticRgn_return \
  26. (GDITE_NtGdiCreateEllipticRgn|GDITF_IGNORE_CLASS)
  27. #define GDITE_NtGdiCreateRectRgn_return \
  28. (GDITE_NtGdiCreateRectRgn|GDITF_IGNORE_CLASS)
  29. #define GDITE_NtGdiCreateRoundRectRgn_return \
  30. (GDITE_NtGdiCreateRoundRectRgn|GDITF_IGNORE_CLASS)
  31. /******************************Public*Routine******************************\
  32. * BOOL bDeleteRegion(HRGN)
  33. *
  34. * Delete the specified region
  35. *
  36. * History:
  37. * 17-Sep-1990 -by- Donald Sidoroff [donalds]
  38. * Wrote it.
  39. \**************************************************************************/
  40. BOOL bDeleteRegion(HRGN hrgn)
  41. {
  42. RGNLOG rl(hrgn,NULL,"bDeleteRegion",0,0,0);
  43. RGNOBJAPI ro(hrgn,FALSE);
  44. return(ro.bValid() &&
  45. (ro.cGet_cRefs() == 0) &&
  46. ro.bDeleteRGNOBJAPI());
  47. }
  48. /***************************Exported*Routine****************************\
  49. * BOOL GreSetRegionOwner(hrgn,lPid)
  50. *
  51. * Assigns a new owner to the given region. This function should be as
  52. * fast as possible so that the USER component can call it often without
  53. * concern for performance!
  54. *
  55. \***********************************************************************/
  56. BOOL
  57. GreSetRegionOwner(
  58. HRGN hrgn,
  59. W32PID lPid)
  60. {
  61. RGNLOG rl(hrgn,NULL,"GreSetRegionOwner",W32GetCurrentPID(),0,0);
  62. //
  63. // Setting a region to public, the region must not have
  64. // a user mode component
  65. //
  66. #if DBG
  67. RGNOBJAPI ro(hrgn,TRUE);
  68. if (ro.bValid())
  69. {
  70. if (PENTRY_FROM_POBJ(ro.prgn)->pUser != NULL)
  71. {
  72. RIP("Error: setting region public that has user component");
  73. }
  74. }
  75. #endif
  76. //
  77. // Get the current PID.
  78. //
  79. if (lPid == OBJECT_OWNER_CURRENT)
  80. {
  81. lPid = W32GetCurrentPID();
  82. }
  83. return HmgSetOwner((HOBJ)hrgn, lPid, RGN_TYPE);
  84. }
  85. /******************************Public*Routine******************************\
  86. * CLIPOBJ *EngCreateClip()
  87. *
  88. * Create a long live clipping object for a driver
  89. *
  90. * History:
  91. * 22-Sep-1992 -by- Donald Sidoroff [donalds]
  92. * Wrote it.
  93. \**************************************************************************/
  94. CLIPOBJ *EngCreateClip()
  95. {
  96. //
  97. // Note that we intentionally zero this memory on allocation. Even though
  98. // we're going to set some of these fields to non-zero values right away,
  99. // this is not a performance-critical function (a driver typically calls
  100. // this only once), and we save a lot of instruction bytes by not having to
  101. // zero a number of fields explicitly.
  102. //
  103. VOID *pv = EngAllocMem(FL_ZERO_MEMORY,
  104. sizeof(ECLIPOBJ) + SINGLE_REGION_SIZE,
  105. 'vrdG');
  106. if (pv != NULL)
  107. {
  108. //
  109. // Make this a CLIPOBJ that doesn't clip anything.
  110. //
  111. ((ECLIPOBJ *) pv)->iDComplexity = DC_TRIVIAL;
  112. ((ECLIPOBJ *) pv)->iFComplexity = FC_RECT;
  113. ((ECLIPOBJ *) pv)->iMode = TC_RECTANGLES;
  114. REGION *prgn = (REGION*)((PBYTE)pv + sizeof(ECLIPOBJ));
  115. ((ECLIPOBJ *) pv)->prgn = prgn;
  116. RGNOBJ ro(prgn);
  117. RECTL r;
  118. r.left = r.top = MIN_REGION_COORD;
  119. r.right = r.bottom = MAX_REGION_COORD;
  120. ro.vSet(&r);
  121. }
  122. return((CLIPOBJ *)pv);
  123. }
  124. /******************************Public*Routine******************************\
  125. * VOID EngDeleteClip()
  126. *
  127. * Delete a long live clipping object for a driver
  128. *
  129. * History:
  130. * 22-Sep-1992 -by- Donald Sidoroff [donalds]
  131. * Wrote it.
  132. \**************************************************************************/
  133. VOID EngDeleteClip(CLIPOBJ *pco)
  134. {
  135. if (pco == NULL)
  136. {
  137. WARNING("Driver calling to free NULL clipobj");
  138. }
  139. else
  140. {
  141. ASSERTGDI(pco->iUniq == 0, "Non-zero iUniq\n");
  142. }
  143. //
  144. // We call EngFreeMem since some drivers like to free non-existant
  145. // Clip Objects.
  146. //
  147. EngFreeMem((PVOID)pco);
  148. }
  149. /******************************Public*Routine******************************\
  150. * ASSERTDEVLOCK()
  151. *
  152. * This validates that the thread using the DC has the devlock as well.
  153. *
  154. * History:
  155. * 24-Jan-1995 -by- Eric Kutter [erick]
  156. * Wrote it.
  157. \**************************************************************************/
  158. #if DBG
  159. VOID ASSERTDEVLOCK(PDC pdc)
  160. {
  161. return;
  162. if (pdc->fs() & DC_SYNCHRONIZEACCESS)
  163. {
  164. ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(pdc->hsemDcDevLock_),
  165. "ASSERTDEVLOCK: wrong id\n");
  166. }
  167. }
  168. #endif
  169. /******************************Public*Routine******************************\
  170. * LONG GreCombineRgn(hrgnTrg,hrgnSrc1,hrgnSrc2,iMode)
  171. *
  172. * Combine the two source regions by the given mode. The result is placed
  173. * in the target. Note that either (or both sources) may be the same as
  174. * the target.
  175. *
  176. \**************************************************************************/
  177. int APIENTRY GreCombineRgn(
  178. HRGN hrgnTrg,
  179. HRGN hrgnSrc1,
  180. HRGN hrgnSrc2,
  181. int iMode)
  182. {
  183. GDITraceHandle3(GreCombineRgn, "(%X, %X, %X, %d)\n", (va_list)&hrgnTrg,
  184. hrgnTrg, hrgnSrc1, hrgnSrc2);
  185. RGNLOG rl(hrgnTrg,NULL,"GreCombineRgn",(ULONG_PTR)hrgnSrc1,(ULONG_PTR)hrgnSrc2,iMode);
  186. LONG Status;
  187. if ((iMode < RGN_MIN) || (iMode > RGN_MAX))
  188. {
  189. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  190. return ERROR;
  191. }
  192. //
  193. // Check if a simple copy is to be performed.
  194. //
  195. if (iMode == RGN_COPY)
  196. {
  197. RGNOBJAPI roTrg(hrgnTrg,FALSE);
  198. RGNOBJAPI roSrc1(hrgnSrc1,TRUE);
  199. //
  200. // if either of these regions have a client rectangle, then set the
  201. // km region
  202. //
  203. if (!roTrg.bValid() || !roSrc1.bValid() || !roTrg.bCopy(roSrc1))
  204. {
  205. if (!roSrc1.bValid() || !roTrg.bValid())
  206. {
  207. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  208. }
  209. Status = ERROR;
  210. }
  211. else
  212. {
  213. Status = roTrg.iComplexity();
  214. }
  215. }
  216. else if (SAMEHANDLE(hrgnTrg, hrgnSrc1) || SAMEHANDLE(hrgnTrg, hrgnSrc2))
  217. {
  218. // Two of the handles are the same. Check to determine if all three
  219. // handles are the same.
  220. if (SAMEHANDLE(hrgnSrc1, hrgnSrc2))
  221. {
  222. RGNOBJAPI roTrg(hrgnTrg,FALSE);
  223. if (!roTrg.bValid())
  224. {
  225. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  226. Status = ERROR;
  227. }
  228. else
  229. {
  230. if ((iMode == RGN_DIFF) || (iMode == RGN_XOR))
  231. {
  232. roTrg.vSet();
  233. }
  234. Status = roTrg.iComplexity();
  235. }
  236. }
  237. else
  238. {
  239. //
  240. // All three handles are not the same.
  241. //
  242. // Also, Src1 or Src2 could be the actual
  243. // destination so don't use TRUE on the
  244. // RGNOBJAPI contructor
  245. //
  246. RGNMEMOBJTMP rmo((BOOL)FALSE);
  247. RGNOBJAPI roSrc1(hrgnSrc1,FALSE);
  248. RGNOBJAPI roSrc2(hrgnSrc2,FALSE);
  249. if (!rmo.bValid() ||
  250. !roSrc1.bValid() ||
  251. !roSrc2.bValid() ||
  252. (rmo.iCombine(roSrc1, roSrc2, iMode) == ERROR))
  253. {
  254. if (!roSrc1.bValid() || !roSrc2.bValid())
  255. {
  256. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  257. }
  258. Status = ERROR;
  259. }
  260. else if (SAMEHANDLE(hrgnTrg, hrgnSrc1))
  261. {
  262. if (!roSrc1.bSwap(&rmo))
  263. {
  264. Status = ERROR;
  265. }
  266. else
  267. {
  268. Status = roSrc1.iComplexity();
  269. }
  270. }
  271. else
  272. {
  273. if (!roSrc2.bSwap(&rmo))
  274. {
  275. Status = ERROR;
  276. }
  277. else
  278. {
  279. Status = roSrc2.iComplexity();
  280. }
  281. }
  282. }
  283. }
  284. else
  285. {
  286. // Handle the general case.
  287. RGNOBJAPI roSrc1(hrgnSrc1,TRUE);
  288. RGNOBJAPI roSrc2(hrgnSrc2,TRUE);
  289. RGNOBJAPI roTrg(hrgnTrg,FALSE);
  290. if (!roSrc1.bValid() ||
  291. !roSrc2.bValid() ||
  292. !roTrg.bValid() ||
  293. (roTrg.iCombine(roSrc1, roSrc2, iMode) == ERROR))
  294. {
  295. if (!roSrc1.bValid() || !roSrc2.bValid() || !roTrg.bValid())
  296. {
  297. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  298. }
  299. Status = ERROR;
  300. }
  301. else
  302. {
  303. Status = roTrg.iComplexity();
  304. }
  305. }
  306. return (int)Status;
  307. }
  308. /******************************Public*Routine******************************\
  309. * HRGN NtGdiCreateEllipticRgn(xLeft,yTop,xRight,yBottom)
  310. *
  311. * Create an elliptical region.
  312. *
  313. \**************************************************************************/
  314. HRGN
  315. APIENTRY NtGdiCreateEllipticRgn(
  316. int xLeft,
  317. int yTop,
  318. int xRight,
  319. int yBottom)
  320. {
  321. GDITrace(NtGdiCreateEllipticRgn, "(%d, %d, %d, %d)\n", (va_list)&xLeft);
  322. HRGN hrgn;
  323. PATHMEMOBJ pmo;
  324. if (!pmo.bValid())
  325. {
  326. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  327. return((HRGN) 0);
  328. }
  329. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  330. if (!VALID_SCRPRC((RECTL *) &ercl))
  331. {
  332. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  333. return((HRGN) 0);
  334. }
  335. // Handle the PS_INSIDEFRAME pen attribute and lower-right exclusion
  336. // by adjusting the box now. And set the flag that this will be an
  337. // ellipse, to fill it nice:
  338. EBOX ebox(ercl, TRUE);
  339. if (ebox.bEmpty())
  340. {
  341. RGNMEMOBJ rmoEmpty;
  342. if (rmoEmpty.bValid())
  343. {
  344. hrgn = rmoEmpty.hrgnAssociate();
  345. if (hrgn == (HRGN)0)
  346. {
  347. rmoEmpty.bDeleteRGNOBJ();
  348. }
  349. }
  350. else
  351. {
  352. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  353. hrgn = (HRGN) 0;
  354. }
  355. }
  356. else if (!bEllipse(pmo, ebox) || !pmo.bFlatten())
  357. {
  358. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  359. hrgn = (HRGN)0;
  360. }
  361. else
  362. {
  363. RGNMEMOBJ rmo(pmo); // convert path to region (ALTERNATE)
  364. if (rmo.bValid())
  365. {
  366. rmo.vTighten();
  367. hrgn = rmo.hrgnAssociate();
  368. if (hrgn == (HRGN)0)
  369. {
  370. rmo.bDeleteRGNOBJ();
  371. }
  372. }
  373. else
  374. {
  375. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  376. hrgn = (HRGN) 0;
  377. }
  378. }
  379. GDITrace(NtGdiCreateEllipticRgn_return, "(%X)\n", (va_list)&hrgn);
  380. return(hrgn);
  381. }
  382. /******************************Public*Routine******************************\
  383. * HRGN GreCreatePolyPolygonRgn(aptl,acptl,cPoly,iFill)
  384. *
  385. * Create a polygonal region with multiple, disjoint polygons.
  386. *
  387. \**************************************************************************/
  388. HRGN
  389. APIENTRY
  390. GreCreatePolyPolygonRgnInternal(
  391. CONST POINT *aptl,
  392. CONST INT *acptl,
  393. int cPoly,
  394. int iFill,
  395. UINT cMaxPoints)
  396. {
  397. GDITrace(GreCreatePolyPolygonRgnInternal, "(%p, %p, %d, %d, %u)\n",
  398. (va_list)&aptl);
  399. HRGN hrgn = NULL;
  400. if ((iFill == ALTERNATE) || (iFill == WINDING))
  401. {
  402. PATHMEMOBJ pmo;
  403. if (pmo.bValid())
  404. {
  405. EXFORMOBJ exfo(IDENTITY);
  406. ASSERTGDI(exfo.bValid(), "Can\'t make IDENTITY matrix!\n");
  407. if (bPolyPolygon(pmo,
  408. exfo,
  409. (PPOINTL) aptl,
  410. (PLONG) acptl,
  411. cPoly,
  412. cMaxPoints))
  413. {
  414. RGNMEMOBJ rmo(pmo, iFill); // convert path to region
  415. if (rmo.bValid())
  416. {
  417. hrgn = rmo.hrgnAssociate();
  418. if (hrgn == (HRGN)0)
  419. {
  420. rmo.bDeleteRGNOBJ();
  421. }
  422. }
  423. }
  424. }
  425. }
  426. GDITrace(GreCreatePolyPolygonRgnInternal_return, "(%X)\n", (va_list)&hrgn);
  427. return(hrgn);
  428. }
  429. /******************************Public*Routine******************************\
  430. * HRGN GreCreateRectRgn(xLeft,yTop,xRight,yBottom)
  431. *
  432. * Create a rectangular region.
  433. *
  434. * Called only from user
  435. *
  436. \**************************************************************************/
  437. HRGN APIENTRY GreCreateRectRgn(
  438. int xLeft,
  439. int yTop,
  440. int xRight,
  441. int yBottom)
  442. {
  443. GDITrace(GreCreateRectRgn, "(%d, %d, %d, %d)\n", (va_list)&xLeft);
  444. RGNLOG rl((PREGION)NULL,"GreCreateRectRgn");
  445. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  446. if (!VALID_SCRPRC((RECTL *) &ercl))
  447. {
  448. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  449. return((HRGN) 0);
  450. }
  451. RGNMEMOBJ rmo((BOOL)FALSE);
  452. HRGN hrgn;
  453. if (!rmo.bValid())
  454. {
  455. hrgn = (HRGN) 0;
  456. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  457. }
  458. else
  459. {
  460. #if NOREORDER_RGN
  461. //
  462. // reduce region if coordinates are not well ordered
  463. //
  464. if ((xLeft > xRigth) || (yTop > yBottom))
  465. {
  466. WARNING("GreCreateRectRgn: region not well ordered");
  467. xLeft = 0;
  468. yTop = 0;
  469. xRight = 0;
  470. yBottom = 0;
  471. }
  472. #else
  473. //
  474. // Make the rectangle well ordered.
  475. //
  476. ercl.vOrder();
  477. #endif
  478. rmo.vSet((RECTL *) &ercl);
  479. hrgn = (HRGN)HmgInsertObject(rmo.prgnGet(),HMGR_MAKE_PUBLIC,RGN_TYPE);
  480. if (hrgn == (HRGN)0)
  481. {
  482. rmo.bDeleteRGNOBJ();
  483. }
  484. }
  485. rl.vRet((ULONG_PTR)hrgn);
  486. GDITrace(GreCreateRectRgn_return, "(%X)\n", (va_list)&hrgn);
  487. return(hrgn);
  488. }
  489. /******************************Public*Routine******************************\
  490. *
  491. * NtGdiCreateRectRgn is the same as GreCreateRectRgn except an additional
  492. * argument is passed in, a shared RECTREGION pointer. This pointer must be
  493. * put into the shared pointer filed of the handle table for the RGN
  494. * created. This allows fast user-mode access to RECT regions.
  495. *
  496. * Arguments:
  497. *
  498. * xLeft - left edge of region
  499. * yTop - top edge of region
  500. * xRight - right edge of region
  501. * yBottom - bottom edge of region
  502. * pRectRegion - pointer to user-mode data
  503. *
  504. * Return Value:
  505. *
  506. * new HRGN or NULL
  507. *
  508. * History:
  509. *
  510. * 20-Jun-1995 -by- Mark Enstrom [marke]
  511. *
  512. \**************************************************************************/
  513. HRGN APIENTRY
  514. NtGdiCreateRectRgn(
  515. int xLeft,
  516. int yTop,
  517. int xRight,
  518. int yBottom
  519. )
  520. {
  521. GDITrace(NtGdiCreateRectRgn, "(%d, %d, %d, %d)\n", (va_list)&xLeft);
  522. RGNLOG rl((PREGION)NULL,"GreCreateRectRgn");
  523. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  524. if (!VALID_SCRPRC((RECTL *) &ercl))
  525. {
  526. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  527. return((HRGN) 0);
  528. }
  529. PVOID pRgnattr = (PRGNATTR)HmgAllocateObjectAttr();
  530. HRGN hrgn;
  531. if (pRgnattr == NULL)
  532. {
  533. //
  534. // memory alloc error
  535. //
  536. hrgn = (HRGN) 0;
  537. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  538. }
  539. else
  540. {
  541. RGNMEMOBJ rmo((BOOL)FALSE);
  542. if (!rmo.bValid())
  543. {
  544. hrgn = (HRGN) 0;
  545. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  546. }
  547. else
  548. {
  549. //
  550. // Make the rectangle well ordered.
  551. //
  552. ercl.vOrder();
  553. rmo.vSet((RECTL *) &ercl);
  554. //
  555. // allocate an object for this region, set
  556. // the shared pointer if needed
  557. //
  558. #if DBG
  559. RGNLOG rl(rmo.prgn,"RGNOBJ::hrgnAssociate");
  560. hrgn = (HRGN)HmgInsertObject(rmo.prgn,HMGR_ALLOC_LOCK,RGN_TYPE);
  561. rl.vRet((ULONG_PTR)hrgn);
  562. #else
  563. hrgn = (HRGN)HmgInsertObject(rmo.prgn,HMGR_ALLOC_LOCK,RGN_TYPE);
  564. #endif
  565. if (hrgn == (HRGN)0)
  566. {
  567. rmo.bDeleteRGNOBJ();
  568. HmgFreeObjectAttr((POBJECTATTR)pRgnattr);
  569. }
  570. else
  571. {
  572. //
  573. // set shared rect region pointer and unlock
  574. //
  575. PENTRY_FROM_POBJ(rmo.prgn)->pUser = (PDC_ATTR)pRgnattr;
  576. DEC_EXCLUSIVE_REF_CNT(rmo.prgn);
  577. }
  578. }
  579. }
  580. rl.vRet((ULONG_PTR)hrgn);
  581. GDITrace(NtGdiCreateRectRgn_return, "(%X)\n", (va_list)&hrgn);
  582. return(hrgn);
  583. }
  584. /******************************Public*Routine******************************\
  585. * HRGN GreCreateRectRgnIndirect(prcl)
  586. *
  587. * Create a rectangular region.
  588. *
  589. \**************************************************************************/
  590. HRGN APIENTRY GreCreateRectRgnIndirect(LPRECT prcl)
  591. {
  592. GDITrace(GreCreateRectRgnIndirect, "(%p)\n", (va_list)&prcl);
  593. RGNLOG rl((PREGION)NULL,"GreCreateRectRgnIndirect",prcl->left,prcl->top,prcl->right);
  594. if ((prcl == (LPRECT) NULL) || !VALID_SCRPRC(prcl))
  595. {
  596. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  597. return((HRGN) 0);
  598. }
  599. RGNMEMOBJ rmo((BOOL)FALSE);
  600. HRGN hrgn;
  601. if (!rmo.bValid())
  602. {
  603. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  604. hrgn = (HRGN) 0;
  605. }
  606. else
  607. {
  608. ((ERECTL *) prcl)->vOrder(); // Make the rectangle well ordered.
  609. rmo.vSet((RECTL *) prcl);
  610. hrgn = rmo.hrgnAssociate();
  611. if (hrgn == (HRGN)0)
  612. {
  613. rmo.bDeleteRGNOBJ();
  614. }
  615. }
  616. rl.vRet((ULONG_PTR)hrgn);
  617. GDITrace(GreCreateRectRgnIndirect_return, "(%X)\n", (va_list)&hrgn);
  618. return(hrgn);
  619. }
  620. HRGN
  621. APIENTRY
  622. NtGdiCreateRoundRectRgn(
  623. int xLeft,
  624. int yTop,
  625. int xRight,
  626. int yBottom,
  627. int xWidth,
  628. int yHeight
  629. )
  630. {
  631. GDITrace(NtGdiCreateRoundRectRgn, "(%d, %d, %d, %d, %d, %d)\n",
  632. (va_list)&xLeft);
  633. PATHMEMOBJ pmo;
  634. if (!pmo.bValid())
  635. {
  636. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  637. return((HRGN) 0);
  638. }
  639. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  640. if (!VALID_SCRPRC((RECTL *) &ercl))
  641. {
  642. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  643. return((HRGN) 0);
  644. }
  645. // Handle the PS_INSIDEFRAME pen attribute and lower-right exclusion
  646. // by adjusting the box now. And set the flag that this will be an
  647. // ellipse, to fill it nice:
  648. EBOX ebox(ercl, TRUE);
  649. HRGN hrgn;
  650. if (ebox.bEmpty())
  651. {
  652. RGNMEMOBJ rmoEmpty;
  653. if (rmoEmpty.bValid())
  654. {
  655. hrgn = rmoEmpty.hrgnAssociate();
  656. if (hrgn == (HRGN)0)
  657. {
  658. rmoEmpty.bDeleteRGNOBJ();
  659. }
  660. }
  661. else
  662. {
  663. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  664. hrgn = (HRGN)0;
  665. }
  666. }
  667. else if (!bRoundRect(pmo, ebox, xWidth, yHeight) || !pmo.bFlatten())
  668. {
  669. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  670. hrgn = (HRGN)0;
  671. }
  672. else
  673. {
  674. RGNMEMOBJ rmo(pmo); // convert path to region (ALTERNATE)
  675. if (rmo.bValid())
  676. {
  677. rmo.vTighten();
  678. hrgn = rmo.hrgnAssociate();
  679. if (hrgn == (HRGN)0)
  680. {
  681. rmo.bDeleteRGNOBJ();
  682. }
  683. }
  684. else
  685. {
  686. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  687. hrgn = (HRGN)0;
  688. }
  689. }
  690. GDITrace(NtGdiCreateRoundRectRgn_return, "(%X)\n", (va_list)&hrgn);
  691. return(hrgn);
  692. }
  693. /******************************Public*Routine******************************\
  694. * NtGdiEqualRgn()
  695. *
  696. * Check if the two regions are equal.
  697. *
  698. \**************************************************************************/
  699. BOOL
  700. APIENTRY
  701. NtGdiEqualRgn(
  702. HRGN hrgn1,
  703. HRGN hrgn2
  704. )
  705. {
  706. GDITraceHandle2(NtGdiEqualRgn, "(%X, %X)\n", (va_list)&hrgn1, hrgn1, hrgn2);
  707. BOOL bRet = ERROR;
  708. RGNOBJAPI roSrc1(hrgn1,TRUE);
  709. RGNOBJAPI roSrc2(hrgn2,TRUE);
  710. if (roSrc1.bValid() && roSrc2.bValid())
  711. {
  712. bRet = roSrc1.bEqual(roSrc2);
  713. }
  714. return (bRet);
  715. }
  716. /******************************Public*Routine******************************\
  717. * BOOL GreFillRgn (hdc,hrgn,hbrush,pac)
  718. *
  719. * Paint the region with the specified brush.
  720. *
  721. \**************************************************************************/
  722. BOOL NtGdiFillRgn(
  723. HDC hdc,
  724. HRGN hrgn,
  725. HBRUSH hbrush
  726. )
  727. {
  728. GDITraceHandle3(NtGdiFillRgn, "(%X, %X, %X)\n", (va_list)&hdc,
  729. hdc, hrgn, hbrush);
  730. BOOL bRet = FALSE;
  731. DCOBJ dco(hdc);
  732. BOOL bXform;
  733. PREGION prgnOrg;
  734. if (dco.bValid())
  735. {
  736. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  737. // We may have to scale/rotate the incoming region.
  738. bXform = !dco.pdc->bWorldToDeviceIdentity();
  739. RGNOBJAPI ro(hrgn,FALSE);
  740. if (ro.bValid())
  741. {
  742. if (bXform)
  743. {
  744. PATHMEMOBJ pmo;
  745. if (!pmo.bValid())
  746. {
  747. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  748. return(FALSE);
  749. }
  750. if (!exo.bValid() || !ro.bCreate(pmo, &exo))
  751. return(FALSE);
  752. ASSERTGDI(pmo.bValid(),"GreFillRgn - pmo not valid\n");
  753. RGNMEMOBJ rmo(pmo);
  754. if (!rmo.bValid())
  755. {
  756. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  757. return(FALSE);
  758. }
  759. // this replaces the prgn in ro with the new prgn. The ro destructor will
  760. // unlock the handle for hrgn. We must first delete the prgn though.
  761. prgnOrg = ro.prgnGet();
  762. ro.vSetRgn(rmo.prgnGet());
  763. }
  764. // If region is null, return TRUE
  765. if (ro.iComplexity() != NULLREGION)
  766. {
  767. // Accumulate bounds. We can do this before knowing if the operation is
  768. // successful because bounds can be loose.
  769. ERECTL ercl(0, 0, 0, 0);
  770. ro.vGet_rcl((RECTL *) &ercl);
  771. if (dco.fjAccum())
  772. dco.vAccumulate(ercl);
  773. if (dco.bHasSurface())
  774. {
  775. dco.pdc->prgnAPI(ro.prgnGet()); // Dirties rgnRao
  776. DEVLOCKOBJ dlo(dco);
  777. SURFACE *pSurf = dco.pSurface();
  778. if (!dlo.bValid())
  779. {
  780. bRet = dco.bFullScreen();
  781. }
  782. else
  783. {
  784. ercl += dco.eptlOrigin(); // So we know where to draw
  785. // Compute the clipping complexity and maybe reduce the exclusion rectangle.
  786. ECLIPOBJ eco(dco.prgnEffRao(), ercl);
  787. if (eco.erclExclude().bEmpty())
  788. {
  789. bRet = TRUE;
  790. }
  791. else
  792. {
  793. XEPALOBJ epal(pSurf->ppal());
  794. XEPALOBJ epalDC(dco.ppal());
  795. PDEVOBJ pdo(pSurf->hdev());
  796. EBRUSHOBJ ebo;
  797. PBRUSH pbrush = (BRUSH *)HmgShareCheckLock((HOBJ)hbrush,
  798. BRUSH_TYPE);
  799. bRet = FALSE; // assume we won't succeed
  800. //
  801. // Substitute the NULL brush if this brush handle
  802. // couldn't be locked.
  803. //
  804. if (pbrush != NULL)
  805. {
  806. //
  807. // in case the brush is cached and the color has changed
  808. //
  809. bSyncBrushObj(pbrush);
  810. ebo.vInitBrush(dco.pdc,
  811. pbrush,
  812. epalDC,
  813. epal,
  814. pSurf);
  815. ebo.pColorAdjustment(dco.pColorAdjustment());
  816. if (!pbrush->bIsNull())
  817. {
  818. // Exclude the pointer.
  819. DEVEXCLUDEOBJ dxo(dco,&eco.erclExclude(),&eco);
  820. // Get and compute the correct mix mode.
  821. MIX mix = ebo.mixBest(dco.pdc->jROP2(),
  822. dco.pdc->jBkMode());
  823. // Inc the target surface uniqueness
  824. INC_SURF_UNIQ(pSurf);
  825. // Issue a call to Paint.
  826. EngPaint(
  827. pSurf->pSurfobj(),
  828. &eco,
  829. &ebo,
  830. &dco.pdc->ptlFillOrigin(),
  831. mix);
  832. bRet = TRUE;
  833. }
  834. DEC_SHARE_REF_CNT_LAZY0(pbrush);
  835. }
  836. }
  837. }
  838. dco.pdc->prgnAPI((PREGION) NULL); // Dirties rgnRao
  839. }
  840. else
  841. {
  842. bRet = TRUE;
  843. }
  844. }
  845. else
  846. {
  847. bRet = TRUE;
  848. }
  849. if (bXform)
  850. {
  851. // need to delete the temporary one and put the old one back in so
  852. // the handle gets unlocked
  853. ro.prgnGet()->vDeleteREGION();
  854. ro.vSetRgn(prgnOrg);
  855. }
  856. }
  857. }
  858. return(bRet);
  859. }
  860. /******************************Public*Routine******************************\
  861. * BOOL GreFrameRgn (hdc,hrgn,hbrush,xWidth,yHeight,pac)
  862. *
  863. * Frame the region and fill with the specified brush.
  864. *
  865. \**************************************************************************/
  866. BOOL APIENTRY NtGdiFrameRgn(
  867. HDC hdc,
  868. HRGN hrgn,
  869. HBRUSH hbrush,
  870. int xWidth,
  871. int yHeight
  872. )
  873. {
  874. GDITraceHandle3(NtGdiFrameRgn, "(%X, %X, %X, %d, %d)\n", (va_list)&hdc,
  875. hdc, hrgn, hbrush);
  876. DCOBJ dco(hdc);
  877. RGNOBJAPI ro(hrgn,TRUE);
  878. BOOL bRet = FALSE;
  879. //
  880. // Take the absolute value just like Win3 does:
  881. //
  882. xWidth = ABS(xWidth);
  883. yHeight = ABS(yHeight);
  884. //
  885. // do some validation
  886. //
  887. if (dco.bValid() &&
  888. ro.bValid() &&
  889. (xWidth > 0) &&
  890. (yHeight > 0))
  891. {
  892. if (ro.iComplexity() == NULLREGION)
  893. {
  894. bRet = TRUE;
  895. }
  896. else
  897. {
  898. //
  899. // Convert the region to a path, scaling/rotating it as we do so.
  900. //
  901. PATHMEMOBJ pmoSpine;
  902. PATHMEMOBJ pmoWide;
  903. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  904. ASSERTGDI(exo.bValid(), "Non valid xform");
  905. if (pmoSpine.bValid() && pmoWide.bValid())
  906. {
  907. if (ro.bCreate(pmoSpine, &exo))
  908. {
  909. EXFORMOBJ exoWiden;
  910. LINEATTRS la;
  911. MATRIX mx;
  912. exoWiden.vInit(&mx, DONT_COMPUTE_FLAGS);
  913. //
  914. // Initialize line attributes and xform from DC's xform:
  915. //
  916. pmoSpine.vWidenSetupForFrameRgn(dco, xWidth, yHeight, &exoWiden, &la);
  917. //
  918. // Make sure we won't expand out of device space before we
  919. // widen:
  920. //
  921. if (pmoWide.bComputeWidenedBounds(pmoSpine, (XFORMOBJ*) &exoWiden, &la) &&
  922. pmoWide.bWiden(pmoSpine, (XFORMOBJ*) &exoWiden, &la))
  923. {
  924. //
  925. // Now convert the widened result back into a region:
  926. //
  927. RGNMEMOBJTMP rmoFill(pmoWide, WINDING);
  928. RGNMEMOBJTMP rmoFrame;
  929. if (rmoFill.bValid() &&
  930. rmoFrame.bValid())
  931. {
  932. if (dco.pdc->bWorldToDeviceIdentity())
  933. {
  934. //
  935. // We AND the original region and the widened region to get the
  936. // frame region:
  937. //
  938. bRet = rmoFrame.bMerge(rmoFill, ro, gafjRgnOp[RGN_AND]);
  939. }
  940. else
  941. {
  942. //
  943. // Ugh, we have to transform the original region according to the
  944. // world transform before we merge it:
  945. //
  946. RGNMEMOBJTMP rmo(pmoSpine);
  947. bRet = rmo.bValid() &&
  948. rmoFrame.bMerge(rmoFill, rmo, gafjRgnOp[RGN_AND]);
  949. }
  950. if (bRet)
  951. {
  952. //
  953. // Accumulate bounds. We can do this before knowing if the operation is
  954. // successful because bounds can be loose.
  955. //
  956. // NOTE - the default return value is now TRUE
  957. ERECTL ercl(0, 0, 0, 0);
  958. rmoFrame.vGet_rcl((RECTL *) &ercl);
  959. if (dco.fjAccum())
  960. {
  961. dco.vAccumulate(ercl);
  962. }
  963. // in FULLSCREEN mode, exit with success.
  964. if (!dco.bFullScreen() && dco.bHasSurface())
  965. {
  966. dco.pdc->prgnAPI(rmoFrame.prgnGet()); // Dirties rgnRao
  967. DEVLOCKOBJ dlo(dco);
  968. SURFACE *pSurf = dco.pSurface();
  969. if (!dlo.bValid())
  970. {
  971. dco.pdc->prgnAPI(NULL); // Dirties rgnRao
  972. bRet = dco.bFullScreen();
  973. }
  974. else
  975. {
  976. ercl += dco.eptlOrigin();
  977. //
  978. // Compute the clipping complexity and maybe reduce the exclusion rectangle.
  979. //
  980. ECLIPOBJ eco(dco.prgnEffRao(), ercl);
  981. if (eco.erclExclude().bEmpty())
  982. {
  983. dco.pdc->prgnAPI(NULL); // Dirties rgnRao
  984. }
  985. else
  986. {
  987. XEPALOBJ epal(pSurf->ppal());
  988. XEPALOBJ epalDC(dco.ppal());
  989. PDEVOBJ pdo(pSurf->hdev());
  990. EBRUSHOBJ ebo;
  991. //
  992. // NOTE - the default return value
  993. // is now FALSE;
  994. PBRUSH pbrush = (BRUSH *)HmgShareCheckLock((HOBJ)hbrush, BRUSH_TYPE);
  995. bRet = FALSE;
  996. if (pbrush == NULL)
  997. {
  998. dco.pdc->prgnAPI(NULL); // Dirties rgnRao
  999. }
  1000. else
  1001. {
  1002. //
  1003. // in case the brush is cached and the color has changed
  1004. //
  1005. bSyncBrushObj (pbrush);
  1006. ebo.vInitBrush(dco.pdc,
  1007. pbrush,
  1008. epalDC,
  1009. epal,
  1010. pSurf);
  1011. ebo.pColorAdjustment(dco.pColorAdjustment());
  1012. if (pbrush->bIsNull())
  1013. {
  1014. dco.pdc->prgnAPI(NULL); // Dirties rgnRao
  1015. }
  1016. else
  1017. {
  1018. //
  1019. // Exclude the pointer.
  1020. //
  1021. DEVEXCLUDEOBJ dxo(dco,&eco.erclExclude(),&eco);
  1022. //
  1023. // Get and compute the correct mix mode.
  1024. //
  1025. MIX mix = ebo.mixBest(dco.pdc->jROP2(), dco.pdc->jBkMode());
  1026. //
  1027. // Inc the target surface uniqueness
  1028. //
  1029. INC_SURF_UNIQ(pSurf);
  1030. //
  1031. // Issue a call to Paint.
  1032. //
  1033. EngPaint(
  1034. pSurf->pSurfobj(), // Destination surface.
  1035. &eco, // Clip object.
  1036. &ebo, // Realized brush.
  1037. &dco.pdc->ptlFillOrigin(), // Brush origin.
  1038. mix); // Mix mode.
  1039. dco.pdc->prgnAPI(NULL); // Dirties rgnRao
  1040. bRet = TRUE;
  1041. }
  1042. DEC_SHARE_REF_CNT_LAZY0(pbrush);
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }
  1050. }
  1051. }
  1052. }
  1053. }
  1054. return(bRet);
  1055. }
  1056. /******************************Public*Routine******************************\
  1057. * LONG GreGetRgnBox(hrgn,prcl)
  1058. *
  1059. * Get the bounding box of the region.
  1060. *
  1061. \**************************************************************************/
  1062. int
  1063. APIENTRY
  1064. GreGetRgnBox(
  1065. HRGN hrgn,
  1066. LPRECT prcl)
  1067. {
  1068. GDITraceHandle(GreGetRgnBox, "(%X, %p)\n", (va_list)&hrgn, hrgn);
  1069. int iret = ERROR;
  1070. RGNOBJAPI ro(hrgn,TRUE);
  1071. if ((prcl != NULL) &&
  1072. (ro.bValid()))
  1073. {
  1074. ro.vGet_rcl((RECTL *) prcl);
  1075. iret = (int)ro.iComplexity();
  1076. if (iret == NULLREGION)
  1077. {
  1078. //
  1079. // Be compatible with Win 3.1 [donalds] 02-Jun-1993
  1080. //
  1081. prcl->left = 0;
  1082. prcl->top = 0;
  1083. prcl->right = 0;
  1084. prcl->bottom = 0;
  1085. }
  1086. }
  1087. return(iret);
  1088. }
  1089. /******************************Public*Routine******************************\
  1090. * BOOL GreInvertRgn(hdc,hrgn)
  1091. *
  1092. * Invert the colors in the given region.
  1093. *
  1094. \**************************************************************************/
  1095. BOOL NtGdiInvertRgn(
  1096. HDC hdc,
  1097. HRGN hrgn)
  1098. {
  1099. GDITraceHandle2(NtGdiInvertRgn, "(%X, %X)\n", (va_list)&hdc, hdc, hrgn);
  1100. DCOBJ dco(hdc);
  1101. BOOL bXform;
  1102. PREGION prgnOrg;
  1103. BOOL bRet = FALSE;
  1104. if (dco.bValid())
  1105. {
  1106. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  1107. //
  1108. // We may have to scale/rotate the incoming region.
  1109. //
  1110. bXform = !dco.pdc->bWorldToDeviceIdentity();
  1111. RGNOBJAPI ro(hrgn,TRUE);
  1112. if (ro.bValid())
  1113. {
  1114. if (bXform)
  1115. {
  1116. PATHMEMOBJ pmo;
  1117. if (!pmo.bValid())
  1118. {
  1119. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1120. return(FALSE);
  1121. }
  1122. if (!exo.bValid() || !ro.bCreate(pmo, &exo))
  1123. return(FALSE);
  1124. RGNMEMOBJ rmo(pmo);
  1125. if (!rmo.bValid())
  1126. {
  1127. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1128. return(FALSE);
  1129. }
  1130. prgnOrg = ro.prgnGet();
  1131. ro.vSetRgn(rmo.prgnGet());
  1132. }
  1133. //
  1134. // If region is null, return TRUE
  1135. //
  1136. if (ro.iComplexity() != NULLREGION)
  1137. {
  1138. // Accumulate bounds. We can do this before knowing if the operation is
  1139. // successful because bounds can be loose.
  1140. ERECTL ercl;
  1141. ro.vGet_rcl((RECTL *) &ercl);
  1142. if (dco.fjAccum())
  1143. dco.vAccumulate(ercl);
  1144. if (dco.bHasSurface())
  1145. {
  1146. dco.pdc->prgnAPI(ro.prgnGet()); // Dirties rgnRao
  1147. DEVLOCKOBJ dlo(dco);
  1148. SURFACE *pSurf = dco.pSurface();
  1149. if (!dlo.bValid())
  1150. {
  1151. bRet = dco.bFullScreen();
  1152. }
  1153. else
  1154. {
  1155. ercl += dco.eptlOrigin();
  1156. // Compute the clipping complexity and maybe reduce the exclusion rectangle.
  1157. ECLIPOBJ eco(dco.prgnEffRao(), ercl);
  1158. if (!eco.erclExclude().bEmpty())
  1159. {
  1160. PDEVOBJ pdo(pSurf->hdev());
  1161. // Exclude the pointer.
  1162. DEVEXCLUDEOBJ dxo(dco,&eco.erclExclude(),&eco);
  1163. // Inc the target surface uniqueness
  1164. INC_SURF_UNIQ(pSurf);
  1165. // Issue a call to Paint.
  1166. EngPaint(
  1167. pSurf->pSurfobj(), // Destination surface.
  1168. &eco, // Clip object.
  1169. (BRUSHOBJ *) NULL, // Realized brush.
  1170. (POINTL *) NULL, // Brush origin.
  1171. 0x00000606); // R2_NOT
  1172. }
  1173. bRet = TRUE;
  1174. }
  1175. dco.pdc->prgnAPI((PREGION)NULL); // Dirties rgnRao
  1176. }
  1177. else
  1178. {
  1179. bRet = TRUE;
  1180. }
  1181. }
  1182. else
  1183. {
  1184. bRet = TRUE;
  1185. }
  1186. if (bXform)
  1187. {
  1188. // need to delete the temporary one and put the old one back in so
  1189. // the handle gets unlocked
  1190. ro.prgnGet()->vDeleteREGION();
  1191. ro.vSetRgn(prgnOrg);
  1192. }
  1193. }
  1194. }
  1195. return(bRet);
  1196. }
  1197. /******************************Public*Routine******************************\
  1198. * LONG GreOffsetRgn(hrgn,x,y)
  1199. *
  1200. * Offset the given region.
  1201. *
  1202. \**************************************************************************/
  1203. int
  1204. APIENTRY
  1205. GreOffsetRgn(
  1206. HRGN hrgn,
  1207. int x,
  1208. int y)
  1209. {
  1210. GDITraceHandle(GreOffsetRgn, "(%X, %d, %d)\n", (va_list)&hrgn, hrgn);
  1211. RGNOBJAPI ro(hrgn,FALSE);
  1212. POINTL ptl;
  1213. int iRet = ERROR;
  1214. ptl.x = x;
  1215. ptl.y = y;
  1216. if (ro.bValid())
  1217. {
  1218. if (ro.bOffset(&ptl))
  1219. {
  1220. iRet = ro.iComplexity();
  1221. }
  1222. }
  1223. return iRet;
  1224. }
  1225. /******************************Public*Routine******************************\
  1226. * BOOL GrePtInRegion(hrgn,x,y)
  1227. *
  1228. * Is the point in the region?
  1229. *
  1230. \**************************************************************************/
  1231. BOOL APIENTRY GrePtInRegion(
  1232. HRGN hrgn,
  1233. int x,
  1234. int y)
  1235. {
  1236. GDITraceHandle(GrePtInRegion, "(%X, %d, %d)\n", (va_list)&hrgn, hrgn);
  1237. RGNOBJAPI ro(hrgn,TRUE);
  1238. if (!ro.bValid())
  1239. {
  1240. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1241. return((BOOL) ERROR);
  1242. }
  1243. POINTL ptl;
  1244. ptl.x = x;
  1245. ptl.y = y;
  1246. return(ro.bInside(&ptl) == REGION_POINT_INSIDE);
  1247. }
  1248. /******************************Public*Routine******************************\
  1249. * BOOL GreRectInRegion(hrgn,prcl)
  1250. *
  1251. * Is any part of the rectangle in the region?
  1252. *
  1253. \**************************************************************************/
  1254. BOOL
  1255. APIENTRY
  1256. GreRectInRegion(
  1257. HRGN hrgn,
  1258. LPRECT prcl)
  1259. {
  1260. GDITraceHandle(GreRectInRegion, "(%X, %p)\n", (va_list)&hrgn, hrgn);
  1261. BOOL bRet = ERROR;
  1262. RGNOBJAPI ro(hrgn,TRUE);
  1263. if (prcl &&
  1264. (ro.bValid()))
  1265. {
  1266. bRet = (ro.bInside((RECTL *) prcl) == REGION_RECT_INTERSECT);
  1267. }
  1268. return (bRet);
  1269. }
  1270. /******************************Public*Routine******************************\
  1271. * VOID GreSetRectRgn(hrgn,xLeft,yTop,xRight,yBottom)
  1272. *
  1273. * Set the region to be the specified rectangle
  1274. *
  1275. \**************************************************************************/
  1276. BOOL
  1277. APIENTRY
  1278. GreSetRectRgn(
  1279. HRGN hrgn,
  1280. int xLeft,
  1281. int yTop,
  1282. int xRight,
  1283. int yBottom)
  1284. {
  1285. GDITraceHandle(GreSetRectRgn, "(%X, %d, %d, %d, %d)\n", (va_list)&hrgn, hrgn);
  1286. RGNOBJAPI ro(hrgn,FALSE);
  1287. BOOL bRet = ERROR;
  1288. if (ro.bValid())
  1289. {
  1290. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  1291. if (VALID_SCRPRC((RECTL *) &ercl))
  1292. {
  1293. ercl.vOrder(); // Make the rectangle well ordered.
  1294. ro.vSet((RECTL *) &ercl);
  1295. bRet = TRUE;
  1296. }
  1297. }
  1298. return bRet;
  1299. }
  1300. /******************************Public*Routine******************************\
  1301. * LONG GreExcludeClipRect(hdc,xLeft,yTop,xRight,yBottom)
  1302. *
  1303. * Subtract the rectangle from the current clip region
  1304. *
  1305. \**************************************************************************/
  1306. int APIENTRY GreExcludeClipRect(
  1307. HDC hdc,
  1308. int xLeft,
  1309. int yTop,
  1310. int xRight,
  1311. int yBottom)
  1312. {
  1313. GDITraceHandle(GreExcludeClipRect, "(%X, %d, %d, %d, %d)\n", (va_list)&hdc,
  1314. hdc);
  1315. int iRet;
  1316. DCOBJ dco(hdc);
  1317. if (dco.bValid())
  1318. {
  1319. // For speed, test for rotation upfront.
  1320. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  1321. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  1322. if (!exo.bRotation())
  1323. {
  1324. exo.vOrder(*(RECTL *)&ercl);
  1325. exo.bXform(ercl);
  1326. iRet = (int)dco.pdc->iCombine((RECTL *) &ercl,RGN_DIFF);
  1327. }
  1328. else if (!VALID_SCRPRC((RECTL *) &ercl))
  1329. {
  1330. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1331. iRet = ERROR;
  1332. }
  1333. else
  1334. {
  1335. iRet = (int) dco.pdc->iCombine(&exo, (RECTL *) &ercl,RGN_DIFF);
  1336. }
  1337. if (iRet > NULLREGION)
  1338. {
  1339. iRet = COMPLEXREGION;
  1340. }
  1341. }
  1342. else
  1343. {
  1344. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1345. iRet = ERROR;
  1346. }
  1347. return (iRet);
  1348. }
  1349. /******************************Public*Routine******************************\
  1350. * LONG GreGetAppClipBox(hdc,prcl)
  1351. *
  1352. * Get the bounding box of the clip region
  1353. *
  1354. \**************************************************************************/
  1355. int APIENTRY GreGetAppClipBox(
  1356. HDC hdc,
  1357. LPRECT prcl)
  1358. {
  1359. GDITraceHandle(GreGetAppClipBox, "(%X, %p)\n", (va_list)&hdc, hdc);
  1360. DCOBJ dor(hdc);
  1361. int iRet;
  1362. int iSaveLeft;
  1363. if (dor.bValid())
  1364. {
  1365. DEVLOCKOBJ dlo(dor);
  1366. if (!dlo.bValid())
  1367. {
  1368. if (dor.bFullScreen())
  1369. {
  1370. prcl->left = 0; // Make it a 'simple' empty rectangle
  1371. prcl->right = 0;
  1372. prcl->top = 0;
  1373. prcl->bottom = 0;
  1374. return(COMPLEXREGION);
  1375. }
  1376. else
  1377. {
  1378. return(ERROR);
  1379. }
  1380. }
  1381. RGNOBJ ro(dor.prgnEffRao());
  1382. ro.vGet_rcl((RECTL *) prcl);
  1383. //
  1384. // return to logical coordinates
  1385. //
  1386. if ((prcl->left >= prcl->right) || (prcl->top >= prcl->bottom))
  1387. {
  1388. prcl->left = 0; // Make it a 'simple' empty rectangle
  1389. prcl->right = 0;
  1390. prcl->top = 0;
  1391. prcl->bottom = 0;
  1392. iRet = NULLREGION;
  1393. }
  1394. else
  1395. {
  1396. EXFORMOBJ xfoDtoW(dor, DEVICE_TO_WORLD);
  1397. if (xfoDtoW.bValid())
  1398. {
  1399. *(ERECTL *)prcl -= dor.eptlOrigin();
  1400. if (!xfoDtoW.bRotation())
  1401. {
  1402. if (xfoDtoW.bXform(*(ERECTL *)prcl))
  1403. {
  1404. iRet = ro.iComplexity();
  1405. //
  1406. // Transforms with negative scale can give
  1407. // a prcl that is not in vOrder.
  1408. //
  1409. //
  1410. // This is the correct fix, but some apps require the
  1411. // previous bad behaviour.
  1412. //
  1413. //((ERECTL *)prcl)->vOrder();
  1414. }
  1415. else
  1416. {
  1417. iRet = ERROR;
  1418. }
  1419. }
  1420. else
  1421. {
  1422. POINTL aptl[4];
  1423. aptl[0].x = prcl->left;
  1424. aptl[0].y = prcl->top;
  1425. aptl[1].x = prcl->right;
  1426. aptl[1].y = prcl->top;
  1427. aptl[2].x = prcl->left;
  1428. aptl[2].y = prcl->bottom;
  1429. aptl[3].x = prcl->right;
  1430. aptl[3].y = prcl->bottom;
  1431. xfoDtoW.bXform(aptl, 4);
  1432. prcl->left = MIN4(aptl[0].x, aptl[1].x, aptl[2].x, aptl[3].x);
  1433. prcl->top = MIN4(aptl[0].y, aptl[1].y, aptl[2].y, aptl[3].y);
  1434. prcl->right = MAX4(aptl[0].x, aptl[1].x, aptl[2].x, aptl[3].x);
  1435. prcl->bottom = MAX4(aptl[0].y, aptl[1].y, aptl[2].y, aptl[3].y);
  1436. iRet = COMPLEXREGION;
  1437. }
  1438. }
  1439. else
  1440. {
  1441. iRet = ERROR;
  1442. }
  1443. }
  1444. if ((iRet != ERROR) && MIRRORED_DC(dor.pdc) && (prcl->left > prcl->right)) {
  1445. iSaveLeft = prcl->left;
  1446. prcl->left = prcl->right;
  1447. prcl->right = iSaveLeft;
  1448. }
  1449. }
  1450. else
  1451. {
  1452. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1453. iRet = ERROR;
  1454. }
  1455. return(iRet);
  1456. }
  1457. /******************************Public*Routine******************************\
  1458. * int GreGetRandomRgn(hdc,hrgn,iNum)
  1459. *
  1460. * Copy the specified region into the handle provided
  1461. *
  1462. \**************************************************************************/
  1463. int GreGetRandomRgn(
  1464. HDC hdc,
  1465. HRGN hrgn,
  1466. int iNum)
  1467. {
  1468. GDITraceHandle2(GreGetRandomRgn, "(%X, %X, %d)\n", (va_list)&hdc, hdc, hrgn);
  1469. DCOBJ dor(hdc);
  1470. PREGION prgnSrc1, prgnSrc2;
  1471. int iMode = RGN_COPY;
  1472. int iRet = -1;
  1473. if (!dor.bValid())
  1474. {
  1475. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1476. }
  1477. else
  1478. {
  1479. DEVLOCKOBJ dlo(dor);
  1480. switch(iNum)
  1481. {
  1482. case 1:
  1483. prgnSrc1 = dor.pdc->prgnClip();
  1484. break;
  1485. case 2:
  1486. prgnSrc1 = dor.pdc->prgnMeta();
  1487. break;
  1488. case 3:
  1489. prgnSrc1 = dor.pdc->prgnClip();
  1490. prgnSrc2 = dor.pdc->prgnMeta();
  1491. if (prgnSrc1 == NULL) // prgnSrc1 == 0, prgnSrc2 != 0
  1492. {
  1493. prgnSrc1 = prgnSrc2;
  1494. }
  1495. else if (prgnSrc2 != NULL) // prgnSrc1 != 0, prgnSrc2 != 0
  1496. {
  1497. iMode = RGN_AND;
  1498. }
  1499. break;
  1500. case 4:
  1501. ASSERTDEVLOCK(dor.pdc);
  1502. prgnSrc1 = dor.pdc->prgnVis();
  1503. break;
  1504. default:
  1505. prgnSrc1 = NULL;
  1506. }
  1507. if (prgnSrc1 == NULL)
  1508. {
  1509. iRet = 0;
  1510. }
  1511. else
  1512. {
  1513. RGNOBJAPI ro(hrgn,FALSE);
  1514. if (ro.bValid())
  1515. {
  1516. RGNOBJ ro1(prgnSrc1);
  1517. if (iMode == RGN_COPY)
  1518. {
  1519. if (ro.bCopy(ro1))
  1520. {
  1521. // For a redirection DC, the surface originates at the
  1522. // redirected window origin. For compatibility reasons,
  1523. // we must return the visrgn in screen coordinates.
  1524. if (iNum == 4 && dor.pdc->bRedirection())
  1525. {
  1526. POINTL ptl;
  1527. if (UserGetRedirectedWindowOrigin(hdc,
  1528. (LPPOINT)&ptl) && ro.bOffset(&ptl))
  1529. {
  1530. iRet = 1;
  1531. }
  1532. }
  1533. else
  1534. {
  1535. iRet = 1;
  1536. }
  1537. }
  1538. }
  1539. else
  1540. {
  1541. RGNOBJ ro2(prgnSrc2);
  1542. if (ro.iCombine(ro1,ro2,iMode) != RGN_ERROR)
  1543. iRet = 1;
  1544. }
  1545. }
  1546. }
  1547. }
  1548. return(iRet);
  1549. }
  1550. /******************************Public*Routine******************************\
  1551. * LONG GreIntersectClipRect(hdc,xLeft,yTop,xRight,yBottom)
  1552. *
  1553. * AND the rectangle with the current clip region
  1554. *
  1555. \**************************************************************************/
  1556. int APIENTRY GreIntersectClipRect(
  1557. HDC hdc,
  1558. int xLeft,
  1559. int yTop,
  1560. int xRight,
  1561. int yBottom)
  1562. {
  1563. GDITraceHandle(GreIntersectClipRect, "(%X, %d, %d, %d, %d)\n", (va_list)&hdc,
  1564. hdc);
  1565. DCOBJ dco(hdc);
  1566. if (!dco.bValid())
  1567. {
  1568. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1569. return(ERROR);
  1570. }
  1571. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  1572. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  1573. // For speed, test for rotation up front.
  1574. int iRet;
  1575. if (!exo.bRotation())
  1576. {
  1577. exo.vOrder(*(RECTL *)&ercl);
  1578. exo.bXform(ercl);
  1579. iRet = (int)dco.pdc->iCombine((RECTL *) &ercl,RGN_AND);
  1580. }
  1581. else if (!VALID_SCRPRC((RECTL *) &ercl))
  1582. {
  1583. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1584. iRet = ERROR;
  1585. }
  1586. else
  1587. {
  1588. iRet = (int)dco.pdc->iCombine(&exo, (RECTL *) &ercl,RGN_AND);
  1589. }
  1590. if (iRet > NULLREGION)
  1591. iRet = COMPLEXREGION;
  1592. return(iRet);
  1593. }
  1594. /******************************Public*Routine******************************\
  1595. * INT NtGdiOffsetClipRgn(hdc,x,y)
  1596. *
  1597. * Offset the current clip region
  1598. *
  1599. \**************************************************************************/
  1600. int APIENTRY
  1601. NtGdiOffsetClipRgn(
  1602. HDC hdc,
  1603. int x,
  1604. int y)
  1605. {
  1606. GDITraceHandle(NtGdiOffsetClipRgn, "(%X, %d, %d)\n", (va_list)&hdc, hdc);
  1607. DCOBJ dor(hdc);
  1608. if (!dor.bValid())
  1609. {
  1610. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1611. return(ERROR);
  1612. }
  1613. PREGION prgn = dor.pdc->prgnClip();
  1614. if (prgn == NULL)
  1615. return(SIMPLEREGION);
  1616. // if this region has multiple references (saved levels) we need to duplicate
  1617. // it and modify the copy.
  1618. if (prgn->cRefs > 1)
  1619. {
  1620. RGNOBJ ro(prgn);
  1621. RGNMEMOBJ rmo(ro.sizeRgn());
  1622. if (!rmo.bValid())
  1623. {
  1624. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1625. return(ERROR);
  1626. }
  1627. rmo.vCopy(ro);
  1628. prgn = rmo.prgnGet();
  1629. rmo.vSelect(hdc);
  1630. ro.vUnselect();
  1631. dor.pdc->prgnClip(prgn);
  1632. }
  1633. RGNOBJ ro(prgn);
  1634. EPOINTL eptl(x, y);
  1635. // Transform the point from Logical to Device
  1636. EXFORMOBJ xfo(dor, WORLD_TO_DEVICE);
  1637. if (!xfo.bXform(*((EVECTORL *) &eptl)) || !ro.bOffset((PPOINTL)&eptl))
  1638. {
  1639. SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE);
  1640. return(ERROR);
  1641. }
  1642. dor.pdc->vReleaseRao();
  1643. dor.pdc->vUpdate_VisRect(dor.pdc->prgnVis());
  1644. return(ro.iComplexity());
  1645. }
  1646. /******************************Public*Routine******************************\
  1647. * BOOL GrePtVisible(hdc,x,y)
  1648. *
  1649. * Is the point in the current clip region?
  1650. *
  1651. \**************************************************************************/
  1652. BOOL
  1653. APIENTRY
  1654. NtGdiPtVisible(
  1655. HDC hdc,
  1656. int x,
  1657. int y)
  1658. {
  1659. DCOBJ dor(hdc);
  1660. if (!dor.bValid())
  1661. {
  1662. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1663. return(ERROR_BOOL);
  1664. }
  1665. DEVLOCKOBJ dlo(dor);
  1666. if (!dlo.bValid())
  1667. return(REGION_POINT_OUTSIDE);
  1668. RGNOBJ ro(dor.prgnEffRao());
  1669. EPOINTL eptl(x, y);
  1670. // Transform the point from Logical to Screen
  1671. EXFORMOBJ xfo(dor, WORLD_TO_DEVICE);
  1672. xfo.bXform(eptl);
  1673. eptl += dor.eptlOrigin();
  1674. return(ro.bInside((PPOINTL)&eptl) == REGION_POINT_INSIDE);
  1675. }
  1676. /******************************Public*Routine******************************\
  1677. * BOOL GreRectVisible(hdc,prcl)
  1678. *
  1679. * Is the rectangle in the current clip region?
  1680. *
  1681. \**************************************************************************/
  1682. BOOL APIENTRY GreRectVisible(
  1683. HDC hdc,
  1684. LPRECT prcl)
  1685. {
  1686. DCOBJ dor(hdc);
  1687. if (!dor.bValid())
  1688. {
  1689. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1690. return(ERROR_BOOL);
  1691. }
  1692. DEVLOCKOBJ dlo(dor);
  1693. if (!dlo.bValid())
  1694. return(REGION_RECT_OUTSIDE);
  1695. RGNOBJ ro(dor.prgnEffRao());
  1696. ERECTL ercl = *((ERECTL *) prcl);
  1697. // Transform the rectangle from Logical to Screen
  1698. EXFORMOBJ xfo(dor, WORLD_TO_DEVICE);
  1699. // If there is no rotation in the transform, just call bInside().
  1700. if (!xfo.bRotation())
  1701. {
  1702. xfo.vOrder(*(RECTL *)&ercl);
  1703. xfo.bXform(ercl);
  1704. ercl += dor.eptlOrigin();
  1705. BOOL bIn = ro.bInside((RECTL *) &ercl);
  1706. return(bIn == REGION_RECT_INTERSECT);
  1707. }
  1708. // Convert the rectangle to a parallelogram and merge it with the Rao.
  1709. // If there is anything left, the call succeeded.
  1710. POINTL aptl[4];
  1711. aptl[0].x = prcl->left;
  1712. aptl[0].y = prcl->top;
  1713. aptl[1].x = prcl->right;
  1714. aptl[1].y = prcl->top;
  1715. aptl[2].x = prcl->right;
  1716. aptl[2].y = prcl->bottom;
  1717. aptl[3].x = prcl->left;
  1718. aptl[3].y = prcl->bottom;
  1719. // Create a path, and draw the parallelogram.
  1720. PATHMEMOBJ pmo;
  1721. BOOL bRes;
  1722. if (!pmo.bValid())
  1723. {
  1724. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1725. bRes = ERROR_BOOL;
  1726. }
  1727. else if (!pmo.bMoveTo(&xfo, &aptl[0]) ||
  1728. !pmo.bPolyLineTo(&xfo, &aptl[1], 3) ||
  1729. !pmo.bCloseFigure())
  1730. {
  1731. bRes = ERROR_BOOL;
  1732. }
  1733. else
  1734. {
  1735. // Now, convert it back into a region.
  1736. RGNMEMOBJTMP rmoPlg(pmo, ALTERNATE);
  1737. RGNMEMOBJTMP rmo;
  1738. if (!rmoPlg.bValid() || !rmo.bValid())
  1739. {
  1740. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1741. bRes = ERROR_BOOL;
  1742. }
  1743. else
  1744. {
  1745. if (!rmo.bMerge(ro, rmoPlg, gafjRgnOp[RGN_AND]) ||
  1746. (rmo.iComplexity() == NULLREGION))
  1747. {
  1748. bRes = (BOOL)REGION_RECT_OUTSIDE;
  1749. }
  1750. else
  1751. {
  1752. bRes = (BOOL)REGION_RECT_INTERSECT;
  1753. }
  1754. }
  1755. }
  1756. return(bRes);
  1757. }
  1758. /******************************Public*Routine******************************\
  1759. * int GreExtSelectClipRgn(hdc,hrgn,iMode)
  1760. *
  1761. * Merge the region into current clip region
  1762. *
  1763. \**************************************************************************/
  1764. int
  1765. GreExtSelectClipRgn(
  1766. HDC hdc,
  1767. HRGN hrgn,
  1768. int iMode)
  1769. {
  1770. GDITraceHandle2(GreExtSelectClipRgn, "(%X, %X, %d)\n", (va_list)&hdc,
  1771. hdc, hrgn);
  1772. int iRet = RGN_ERROR;
  1773. BOOL bSame = FALSE;
  1774. if (((iMode < RGN_MIN) || (iMode > RGN_MAX)))
  1775. {
  1776. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1777. }
  1778. else
  1779. {
  1780. DCOBJ dco(hdc);
  1781. if (!dco.bValid())
  1782. {
  1783. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1784. }
  1785. else
  1786. {
  1787. if (hrgn != (HRGN)0)
  1788. {
  1789. RGNOBJAPI ro(hrgn,TRUE);
  1790. if (ro.bValid())
  1791. {
  1792. iRet = dco.pdc->iSelect(ro.prgnGet(),iMode);
  1793. if (iRet != RGN_ERROR)
  1794. {
  1795. DEVLOCKOBJ dlo(dco);
  1796. RGNOBJ ro(dco.prgnEffRao());
  1797. iRet = ro.iComplexity();
  1798. }
  1799. }
  1800. }
  1801. else
  1802. {
  1803. if (iMode == RGN_COPY)
  1804. {
  1805. iRet = dco.pdc->iSelect((PREGION)NULL,iMode);
  1806. if (iRet != RGN_ERROR)
  1807. {
  1808. DEVLOCKOBJ dlo(dco);
  1809. RGNOBJ roVis(dco.pdc->prgnVis());
  1810. iRet = roVis.iComplexity();
  1811. }
  1812. }
  1813. }
  1814. }
  1815. }
  1816. return(iRet);
  1817. }
  1818. /******************************Public*Routine******************************\
  1819. * SelectClip from bathcing
  1820. *
  1821. * Arguments:
  1822. *
  1823. *
  1824. *
  1825. * Return Value:
  1826. *
  1827. *
  1828. *
  1829. * History:
  1830. *
  1831. * 26-Oct-1995 -by- Mark Enstrom [marke]
  1832. *
  1833. \**************************************************************************/
  1834. GreExtSelectClipRgnLocked(
  1835. XDCOBJ &dco,
  1836. PRECTL prcl,
  1837. int iMode)
  1838. {
  1839. int iRet = RGN_ERROR;
  1840. BOOL bNullHrgn = iMode & REGION_NULL_HRGN;
  1841. iMode &= ~REGION_NULL_HRGN;
  1842. if (((iMode < RGN_MIN) || (iMode > RGN_MAX)))
  1843. {
  1844. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1845. }
  1846. else
  1847. {
  1848. if (!dco.bValid())
  1849. {
  1850. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1851. }
  1852. else
  1853. {
  1854. //
  1855. // iFlag specifies a null hrgn
  1856. //
  1857. if (!bNullHrgn)
  1858. {
  1859. //
  1860. // check if current region is the same as new
  1861. // hrgn
  1862. //
  1863. BOOL bSame = FALSE;
  1864. RGNOBJ roClipOld(dco.pdc->prgnClip());
  1865. if (roClipOld.bValid())
  1866. {
  1867. if (roClipOld.bRectl())
  1868. {
  1869. RECTL rclOld;
  1870. roClipOld.vGet_rcl(&rclOld);
  1871. if (
  1872. (prcl->left == rclOld.left) &&
  1873. (prcl->top == rclOld.top) &&
  1874. (prcl->right == rclOld.right) &&
  1875. (prcl->bottom == rclOld.bottom)
  1876. )
  1877. {
  1878. RGNOBJ ro(dco.prgnEffRao());
  1879. iRet = ro.iComplexity();
  1880. bSame = TRUE;
  1881. }
  1882. }
  1883. }
  1884. //
  1885. // regions don't match, must select new region into DC
  1886. //
  1887. if (!bSame)
  1888. {
  1889. RGNMEMOBJTMP ro(FALSE);
  1890. if (ro.bValid())
  1891. {
  1892. ro.vSet(prcl);
  1893. iRet = dco.pdc->iSelect(ro.prgnGet(),iMode);
  1894. //
  1895. // need to update RAO
  1896. //
  1897. if (dco.pdc->bDirtyRao())
  1898. {
  1899. if (!dco.pdc->bCompute())
  1900. {
  1901. WARNING("bCompute fails in GreExtSelectClipRgnLocked");
  1902. }
  1903. }
  1904. if (iRet != RGN_ERROR)
  1905. {
  1906. RGNOBJ ro(dco.prgnEffRao());
  1907. iRet = ro.iComplexity();
  1908. }
  1909. }
  1910. }
  1911. }
  1912. else
  1913. {
  1914. if (iMode == RGN_COPY)
  1915. {
  1916. iRet = dco.pdc->iSelect((PREGION)NULL,iMode);
  1917. //
  1918. // need to update RAO
  1919. //
  1920. if (dco.pdc->bDirtyRao())
  1921. {
  1922. if (!dco.pdc->bCompute())
  1923. {
  1924. WARNING("bCompute fails in GreExtSelectClipRgnLocked");
  1925. }
  1926. }
  1927. if (iRet != RGN_ERROR)
  1928. {
  1929. RGNOBJ roVis(dco.pdc->prgnVis());
  1930. iRet = roVis.iComplexity();
  1931. }
  1932. }
  1933. }
  1934. }
  1935. }
  1936. return(iRet);
  1937. }
  1938. /******************************Public*Routine******************************\
  1939. * int GreStMetaRgn(hdc,hrgn,iMode)
  1940. *
  1941. * Merge the region into current meta region
  1942. *
  1943. \**************************************************************************/
  1944. int GreSetMetaRgn(
  1945. HDC hdc)
  1946. {
  1947. DCOBJ dco(hdc);
  1948. if (!dco.bValid())
  1949. {
  1950. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1951. return(ERROR);
  1952. }
  1953. return(dco.pdc->iSetMetaRgn());
  1954. }
  1955. /******************************Public*Routine******************************\
  1956. * GreGetRegionData
  1957. *
  1958. * Retreives the region data
  1959. *
  1960. * History:
  1961. * 5-Dec-1997 -by- Samer Arafeh [samera]
  1962. * Wrote it.
  1963. \**************************************************************************/
  1964. DWORD
  1965. GreGetRegionData(
  1966. HRGN hrgn,
  1967. DWORD nCount,
  1968. LPRGNDATA lpRgnData)
  1969. {
  1970. GDITraceHandle(GreGetRegionData, "(%X, %u, %p)\n", (va_list)&hrgn, hrgn);
  1971. DWORD nSize;
  1972. DWORD nRectangles;
  1973. DWORD nRgnSize; // size of buffer of rectangles
  1974. RGNOBJAPI ro(hrgn,TRUE);
  1975. if (ro.bValid())
  1976. {
  1977. //
  1978. // just return size if buffer is NULL
  1979. //
  1980. nRgnSize = ro.sizeSave();
  1981. nSize = nRgnSize + sizeof(RGNDATAHEADER);
  1982. if (lpRgnData != (LPRGNDATA) NULL)
  1983. {
  1984. if (nSize > nCount)
  1985. {
  1986. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1987. nSize = ERROR;
  1988. }
  1989. else
  1990. {
  1991. nRectangles = (nSize - sizeof(RGNDATAHEADER)) / sizeof(RECTL);
  1992. lpRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
  1993. lpRgnData->rdh.iType = RDH_RECTANGLES;
  1994. lpRgnData->rdh.nCount = nRectangles;
  1995. lpRgnData->rdh.nRgnSize = nRgnSize;
  1996. if (nRectangles != 0)
  1997. {
  1998. ro.vGet_rcl((RECTL *) &lpRgnData->rdh.rcBound);
  1999. }
  2000. else
  2001. {
  2002. lpRgnData->rdh.rcBound.left = 0;
  2003. lpRgnData->rdh.rcBound.top = 0;
  2004. lpRgnData->rdh.rcBound.right = 0;
  2005. lpRgnData->rdh.rcBound.bottom = 0;
  2006. }
  2007. ro.vDownload((PVOID) &lpRgnData->Buffer);
  2008. }
  2009. }
  2010. }
  2011. else
  2012. {
  2013. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  2014. nSize = ERROR;
  2015. }
  2016. return(nSize);
  2017. }
  2018. /******************************Public*Routine******************************\
  2019. * DWORD NtGdiGetRegionData(hrgn, nCount, lpRgnData)
  2020. *
  2021. * Compute size of buffer/copy region data to buffer
  2022. *
  2023. \**************************************************************************/
  2024. DWORD
  2025. NtGdiGetRegionData(
  2026. HRGN hrgn,
  2027. DWORD nCount,
  2028. LPRGNDATA lpRgnData)
  2029. {
  2030. GDITraceHandle(NtGdiGetRegionData, "(%X, %u, %p)\n", (va_list)&hrgn, hrgn);
  2031. DWORD nSize=!ERROR;
  2032. ULONG ulTemp[QUANTUM_REGION_SIZE/2];
  2033. LPRGNDATA prgnTemp=NULL;
  2034. //
  2035. // If it is valid user pointer, let's copy into
  2036. // into kernel memory (we don't know what the user might do with this memory)
  2037. //
  2038. if (lpRgnData)
  2039. {
  2040. if (nCount <= sizeof(ulTemp))
  2041. prgnTemp = (PRGNDATA) ulTemp;
  2042. else
  2043. prgnTemp = (PRGNDATA)AllocFreeTmpBuffer(nCount);
  2044. if (!prgnTemp)
  2045. {
  2046. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  2047. nSize = ERROR;
  2048. }
  2049. }
  2050. //
  2051. // Check if allocation (if happened) is ok ?
  2052. //
  2053. if (nSize != ERROR)
  2054. {
  2055. nSize = GreGetRegionData( hrgn , nCount , prgnTemp );
  2056. //
  2057. // Copy retreived data to user-buffer
  2058. //
  2059. if (lpRgnData && (nSize != ERROR))
  2060. {
  2061. __try
  2062. {
  2063. ProbeForWrite(lpRgnData,nSize, sizeof(DWORD));
  2064. RtlCopyMemory( lpRgnData , prgnTemp , nSize );
  2065. }
  2066. __except(EXCEPTION_EXECUTE_HANDLER)
  2067. {
  2068. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  2069. nSize = ERROR;
  2070. }
  2071. }
  2072. }
  2073. //
  2074. // And free the kernel memory, if allocated
  2075. //
  2076. if (prgnTemp && (prgnTemp != (PRGNDATA)&ulTemp[0]))
  2077. {
  2078. FreeTmpBuffer(prgnTemp);
  2079. }
  2080. return(nSize);
  2081. }
  2082. /******************************Public*Routine******************************\
  2083. * HRGN GreExtCreateRegion(lpXform, nCount, lpRgnData)
  2084. *
  2085. * Create a region from a region data buffer
  2086. *
  2087. \**************************************************************************/
  2088. HRGN
  2089. GreExtCreateRegion(
  2090. XFORML *lpXform,
  2091. DWORD nCount,
  2092. LPRGNDATA lpRgnData)
  2093. {
  2094. GDITrace(GreExtCreateRegion, "(%p, %u, %p)\n", (va_list)&lpXform);
  2095. ASSERTGDI(nCount >= sizeof(RGNDATAHEADER), "GreExtCreateRegion: passed invalid count");
  2096. DWORD nSize = lpRgnData->rdh.dwSize;
  2097. ULONG cRect = lpRgnData->rdh.nCount;
  2098. if (nSize != sizeof(RGNDATAHEADER))
  2099. {
  2100. WARNING("GreExtCreateRegion: bad nSize");
  2101. return((HRGN) 0);
  2102. }
  2103. if (cRect > ((MAXULONG - sizeof(RGNDATAHEADER)) / sizeof (RECTL)))
  2104. {
  2105. // cRect is too large, which will cause the computation for nSize below to overflow.
  2106. return ((HRGN) 0);
  2107. }
  2108. nSize += (cRect * sizeof(RECTL));
  2109. if (nSize > nCount)
  2110. return((HRGN) 0);
  2111. // At this point we have what looks like a valid header, and a buffer that
  2112. // is at least big enough to contain all the data for a region. Create a
  2113. // region to contain it and then attempt to upload the data into the region.
  2114. RGNMEMOBJ rmo;
  2115. if(!rmo.bValid())
  2116. {
  2117. rmo.bDeleteRGNOBJ();
  2118. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2119. return((HRGN) 0);
  2120. }
  2121. RECTL *prcl = (RECTL *)lpRgnData->Buffer;
  2122. if(!rmo.bSet(cRect, prcl))
  2123. {
  2124. rmo.bDeleteRGNOBJ();
  2125. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2126. return((HRGN) 0);
  2127. }
  2128. HRGN hrgn;
  2129. if ((lpXform == NULL) || (rmo.iComplexity() == NULLREGION))
  2130. {
  2131. //
  2132. // Create the proper bounding box and make it long lived
  2133. //
  2134. rmo.vTighten();
  2135. hrgn = rmo.hrgnAssociate();
  2136. if (hrgn == NULL)
  2137. {
  2138. rmo.bDeleteRGNOBJ();
  2139. }
  2140. GDITrace(GreExtCreateRegion_return, "(%X)\n", (va_list)&hrgn);
  2141. return(hrgn);
  2142. }
  2143. //
  2144. // Convert the XFORM to a MATRIX
  2145. //
  2146. MATRIX mx;
  2147. vConvertXformToMatrix(lpXform, &mx);
  2148. //
  2149. // Scale it to FIXED notation.
  2150. //
  2151. mx.efM11.vTimes16();
  2152. mx.efM12.vTimes16();
  2153. mx.efM21.vTimes16();
  2154. mx.efM22.vTimes16();
  2155. mx.efDx.vTimes16();
  2156. mx.efDy.vTimes16();
  2157. mx.fxDx *= 16;
  2158. mx.fxDy *= 16;
  2159. EXFORMOBJ exo(&mx, XFORM_FORMAT_LTOFX | COMPUTE_FLAGS);
  2160. if (!exo.bValid())
  2161. {
  2162. rmo.bDeleteRGNOBJ();
  2163. return((HRGN) 0);
  2164. }
  2165. //
  2166. // If the xform is the identity, we don't have to do anything.
  2167. //
  2168. if (exo.bIdentity())
  2169. {
  2170. //
  2171. // Create the proper bounding box and make it long lived
  2172. //
  2173. rmo.vTighten();
  2174. hrgn = rmo.hrgnAssociate();
  2175. if (hrgn == NULL)
  2176. {
  2177. rmo.bDeleteRGNOBJ();
  2178. }
  2179. GDITrace(GreExtCreateRegion_return, "(%X)\n", (va_list)&hrgn);
  2180. return(hrgn);
  2181. }
  2182. //
  2183. // Create a path from the region
  2184. //
  2185. PATHMEMOBJ pmo;
  2186. if (!pmo.bValid())
  2187. {
  2188. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2189. rmo.bDeleteRGNOBJ();
  2190. return((HRGN) 0);
  2191. }
  2192. BOOL bSuccess = rmo.bCreate(pmo, &exo);
  2193. //
  2194. // done with the region, delete it now.
  2195. //
  2196. rmo.bDeleteRGNOBJ();
  2197. if (!bSuccess)
  2198. {
  2199. return((HRGN) 0);
  2200. }
  2201. //
  2202. // Create a region from the path
  2203. //
  2204. RGNMEMOBJTMP rmoPath(pmo);
  2205. if (!rmoPath.bValid())
  2206. {
  2207. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2208. return((HRGN) 0);
  2209. }
  2210. RGNMEMOBJ rmoFinal;
  2211. if (!rmoFinal.bValid())
  2212. {
  2213. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2214. return((HRGN) 0);
  2215. }
  2216. //
  2217. // coelece the region
  2218. //
  2219. rmoFinal.iReduce(rmoPath);
  2220. //
  2221. // Create the proper bounding box and make it long lived
  2222. //
  2223. rmoFinal.vTighten();
  2224. hrgn = rmoFinal.hrgnAssociate();
  2225. if (hrgn == NULL)
  2226. {
  2227. rmoFinal.bDeleteRGNOBJ();
  2228. }
  2229. GDITrace(GreExtCreateRegion_return, "(%X)\n", (va_list)&hrgn);
  2230. return(hrgn);
  2231. }
  2232. /******************************Public*Routine******************************\
  2233. * BOOL GreIntersectVisRect(hdc, xLeft, yTop, xRight, yBottom)
  2234. *
  2235. * Intersect (AND) the rectangle with the vis region
  2236. *
  2237. * Warnings:
  2238. * This is a PRIVATE USER API.
  2239. *
  2240. \**************************************************************************/
  2241. BOOL GreIntersectVisRect(
  2242. HDC hdc,
  2243. int xLeft,
  2244. int yTop,
  2245. int xRight,
  2246. int yBottom)
  2247. {
  2248. BOOL bRes = FALSE;
  2249. //
  2250. // fail bad ordered rectangles
  2251. //
  2252. if ((xLeft>=xRight) || (yTop>=yBottom))
  2253. {
  2254. return(FALSE);
  2255. }
  2256. //
  2257. // fail bad coordinates
  2258. //
  2259. if ((xLeft<MIN_REGION_COORD) ||
  2260. (xRight>MAX_REGION_COORD) ||
  2261. (yTop<MIN_REGION_COORD) ||
  2262. (yBottom>MAX_REGION_COORD))
  2263. {
  2264. return(FALSE);
  2265. }
  2266. DCOBJA dov(hdc); // Use ALTLOCK
  2267. if (dov.bValid()) // don't trust them the DC to be valid
  2268. {
  2269. // We invoke the 'dlo(po)' devlock form instead of 'dlo(dco)'
  2270. // to avoid the bCompute that the latter does:
  2271. PDEVOBJ po(dov.hdev());
  2272. DEVLOCKOBJ dlo(po);
  2273. ASSERTDEVLOCK(dov.pdc);
  2274. if (dlo.bValid())
  2275. {
  2276. RGNOBJ ro(dov.pdc->prgnVis());
  2277. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  2278. RGNMEMOBJTMP rmo;
  2279. RGNMEMOBJTMP rmo2(ro.sizeRgn());
  2280. if (!rmo.bValid() || !rmo2.bValid())
  2281. {
  2282. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  2283. }
  2284. else
  2285. {
  2286. rmo.vSet((RECTL *) &ercl);
  2287. rmo2.vCopy(ro);
  2288. if (ro.iCombine(rmo, rmo2, RGN_AND) != ERROR)
  2289. {
  2290. dov.pdc->prgnVis(ro.prgnGet());
  2291. ro.prgnGet()->vStamp();
  2292. dov.pdc->vReleaseRao();
  2293. bRes = TRUE;
  2294. }
  2295. }
  2296. }
  2297. RGNLOG rl((HRGN) dov.pdc->prgnVis(),0,"GreIntersectVisRect",(ULONG_PTR)hdc);
  2298. rl.vRet((ULONG_PTR)bRes);
  2299. }
  2300. #if DBG
  2301. else
  2302. {
  2303. //
  2304. // USER may send a NULL hdc in low memory situations.
  2305. // Just print a warning for those situations, but rip
  2306. // for other bad handles (i.e., USER should figure out
  2307. // why they passed us a bad handle).
  2308. //
  2309. if (hdc)
  2310. {
  2311. RIP("GDISRV!GreSelectVisRgn: Bad hdc\n");
  2312. }
  2313. else
  2314. {
  2315. WARNING("GDISRV!GreSelectVisRgn: hdc NULL\n");
  2316. }
  2317. }
  2318. #endif
  2319. return(bRes);
  2320. }
  2321. #if DBG || defined(PRERELEASE)
  2322. /******************************Public*Routine******************************\
  2323. * GreValidateVisrgn()
  2324. *
  2325. * History:
  2326. * 10-Dec-1998 -by- Vadim Gorokhovsky [vadimg]
  2327. * Wrote it.
  2328. \**************************************************************************/
  2329. VOID
  2330. GreValidateVisrgn(
  2331. HDC hdc,
  2332. BOOL bValidateVisrgn
  2333. )
  2334. {
  2335. DCOBJA dco(hdc);
  2336. if (dco.bValid())
  2337. {
  2338. dco.pdc->vValidateVisrgn(bValidateVisrgn);
  2339. if (bValidateVisrgn)
  2340. {
  2341. PDEVOBJ pdo(dco.hdev());
  2342. SURFACE *pSurf = dco.pSurface();
  2343. REGION *prgn = dco.pdc->prgnVis();
  2344. if (pdo.bValid() && !pdo.bMetaDriver() && pSurf && prgn)
  2345. {
  2346. BOOL bIsOK = ((pSurf->sizl().cx >= prgn->rcl.right) &&
  2347. (pSurf->sizl().cy >= prgn->rcl.bottom)&&
  2348. (prgn->rcl.left >= 0) &&
  2349. (prgn->rcl.top >= 0));
  2350. FREASSERTGDI(bIsOK, "Rgn size is bigger than surface size");
  2351. }
  2352. }
  2353. }
  2354. }
  2355. #endif
  2356. /******************************Public*Routine******************************\
  2357. * GreIsValidRegion()
  2358. *
  2359. * History:
  2360. * 08-Dec-2001 -by- Mohamed Sadek [msadek]
  2361. * Wrote it.
  2362. \**************************************************************************/
  2363. BOOL
  2364. GreIsValidRegion(
  2365. HRGN hrgn)
  2366. {
  2367. RGNOBJAPI ro(hrgn, TRUE);
  2368. return ro.bValid();
  2369. }
  2370. /******************************Public*Routine******************************\
  2371. * HRGN GreSelectVisRgn(hdc,hrgn,fl)
  2372. *
  2373. * Select the region as the new vis region
  2374. *
  2375. * flags - only one of these may be passed in
  2376. *
  2377. * SVR_COPYNEW - make a copy of region passed in, deletes the old one
  2378. * SVR_DELETEOLD - use the select rgn, delete the old one
  2379. * SVR_SWAP - swaps the contents of the hrgn and the visrgn
  2380. *
  2381. * Warnings:
  2382. * This is a PRIVATE USER API.
  2383. *
  2384. \**************************************************************************/
  2385. BOOL
  2386. GreSelectVisRgn(
  2387. HDC hdc,
  2388. HRGN hrgn,
  2389. VIS_REGION_SELECT fl)
  2390. {
  2391. RGNLOG rl(hrgn,NULL,"GreSelectVisRgn",(ULONG_PTR)hdc,(ULONG_PTR)fl);
  2392. ASSERTGDI((fl == SVR_COPYNEW ) ||
  2393. (fl == SVR_DELETEOLD) ||
  2394. (fl == SVR_SWAP ), "GreSelectVisRgn - invalid fl\n");
  2395. BOOL bRet;
  2396. //
  2397. // Share Lock DC
  2398. //
  2399. DCOBJA dco(hdc);
  2400. PREGION prgnOld;
  2401. PREGION prgn;
  2402. ASSERTDEVLOCK(dco.pdc);
  2403. //
  2404. // Always validate input hdc
  2405. //
  2406. if (!dco.bValid())
  2407. {
  2408. #if DBG
  2409. //
  2410. // USER may send a NULL hdc in low memory situations.
  2411. // Just print a warning for those situations, but rip
  2412. // for other bad handles (i.e., USER should figure out
  2413. // why they passed us a bad handle).
  2414. //
  2415. if (hdc)
  2416. {
  2417. RIP("GDISRV!GreSelectVisRgn: Bad hdc\n");
  2418. }
  2419. else
  2420. {
  2421. WARNING("GDISRV!GreSelectVisRgn: hdc NULL\n");
  2422. }
  2423. #endif
  2424. bRet = FALSE;
  2425. }
  2426. else
  2427. {
  2428. bRet = TRUE;
  2429. //
  2430. // Always nuke the Rao
  2431. //
  2432. dco.pdc->vReleaseRao();
  2433. BOOL bDeleteOld = TRUE;
  2434. if (hrgn != (HRGN) NULL)
  2435. {
  2436. //
  2437. // The incoming region may be some random thing, make it lockable
  2438. //
  2439. GreSetRegionOwner(hrgn, OBJECT_OWNER_PUBLIC);
  2440. RGNOBJAPI ro(hrgn,FALSE);
  2441. if (ro.bValid())
  2442. {
  2443. #if DBG || defined(PRERELEASE)
  2444. //
  2445. // Make Sure USER is not going to give us a RGN bigger than the surface
  2446. // Note: USER may select a bogus rgn in during ReleaseDC time, we don't want
  2447. // to assert there.
  2448. //
  2449. // To make things easy, we only check for single monitors
  2450. //
  2451. PDEVOBJ pdo(dco.hdev());
  2452. if (pdo.bValid() && !pdo.bMetaDriver())
  2453. {
  2454. UINT uiIndex = (UINT) HmgIfromH((HOBJ)hdc);
  2455. PENTRY pentTmp = &gpentHmgr[uiIndex];
  2456. SURFACE *pSurf = dco.pSurface();
  2457. if (pSurf &&
  2458. dco.pdc->bValidateVisrgn() &&
  2459. (OBJECTOWNER_PID(pentTmp->ObjectOwner) != OBJECT_OWNER_NONE))
  2460. {
  2461. BOOL bIsOK = ((pSurf->sizl().cx >= ro.prgn->rcl.right) &&
  2462. (pSurf->sizl().cy >= ro.prgn->rcl.bottom)&&
  2463. (ro.prgn->rcl.left >= 0) &&
  2464. (ro.prgn->rcl.top >= 0));
  2465. FREASSERTGDI(bIsOK, "Rgn size is bigger than surface size");
  2466. }
  2467. }
  2468. #endif
  2469. switch (fl)
  2470. {
  2471. case SVR_COPYNEW:
  2472. {
  2473. //
  2474. // We need to make a copy of the new one and delete the old one
  2475. //
  2476. RGNMEMOBJ rmo(ro.sizeRgn());
  2477. if (!rmo.bValid())
  2478. {
  2479. prgn = prgnDefault;
  2480. }
  2481. else
  2482. {
  2483. rmo.vCopy(ro);
  2484. prgn = rmo.prgnGet();
  2485. }
  2486. }
  2487. break;
  2488. case SVR_SWAP:
  2489. {
  2490. //
  2491. // we need to just swap handles. No deletion.
  2492. //
  2493. prgn = dco.pdc->prgnVis();
  2494. if (prgn == NULL)
  2495. {
  2496. prgn = prgnDefault;
  2497. }
  2498. //
  2499. // don't swap out prgnDefault
  2500. //
  2501. if (prgn != prgnDefault)
  2502. {
  2503. RGNOBJ roVis(prgn);
  2504. ro.bSwap(&roVis);
  2505. //
  2506. // roVis now contains the new vis rgn and the old visrgn
  2507. // is associated with hrgn.
  2508. //
  2509. prgn = roVis.prgnGet();
  2510. bDeleteOld = FALSE;
  2511. }
  2512. else
  2513. {
  2514. bRet = FALSE;
  2515. }
  2516. }
  2517. break;
  2518. case SVR_DELETEOLD:
  2519. //
  2520. // delete the old handle but keep the region
  2521. //
  2522. prgn = ro.prgnGet();
  2523. if (ro.bDeleteHandle())
  2524. ro.vSetRgn(NULL);
  2525. break;
  2526. }
  2527. }
  2528. else
  2529. {
  2530. RIP("Bad hrgn");
  2531. prgn = prgnDefault;
  2532. }
  2533. // see if we need to delete the old one
  2534. if (bDeleteOld)
  2535. {
  2536. dco.pdc->vReleaseVis();
  2537. }
  2538. // set the new one in.
  2539. dco.pdc->prgnVis(prgn);
  2540. prgn->vStamp();
  2541. }
  2542. else
  2543. {
  2544. //
  2545. // User called GreSelectVisRgn after CreateRectRgn without
  2546. // checking return value, so may have NULL hrgn here.
  2547. //
  2548. #if DBG
  2549. if (fl != SVR_DELETEOLD)
  2550. {
  2551. WARNING("GreSelectVisRgn - fl != SVR_DELETEOLD");
  2552. }
  2553. #endif
  2554. dco.pdc->vReleaseVis();
  2555. dco.pdc->bSetDefaultRegion();
  2556. }
  2557. }
  2558. rl.vRet((ULONG_PTR)bRet);
  2559. return(bRet);
  2560. }
  2561. /******************************Public*Routine******************************\
  2562. * GreCopyVisVisRgn()
  2563. *
  2564. * History:
  2565. * 11-Jan-1995 -by- Eric Kutter [erick]
  2566. * Wrote it.
  2567. \**************************************************************************/
  2568. int GreCopyVisRgn(
  2569. HDC hdc,
  2570. HRGN hrgn)
  2571. {
  2572. RGNLOG rl(hrgn,NULL,"GreCopyVisRgn",(ULONG_PTR)hdc,0);
  2573. int iRet = ERROR;
  2574. DCOBJA dco(hdc); // Use ALT_LOCK on DC
  2575. RGNOBJAPI ro(hrgn,FALSE);
  2576. ASSERTDEVLOCK(dco.pdc);
  2577. if (dco.bValid() && ro.bValid())
  2578. {
  2579. RGNOBJ roVis(dco.pdc->prgnVis());
  2580. if (roVis.bValid() && ro.bCopy(roVis))
  2581. iRet = ro.iComplexity();
  2582. }
  2583. return(iRet);
  2584. }
  2585. /******************************Public*Routine******************************\
  2586. * LONG GreGetClipBox(hdc,prcl,fXForm)
  2587. *
  2588. * Get the bounding box of the clip region
  2589. *
  2590. \**************************************************************************/
  2591. int
  2592. APIENTRY
  2593. GreGetClipBox(
  2594. HDC hdc,
  2595. LPRECT prcl,
  2596. BOOL fXForm)
  2597. {
  2598. GDITraceHandle(GreGetClipBox, "(%X, %p, %X)\n", (va_list)&hdc, hdc);
  2599. int iRet = ERROR;
  2600. int iSaveLeft;
  2601. DCOBJ dor(hdc);
  2602. if (dor.bValid())
  2603. {
  2604. DEVLOCKOBJ dlo(dor);
  2605. if (!dlo.bValid())
  2606. {
  2607. prcl->left = 0; // Make it a 'simple' empty rectangle
  2608. prcl->right = 0;
  2609. prcl->top = 0;
  2610. prcl->bottom = 0;
  2611. if (dor.bFullScreen())
  2612. iRet = NULLREGION;
  2613. }
  2614. else
  2615. {
  2616. RGNOBJ ro(dor.prgnEffRao());
  2617. ro.vGet_rcl((RECTL *) prcl);
  2618. // First convert from screen to device coordinates
  2619. if ((prcl->left >= prcl->right) || (prcl->top >= prcl->bottom))
  2620. {
  2621. prcl->left = 0; // Make it a 'simple' empty rectangle
  2622. prcl->right = 0;
  2623. prcl->top = 0;
  2624. prcl->bottom = 0;
  2625. }
  2626. else
  2627. {
  2628. *(ERECTL *)prcl -= dor.eptlOrigin();
  2629. // If requested, convert from device to logical coordinates.
  2630. if (fXForm)
  2631. {
  2632. EXFORMOBJ xfoDtoW(dor, DEVICE_TO_WORLD);
  2633. if (xfoDtoW.bValid())
  2634. {
  2635. xfoDtoW.bXform(*(ERECTL *)prcl);
  2636. }
  2637. }
  2638. if (MIRRORED_DC(dor.pdc) && (prcl->left > prcl->right)) {
  2639. iSaveLeft = prcl->left;
  2640. prcl->left = prcl->right;
  2641. prcl->right = iSaveLeft;
  2642. }
  2643. }
  2644. iRet = ro.iComplexity();
  2645. }
  2646. GDITrace(GreGetClipBox, " returns (%d, %d) - (%d %d)\n", (va_list)prcl);
  2647. }
  2648. return(iRet);
  2649. }
  2650. /******************************Public*Routine******************************\
  2651. * int GreSubtractRgnRectList(hrgn, prcl, arcl, crcl)
  2652. *
  2653. * Quickly subtract the list of rectangles from the first rectangle to
  2654. * produce a region.
  2655. *
  2656. \**************************************************************************/
  2657. int
  2658. GreSubtractRgnRectList(
  2659. HRGN hrgn,
  2660. LPRECT prcl,
  2661. LPRECT arcl,
  2662. int crcl)
  2663. {
  2664. GDITraceHandle(GreSubtractRgnRectList, "(%X, %p, %p, %d)\n", (va_list)&hrgn, hrgn);
  2665. RGNLOG rl(hrgn,NULL,"GreSubtractRgnRectList",crcl);
  2666. RGNOBJAPI ro(hrgn,FALSE);
  2667. int iRet;
  2668. if (!ro.bValid() || !ro.bSubtract((RECTL *) prcl, (RECTL *) arcl, crcl))
  2669. {
  2670. // If bSubtract fails, clean up the target region for USER.
  2671. if (ro.bValid())
  2672. ro.vSet();
  2673. iRet = ERROR;
  2674. }
  2675. else
  2676. {
  2677. iRet = ro.iComplexity();
  2678. }
  2679. rl.vRet(iRet);
  2680. return(iRet);
  2681. }