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.

809 lines
24 KiB

  1. /*****************************************************************************
  2. *
  3. * regions - Entry points for Win32 to Win 16 converter
  4. *
  5. * Date: 7/1/91
  6. * Author: Jeffrey Newman (c-jeffn)
  7. *
  8. * Copyright 1991 Microsoft Corp
  9. *
  10. * NOTES:
  11. *
  12. When there are no embedded metafiles we need to do the following:
  13. 1] Read the metafile data from the Win32 metafile. This
  14. is done by the handler routines that in turn call these
  15. routines.
  16. 2] Translate the Win32 metafile data into Win16 metafile data.
  17. The region data for FillRgn, FrameRgn, InvertRgn, and PaintRgn
  18. are in record-time world coordinates. The region data for
  19. these region API's will have to be translated from record-time
  20. -world coordinates to play-time-page coordinates
  21. (XFORM_WORLD_TO_PAGE). The helperDC will be used for
  22. this transformation.
  23. The region data for SelectClipRgn and OffsetClipRgn are in
  24. record-time device coordinates. The region data for these
  25. APIs will be translated from record-time-device coordinates
  26. to play-time-device coordinates.
  27. 3] Emit a Win16 create region metafile record.
  28. 4] Select the newly created region into the metafile.
  29. 5] Do the region function (FillRegion, FrameRegion, ...).
  30. This means emit a FillRegion or FrameRegion drawing order
  31. into the Win16 metafile.
  32. 6] Emit a Delete Region drawing order.
  33. 7] Clean up all the memory resources used.
  34. When there are embedded metafiles things get a little more complicated.
  35. Most of the complications are hidden in PlayMetafile record processing.
  36. Items 1 thru 3 will be handled by the PlayMetafile Doer.
  37. 1] We need to keep the region from the previous DC level.
  38. This can be done by the helper DC (SaveDC). We will have to
  39. do a GetClipRgn and a SelectMetaRgn. A MetaRgn is the clip
  40. region from the previous level.
  41. 2] We will have to intersect any clip regions from the current
  42. level with any clip regions from the previous level. This can
  43. be done by the helper DC (using the hrgnMeta & ExtCombineRegion)
  44. 3] When we pop out from this level we will have to restore the
  45. previous saved region. This can be done by the helper DC.
  46. (RestoreDC).
  47. Since we do not know whether or not there will be an embedded metafile
  48. in the metafile we are currently processing we will always shadow
  49. the Clip Region call into the helper DC.
  50. *****************************************************************************/
  51. #include "precomp.h"
  52. #pragma hdrstop
  53. BOOL bEmitWin3Region(PLOCALDC pLocalDC, HRGN hrgn);
  54. extern fnSetVirtualResolution pfnSetVirtualResolution;
  55. #define MIN_RGN_COORD16 -30000
  56. #define MAX_RGN_COORD16 30000
  57. /***************************************************************************
  58. * DoDrawRgn
  59. *
  60. * CR1: This routine was added as part of the handle manager change.
  61. * I noticed that almost all of the Region Rendering code was
  62. * the same.
  63. **************************************************************************/
  64. BOOL APIENTRY DoDrawRgn
  65. (
  66. PLOCALDC pLocalDC,
  67. INT ihBrush,
  68. INT nWidth,
  69. INT nHeight,
  70. INT cRgnData,
  71. LPRGNDATA pRgnData,
  72. INT mrType
  73. )
  74. {
  75. BOOL b ;
  76. HRGN hrgn = (HRGN) 0;
  77. INT ihW16Rgn = -1,
  78. ihW16Brush = -1;
  79. b = FALSE ;
  80. // Translate the Win32 region data from Metafile-World to
  81. // Referencd-Page space.
  82. // This is done by ExtCreateRegion's xform. The returned region
  83. // is transformed.
  84. hrgn = ExtCreateRegion(&pLocalDC->xformRWorldToPPage, cRgnData,
  85. (LPRGNDATA) pRgnData);
  86. if (!hrgn)
  87. {
  88. RIPS("MF3216: DoDrawRgn, ExtCreateRegion failed\n") ;
  89. goto error_exit ;
  90. }
  91. // Allocate a handle for the region.
  92. // This is different from a normal handle allocation, because
  93. // there is no region handle in Win32. We are using one of our
  94. // extra slots here.
  95. ihW16Rgn = iGetW16ObjectHandleSlot(pLocalDC, REALIZED_REGION) ;
  96. if (ihW16Rgn == -1)
  97. goto error_exit ;
  98. // Emit a Win16 create region record for the region.
  99. if (!bEmitWin3Region(pLocalDC, hrgn))
  100. {
  101. RIPS("MF3216: DoDrawRgn, bEmitWin3Region failed\n") ;
  102. goto error_exit ;
  103. }
  104. // Translate the W32 Brush object index to a W16 Brush object index.
  105. if (ihBrush)
  106. {
  107. // Make sure that the W16 object exists. Stock brushes may not
  108. // have been created and iValidateHandle will take care of creating
  109. // them.
  110. ihW16Brush = iValidateHandle(pLocalDC, ihBrush) ;
  111. if (ihW16Brush == -1)
  112. goto error_exit ;
  113. }
  114. // Emit the Region Record depending upon the function type.
  115. switch (mrType)
  116. {
  117. case EMR_FILLRGN:
  118. if(ihW16Brush == -1)
  119. goto error_exit;
  120. b = bEmitWin16FillRgn(pLocalDC,
  121. LOWORD(ihW16Rgn),
  122. LOWORD(ihW16Brush)) ;
  123. break ;
  124. case EMR_FRAMERGN:
  125. nWidth = iMagnitudeXform (pLocalDC, nWidth, CX_MAG) ;
  126. nHeight = iMagnitudeXform (pLocalDC, nHeight, CY_MAG) ;
  127. if(ihW16Brush == -1)
  128. goto error_exit;
  129. b = bEmitWin16FrameRgn(pLocalDC,
  130. LOWORD(ihW16Rgn),
  131. LOWORD(ihW16Brush),
  132. LOWORD(nWidth),
  133. LOWORD(nHeight)) ;
  134. break ;
  135. case EMR_INVERTRGN:
  136. b = bEmitWin16InvertRgn(pLocalDC,
  137. LOWORD(ihW16Rgn)) ;
  138. break ;
  139. case EMR_PAINTRGN:
  140. b = bEmitWin16PaintRgn(pLocalDC,
  141. LOWORD(ihW16Rgn)) ;
  142. break ;
  143. default:
  144. RIPS("MF3216: DoDrawRgn, unknown type\n") ;
  145. break ;
  146. }
  147. error_exit:
  148. // Delete the W16 Region Object.
  149. if (ihW16Rgn != -1)
  150. bDeleteW16Object(pLocalDC, ihW16Rgn) ;
  151. if (hrgn)
  152. DeleteObject(hrgn) ;
  153. return(b) ;
  154. }
  155. /***************************************************************************
  156. * ExtSelectClipRgn - Win32 to Win16 Metafile Converter Entry Point
  157. *
  158. * History:
  159. * Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
  160. * Wrote it.
  161. **************************************************************************/
  162. BOOL WINAPI DoExtSelectClipRgn
  163. (
  164. PLOCALDC pLocalDC,
  165. INT cRgnData,
  166. LPRGNDATA pRgnData,
  167. INT iMode
  168. )
  169. {
  170. HANDLE hrgn;
  171. BOOL bRet;
  172. BOOL bNoClipRgn ;
  173. WORD wEscape ;
  174. if(pLocalDC->iXORPass == DRAWXORPASS)
  175. {
  176. pLocalDC->iXORPass = OBJECTRECREATION ;
  177. bRet = DoRemoveObjects( pLocalDC ) ;
  178. if( !bRet )
  179. return bRet ;
  180. //Restore the DC to the same level that it was in when we started the
  181. //XOR pass
  182. bRet = DoRestoreDC(pLocalDC, pLocalDC->iXORPassDCLevel - pLocalDC->iLevel);
  183. bRet = DoMoveTo(pLocalDC, pLocalDC->pOldPosition.x, pLocalDC->pOldPosition.y) ;
  184. wEscape = ENDPSIGNORE;
  185. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  186. return FALSE ;
  187. wEscape = CLIP_SAVE ;
  188. if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  189. return FALSE ;
  190. return bRet;
  191. }
  192. else if(pLocalDC->iXORPass == ERASEXORPASS)
  193. {
  194. pLocalDC->iXORPass = NOTXORPASS ;
  195. pLocalDC->pbChange = NULL ;
  196. bRet = DoSetRop2(pLocalDC, pLocalDC->iROP);
  197. //bRet = DoRestoreDC(pLocalDC, -1);
  198. wEscape = CLIP_RESTORE ;
  199. if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  200. return FALSE ;
  201. if (!bEmitWin16EmitSrcCopyComment(pLocalDC, msocommentEndSrcCopy))
  202. {
  203. return FALSE;
  204. }
  205. return bRet ;
  206. }
  207. bNoClipRgn = bNoDCRgn(pLocalDC, DCRGN_CLIP);
  208. // Do it to the helper DC.
  209. // Restore the PS clippath
  210. wEscape = CLIP_RESTORE ;
  211. while(pLocalDC->iSavePSClipPath > 0)
  212. {
  213. bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL);
  214. pLocalDC->iSavePSClipPath--;
  215. }
  216. if (cRgnData == 0) // default clipping
  217. {
  218. ASSERTGDI(iMode == RGN_COPY, "MF3216: DoExtSelectClipRgn: bad iMode\n");
  219. // No work if no previous clip region.
  220. if (bNoClipRgn)
  221. return(TRUE);
  222. bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, (HRGN)0, iMode) != ERROR);
  223. return(bW16Emit1(pLocalDC, META_SELECTCLIPREGION, 0));
  224. }
  225. else
  226. {
  227. // If there is no initial clip region and we are going to operate
  228. // on the initial clip region, we have to
  229. // create one. Otherwise, GDI will create some random default
  230. // clipping region for us!
  231. if (bNoClipRgn
  232. && (iMode == RGN_DIFF || iMode == RGN_XOR || iMode == RGN_OR))
  233. {
  234. HRGN hrgnDefault;
  235. if (!(hrgnDefault = CreateRectRgn((int) (SHORT) MINSHORT,
  236. (int) (SHORT) MINSHORT,
  237. (int) (SHORT) MAXSHORT,
  238. (int) (SHORT) MAXSHORT)))
  239. {
  240. ASSERTGDI(FALSE, "MF3216: CreateRectRgn failed");
  241. return(FALSE);
  242. }
  243. bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, hrgnDefault, RGN_COPY)
  244. != ERROR);
  245. ASSERTGDI(bRet, "MF3216: ExtSelectClipRgn failed");
  246. if (!DeleteObject(hrgnDefault))
  247. ASSERTGDI(FALSE, "MF3216: DeleteObject failed");
  248. if (!bRet)
  249. return(FALSE);
  250. }
  251. // Create a region from the region data passed in.
  252. if (pfnSetVirtualResolution != NULL)
  253. {
  254. if (!(hrgn = ExtCreateRegion((LPXFORM) NULL, cRgnData, pRgnData)))
  255. {
  256. RIPS("MF3216: DoExtSelectClipRgn, Create region failed\n");
  257. return(FALSE);
  258. }
  259. }
  260. else
  261. {
  262. if (pRgnData->rdh.rcBound.left > pRgnData->rdh.rcBound.right ||
  263. pRgnData->rdh.rcBound.top > pRgnData->rdh.rcBound.bottom )
  264. {
  265. RIPS("MF3216: DoExtSelectClipRgn, Create region failed\n");
  266. return(FALSE);
  267. }
  268. // We need to create the region in Device Units for the helper DC
  269. // therefore add the xformDC to the transform
  270. if (!(hrgn = ExtCreateRegion(&pLocalDC->xformDC, cRgnData, pRgnData)))
  271. {
  272. RIPS("MF3216: DoExtSelectClipRgn, Create region failed\n");
  273. return(FALSE);
  274. }
  275. }
  276. bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, hrgn, iMode) != ERROR);
  277. ASSERTGDI(bRet, "MF3216: ExtSelectClipRgn failed\n");
  278. if (!DeleteObject(hrgn))
  279. RIPS("MF3216: DeleteObject failed\n");
  280. }
  281. // dump the clip region data.
  282. if (bRet)
  283. return(bDumpDCClipping(pLocalDC));
  284. else
  285. return(FALSE);
  286. }
  287. /***************************************************************************
  288. * SetMetaRgn - Win32 to Win16 Metafile Converter Entry Point
  289. *
  290. * History:
  291. * Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
  292. * Wrote it.
  293. **************************************************************************/
  294. BOOL WINAPI DoSetMetaRgn(PLOCALDC pLocalDC)
  295. {
  296. // No work if the clip region does not exist.
  297. if (bNoDCRgn(pLocalDC, DCRGN_CLIP))
  298. return(TRUE);
  299. // Do it to the helper DC.
  300. if (!SetMetaRgn(pLocalDC->hdcHelper))
  301. return(FALSE);
  302. // Dump the clip region data.
  303. return(bDumpDCClipping(pLocalDC));
  304. }
  305. /***************************************************************************
  306. * OffsetClipRgn - Win32 to Win16 Metafile Converter Entry Point
  307. *
  308. * History:
  309. * Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
  310. * Wrote it.
  311. **************************************************************************/
  312. BOOL WINAPI DoOffsetClipRgn(PLOCALDC pLocalDC, INT x, INT y)
  313. {
  314. POINTL aptl[2];
  315. BOOL b;
  316. // Do it to the helper DC.
  317. POINTL p[2] = {0, 0, x, y};
  318. if (pfnSetVirtualResolution == NULL)
  319. {
  320. if (!bXformWorkhorse(p, 2, &pLocalDC->xformRWorldToRDev))
  321. {
  322. return FALSE;
  323. }
  324. // We just want the scale factor of the WorldToDevice Transform
  325. p[1].x -= p[0].x;
  326. p[1].y -= p[0].y;
  327. }
  328. if (!OffsetClipRgn(pLocalDC->hdcHelper, p[1].x, p[1].y))
  329. return(FALSE);
  330. // Dump region if the meta region exists.
  331. // We don't offset the meta region!
  332. if (!bNoDCRgn(pLocalDC, DCRGN_META))
  333. return(bDumpDCClipping(pLocalDC));
  334. // Translate the record-time world offsets to play-time page offsets.
  335. aptl[0].x = 0;
  336. aptl[0].y = 0;
  337. aptl[1].x = x;
  338. aptl[1].y = y;
  339. if (!bXformRWorldToPPage(pLocalDC, aptl, 2))
  340. return(FALSE);
  341. aptl[1].x -= aptl[0].x;
  342. aptl[1].y -= aptl[0].y;
  343. b = bEmitWin16OffsetClipRgn(pLocalDC, (SHORT) aptl[1].x, (SHORT) aptl[1].y);
  344. ASSERTGDI(b, "MF3216: DoOffsetClipRgn, bEmitWin16OffsetClipRgn failed\n");
  345. return(b) ;
  346. }
  347. /***************************************************************************
  348. * bNoDCRgn - Return TRUE if the dc clip region does not exist.
  349. * Otherwise, return FALSE.
  350. * This is TEMPORARY only. Get gdi to provide this functionality.
  351. **************************************************************************/
  352. BOOL bNoDCRgn(PLOCALDC pLocalDC, INT iType)
  353. {
  354. BOOL bRet = FALSE; // assume the dc region exists
  355. HRGN hrgnTmp;
  356. ASSERTGDI(iType == DCRGN_CLIP || iType == DCRGN_META,
  357. "MF3216: bNoDCRgn, bad iType\n");
  358. if (!(hrgnTmp = CreateRectRgn(0, 0, 0, 0)))
  359. {
  360. ASSERTGDI(FALSE, "MF3216: bNoDCRgn, CreateRectRgn failed\n");
  361. return(bRet);
  362. }
  363. switch (GetRandomRgn(pLocalDC->hdcHelper,
  364. hrgnTmp,
  365. iType == DCRGN_CLIP ? 1 : 2
  366. )
  367. )
  368. {
  369. case -1: // error
  370. ASSERTGDI(FALSE, "GetRandomRgn failed");
  371. break;
  372. case 0: // no dc region
  373. bRet = TRUE;
  374. break;
  375. case 1: // has dc region
  376. break;
  377. }
  378. if (!DeleteObject(hrgnTmp))
  379. ASSERTGDI(FALSE, "DeleteObject failed");
  380. return(bRet);
  381. }
  382. /***************************************************************************
  383. * bDumpDCClipping - Dump the DC clipping regions.
  384. *
  385. * History:
  386. * Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
  387. * Wrote it.
  388. **************************************************************************/
  389. BOOL bDumpDCClipping(PLOCALDC pLocalDC)
  390. {
  391. BOOL bRet = FALSE; // assume failure
  392. HRGN hrgnRDev = (HRGN) 0;
  393. HRGN hrgnPPage = (HRGN) 0;
  394. HRGN hrgnPPageBounds = (HRGN) 0;
  395. LPRGNDATA lprgnRDev = (LPRGNDATA) NULL;
  396. LPRGNDATA lprgnPPage = (LPRGNDATA) NULL;
  397. DWORD cRgnData;
  398. INT i;
  399. INT nrcl;
  400. PRECTL prcl;
  401. RECTL rclPPage;
  402. XFORM xform;
  403. // Since clipping region is not scalable in Win30, we do not emit
  404. // SelectClipRgn record. Instead, we set the clipping to the default, i.e.
  405. // no clipping, and then emit the scalable IntersectClipRect/ExcludeClipRect
  406. // records to exclude clipping region. This will allow the win30 metafiles
  407. // to be scalable.
  408. // First, emit a default clipping region.
  409. // On Win3.x, the META_SELECTCLIPREGION record only works if it has
  410. // a NULL handle. The Win3x metafile driver does not translate the
  411. // region handle at playback time!
  412. if (!bW16Emit1(pLocalDC, META_SELECTCLIPREGION, 0))
  413. goto ddcc_exit;
  414. // Now find the clip and meta regions to be excluded from the default
  415. // clipping region.
  416. if (!(hrgnRDev = CreateRectRgn(0, 0, 0, 0)))
  417. goto ddcc_exit;
  418. switch (GetRandomRgn(pLocalDC->hdcHelper, hrgnRDev, 3)) // meta and clip
  419. {
  420. case -1: // error
  421. ASSERTGDI(FALSE, "GetRandomRgn failed");
  422. goto ddcc_exit;
  423. case 0: // no clip region, we are done
  424. bRet = TRUE;
  425. goto ddcc_exit;
  426. case 1: // has clip region
  427. break;
  428. }
  429. // Get the clip region data.
  430. // First query the size of the buffer required to hold the clip region data.
  431. if (!(cRgnData = GetRegionData(hrgnRDev, 0, (LPRGNDATA) NULL)))
  432. goto ddcc_exit;
  433. // Allocate the memory for the clip region data buffer.
  434. if (!(lprgnRDev = (LPRGNDATA) LocalAlloc(LMEM_FIXED, cRgnData)))
  435. goto ddcc_exit;
  436. // Get clip region data.
  437. if (GetRegionData(hrgnRDev, cRgnData, lprgnRDev) != cRgnData)
  438. goto ddcc_exit;
  439. // Create the clip region in the playtime page space.
  440. if (!(hrgnPPage = ExtCreateRegion(&pLocalDC->xformRDevToPPage, cRgnData, lprgnRDev)))
  441. goto ddcc_exit;
  442. // Get the bounding box for the playtime clip region in page space.
  443. if (GetRgnBox(hrgnPPage, (LPRECT) &rclPPage) == ERROR)
  444. goto ddcc_exit;
  445. // Bound it to 16-bit.
  446. rclPPage.left = max(MIN_RGN_COORD16,rclPPage.left);
  447. rclPPage.top = max(MIN_RGN_COORD16,rclPPage.top);
  448. rclPPage.right = min(MAX_RGN_COORD16,rclPPage.right);
  449. rclPPage.bottom = min(MAX_RGN_COORD16,rclPPage.bottom);
  450. // Set the bounding box as the bounds for the clipping.
  451. if (!bEmitWin16IntersectClipRect(pLocalDC,
  452. (SHORT) rclPPage.left,
  453. (SHORT) rclPPage.top,
  454. (SHORT) rclPPage.right,
  455. (SHORT) rclPPage.bottom))
  456. goto ddcc_exit;
  457. // Create the bounding region.
  458. if (!(hrgnPPageBounds = CreateRectRgn(rclPPage.left,
  459. rclPPage.top,
  460. rclPPage.right,
  461. rclPPage.bottom)))
  462. goto ddcc_exit;
  463. // Exclude the regions in playtime page space.
  464. if (CombineRgn(hrgnPPage, hrgnPPageBounds, hrgnPPage, RGN_DIFF) == ERROR)
  465. goto ddcc_exit;
  466. // Finally, exclude the rectangles from the bounding box.
  467. if (!(cRgnData = GetRegionData(hrgnPPage, 0, (LPRGNDATA) NULL)))
  468. goto ddcc_exit;
  469. if (!(lprgnPPage = (LPRGNDATA) LocalAlloc(LMEM_FIXED, cRgnData)))
  470. goto ddcc_exit;
  471. if (GetRegionData(hrgnPPage, cRgnData, lprgnPPage) != cRgnData)
  472. goto ddcc_exit;
  473. // Get the number of rectangles in the transformed region.
  474. nrcl = lprgnPPage->rdh.nCount;
  475. prcl = (PRECTL) lprgnPPage->Buffer;
  476. // Emit a series of Exclude Clip Rectangle Metafile records.
  477. for (i = 0 ; i < nrcl; i++)
  478. {
  479. ASSERTGDI(prcl[i].left >= MIN_RGN_COORD16
  480. && prcl[i].top >= MIN_RGN_COORD16
  481. && prcl[i].right <= MAX_RGN_COORD16
  482. && prcl[i].bottom <= MAX_RGN_COORD16,
  483. "MF3216: bad coord");
  484. if (!bEmitWin16ExcludeClipRect(pLocalDC,
  485. (SHORT) prcl[i].left,
  486. (SHORT) prcl[i].top,
  487. (SHORT) prcl[i].right,
  488. (SHORT) prcl[i].bottom))
  489. goto ddcc_exit;
  490. }
  491. bRet = TRUE; // we are golden!
  492. // Cleanup all the resources used.
  493. ddcc_exit:
  494. if (hrgnRDev)
  495. DeleteObject(hrgnRDev);
  496. if (hrgnPPage)
  497. DeleteObject(hrgnPPage);
  498. if (hrgnPPageBounds)
  499. DeleteObject(hrgnPPageBounds);
  500. if (lprgnRDev)
  501. LocalFree(lprgnRDev);
  502. if (lprgnPPage)
  503. LocalFree(lprgnPPage);
  504. return(bRet) ;
  505. }
  506. /***************************************************************************
  507. * Emit a 16-bit CreateRegion record for the given region.
  508. *
  509. * This code is copied from the 16-bit metafile driver in gdi.
  510. *
  511. **************************************************************************/
  512. WIN3REGION w3rgnEmpty =
  513. {
  514. 0, // nextInChain
  515. 6, // ObjType
  516. 0x2F6, // ObjCount
  517. sizeof(WIN3REGION) - sizeof(SCAN) + 2,
  518. // cbRegion
  519. 0, // cScans
  520. 0, // maxScan
  521. {0,0,0,0}, // rcBounding
  522. {0,0,0,{0,0},0} // aScans[]
  523. };
  524. BOOL bEmitWin3Region(PLOCALDC pLocalDC, HRGN hrgn)
  525. {
  526. /*
  527. * in win2, METACREATEREGION records contained an entire region object,
  528. * including the full header. this header changed in win3.
  529. *
  530. * to remain compatible, the region records will be saved with the
  531. * win2 header. here we save our region with a win2 header.
  532. */
  533. PWIN3REGION lpw3rgn;
  534. DWORD cbNTRgnData;
  535. DWORD curRectl;
  536. WORD cScans;
  537. WORD maxScanEntry;
  538. WORD curScanEntry;
  539. DWORD cbw3data;
  540. PRGNDATA lprgn;
  541. LPRECT lprc;
  542. PSCAN lpScan;
  543. BOOL bRet;
  544. ASSERTGDI(hrgn, "MF3216: bEmitWin3Region, hrgn is NULL");
  545. // Get the NT Region Data
  546. cbNTRgnData = GetRegionData(hrgn, 0, NULL);
  547. if (cbNTRgnData == 0)
  548. return(FALSE);
  549. lprgn = (PRGNDATA) LocalAlloc(LMEM_FIXED, cbNTRgnData);
  550. if (!lprgn)
  551. return(FALSE);
  552. cbNTRgnData = GetRegionData(hrgn, cbNTRgnData, lprgn);
  553. if (cbNTRgnData == 0)
  554. {
  555. LocalFree((HANDLE) lprgn);
  556. return(FALSE);
  557. }
  558. // Handle the empty region.
  559. if (!lprgn->rdh.nCount)
  560. {
  561. bRet = bEmitWin16CreateRegion(pLocalDC, sizeof(WIN3REGION) - sizeof(SCAN), (PVOID) &w3rgnEmpty);
  562. LocalFree((HANDLE)lprgn);
  563. return(bRet);
  564. }
  565. lprc = (LPRECT)lprgn->Buffer;
  566. // Create the Windows 3.x equivalent
  567. // worst case is one scan for each rect
  568. cbw3data = 2*sizeof(WIN3REGION) + (WORD)lprgn->rdh.nCount*sizeof(SCAN);
  569. lpw3rgn = (PWIN3REGION)LocalAlloc(LMEM_FIXED, cbw3data);
  570. if (!lpw3rgn)
  571. {
  572. LocalFree((HANDLE) lprgn);
  573. return(FALSE);
  574. }
  575. // Grab the bounding rect.
  576. lpw3rgn->rcBounding.left = (SHORT)lprgn->rdh.rcBound.left;
  577. lpw3rgn->rcBounding.right = (SHORT)lprgn->rdh.rcBound.right;
  578. lpw3rgn->rcBounding.top = (SHORT)lprgn->rdh.rcBound.top;
  579. lpw3rgn->rcBounding.bottom = (SHORT)lprgn->rdh.rcBound.bottom;
  580. cbw3data = sizeof(WIN3REGION) - sizeof(SCAN) + 2;
  581. // visit all the rects
  582. curRectl = 0;
  583. cScans = 0;
  584. maxScanEntry = 0;
  585. lpScan = lpw3rgn->aScans;
  586. while(curRectl < lprgn->rdh.nCount)
  587. {
  588. LPWORD lpXEntry;
  589. DWORD cbScan;
  590. curScanEntry = 0; // Current X pair in this scan
  591. lpScan->scnPntTop = (WORD)lprc[curRectl].top;
  592. lpScan->scnPntBottom = (WORD)lprc[curRectl].bottom;
  593. lpXEntry = (LPWORD) lpScan->scnPntsX;
  594. // handle rects on this scan
  595. do
  596. {
  597. lpXEntry[curScanEntry + 0] = (WORD)lprc[curRectl].left;
  598. lpXEntry[curScanEntry + 1] = (WORD)lprc[curRectl].right;
  599. curScanEntry += 2;
  600. curRectl++;
  601. } while ((curRectl < lprgn->rdh.nCount)
  602. && (lprc[curRectl-1].top == lprc[curRectl].top)
  603. && (lprc[curRectl-1].bottom == lprc[curRectl].bottom)
  604. );
  605. lpScan->scnPntCnt = curScanEntry;
  606. lpXEntry[curScanEntry] = curScanEntry; // Count also follows Xs
  607. cScans++;
  608. if (curScanEntry > maxScanEntry)
  609. maxScanEntry = curScanEntry;
  610. // account for each new scan + each X1 X2 Entry but the first
  611. cbScan = sizeof(SCAN)-(sizeof(WORD)*2) + (curScanEntry*sizeof(WORD));
  612. cbw3data += cbScan;
  613. lpScan = (PSCAN)(((LPBYTE)lpScan) + cbScan);
  614. }
  615. // Initialize the header
  616. lpw3rgn->nextInChain = 0;
  617. lpw3rgn->ObjType = 6; // old Windows OBJ_RGN identifier
  618. lpw3rgn->ObjCount= 0x2F6; // any non-zero number
  619. lpw3rgn->cbRegion = (WORD)cbw3data; // don't count type and next
  620. lpw3rgn->cScans = cScans;
  621. lpw3rgn->maxScan = maxScanEntry;
  622. bRet = bEmitWin16CreateRegion(pLocalDC, cbw3data-2, (PVOID) lpw3rgn);
  623. if (LocalFree((HANDLE)lprgn))
  624. ASSERTGDI(FALSE, "bEmitWin3Region: LocalFree(lprgn) Failed\n");
  625. if (LocalFree((HANDLE)lpw3rgn))
  626. ASSERTGDI(FALSE, "bEmitWin3Region: LocalFree(lpw3rgn) Failed\n");
  627. return(bRet);
  628. }