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.

664 lines
22 KiB

  1. //-------------------------------------------------------------------------//
  2. // Rgn.cpp - Bitmap-to-Region transforms
  3. //
  4. // History:
  5. // 01/31/2000 scotthan created
  6. //-------------------------------------------------------------------------//
  7. #include "stdafx.h"
  8. #include "rgn.h"
  9. #include "tmutils.h"
  10. //------------//
  11. // Helpers:
  12. //-------------------------------------------------------------------------//
  13. #define CX_USEDEFAULT -1
  14. #define CY_USEDEFAULT -1
  15. #define _ABS( val1, val2 ) ((val1)>(val2) ? (val1)-(val2) : (val2)-(val1))
  16. //-------------------------------------------------------------------------//
  17. inline BOOL IsColorMatch( COLORREF rgb1, COLORREF rgb2, int nTolerance = 0 )
  18. {
  19. if( nTolerance == 0 )
  20. return (rgb1 << 8) == (rgb2 << 8);
  21. return _ABS(GetRValue(rgb1),GetRValue(rgb2)) <= nTolerance &&
  22. _ABS(GetGValue(rgb1),GetGValue(rgb2)) <= nTolerance &&
  23. _ABS(GetBValue(rgb1),GetBValue(rgb2)) <= nTolerance;
  24. }
  25. //-------------------------------------------------------------------------//
  26. inline BOOL _IsNormalRect( IN LPCRECT prc )
  27. {
  28. return (prc->right >= prc->left) &&
  29. (prc->bottom >= prc->top);
  30. }
  31. //-------------------------------------------------------------------------//
  32. inline BOOL _IsOnScreenRect( IN LPCRECT prc )
  33. {
  34. return prc->left >= 0 && prc->top >= 0 &&
  35. prc->right >= 0 && prc->bottom >= 0;
  36. }
  37. //-------------------------------------------------------------------------//
  38. inline void _InPlaceUnionRect( IN OUT LPRECT prcDest, IN LPCRECT prcSrc )
  39. {
  40. ASSERT(prcDest);
  41. ASSERT(prcSrc);
  42. ASSERT(_IsNormalRect(prcSrc));
  43. if( prcDest->left == -1 || prcDest->left > prcSrc ->left )
  44. prcDest->left = prcSrc ->left;
  45. if( prcDest->right == -1 || prcDest->right < prcSrc ->right )
  46. prcDest->right = prcSrc ->right;
  47. if( prcDest->top == -1 || prcDest->top > prcSrc ->top )
  48. prcDest->top = prcSrc ->top;
  49. if( prcDest->bottom == -1 || prcDest->bottom < prcSrc ->bottom )
  50. prcDest->bottom = prcSrc ->bottom;
  51. }
  52. //-------------------------------------------------------------------------//
  53. // Walks the pixels and computes the region
  54. HRGN WINAPI _PixelsToRgn(
  55. DWORD *pdwBits,
  56. int cxImageOffset, // image cell horz offset
  57. int cyImageOffset, // image cell vert offset
  58. int cxImage, // image cell width
  59. int cyImage, // image cell height
  60. int cxSrc, // src bitmap width
  61. int cySrc, // src bitmap height
  62. BOOL fAlphaChannel,
  63. int iAlphaThreshold,
  64. COLORREF rgbMask,
  65. int nMaskTolerance )
  66. {
  67. // Establish a series of rectangles, each corresponding to a scan line (row)
  68. // in the bitmap, that will comprise the region.
  69. const UINT RECTBLOCK = 512;
  70. UINT nAllocRects = 0;
  71. HRGN hrgnRet = NULL;
  72. HGLOBAL hrgnData = GlobalAlloc( GMEM_MOVEABLE,
  73. sizeof(RGNDATAHEADER) + (sizeof(RECT) * (nAllocRects + RECTBLOCK)) );
  74. if( hrgnData )
  75. {
  76. nAllocRects += RECTBLOCK;
  77. RGNDATA* prgnData = (RGNDATA*)GlobalLock( hrgnData );
  78. LPRECT prgrc = (LPRECT)prgnData->Buffer;
  79. ZeroMemory( &prgnData->rdh, sizeof(prgnData->rdh) );
  80. prgnData->rdh.dwSize = sizeof(prgnData->rdh);
  81. prgnData->rdh.iType = RDH_RECTANGLES;
  82. SetRect( &prgnData->rdh.rcBound, -1, -1, -1, -1 );
  83. // invert offset in y dimension since bits are arrayed bottom to top
  84. int cyRow0 = cySrc - (cyImage + cyImageOffset);
  85. int cyRowN = (cyRow0 + cyImage) - 1 ; // index of the last row
  86. // Compute a transparency mask if not specified.
  87. if( -1 == rgbMask )
  88. rgbMask = pdwBits[cxImageOffset + (cyRowN * cxSrc)];
  89. //---- pixels in pdwBits[] have RBG's reversed ----
  90. //---- reverse our mask to match ----
  91. rgbMask = REVERSE3(rgbMask);
  92. //---- rows in pdwBits[] are reversed (bottom to top) ----
  93. for( int y = cyRow0; y <= cyRowN; y++ ) // working bottom-to-top
  94. {
  95. //---- Scanning pixels left to right ----
  96. DWORD *pdwFirst = &pdwBits[cxImageOffset + (y * cxSrc)];
  97. DWORD *pdwLast = pdwFirst + cxImage - 1;
  98. DWORD *pdwPixel = pdwFirst;
  99. while (pdwPixel <= pdwLast)
  100. {
  101. //---- skip TRANSPARENT pixels to find next OPAQUE (on this row) ----
  102. if (fAlphaChannel)
  103. {
  104. while ((pdwPixel <= pdwLast) && (ALPHACHANNEL(*pdwPixel) < iAlphaThreshold))
  105. pdwPixel++;
  106. }
  107. else
  108. {
  109. while ((pdwPixel <= pdwLast) && (IsColorMatch(*pdwPixel, rgbMask, nMaskTolerance)))
  110. pdwPixel++;
  111. }
  112. if (pdwPixel > pdwLast) // too far; try next row
  113. break;
  114. DWORD *pdw0 = pdwPixel;
  115. pdwPixel++; // skip over current opaque pixel
  116. //---- skip OPAQUE pixels to find next TRANSPARENT (on this row) ----
  117. if (fAlphaChannel)
  118. {
  119. while ((pdwPixel <= pdwLast) && (ALPHACHANNEL(*pdwPixel) >= iAlphaThreshold))
  120. pdwPixel++;
  121. }
  122. else
  123. {
  124. while ((pdwPixel <= pdwLast) && (! IsColorMatch(*pdwPixel, rgbMask, nMaskTolerance)))
  125. pdwPixel++;
  126. }
  127. //---- got a stream of 1 or more opaque pixels on this row ----
  128. // allocate more region rects if necessary (a particularly complex line)
  129. if( prgnData->rdh.nCount >= nAllocRects )
  130. {
  131. GlobalUnlock( hrgnData );
  132. prgnData = NULL;
  133. HGLOBAL hNew = GlobalReAlloc( hrgnData,
  134. sizeof(RGNDATAHEADER) + (sizeof(RECT) * (nAllocRects + RECTBLOCK)),
  135. GMEM_MOVEABLE );
  136. if( hNew )
  137. {
  138. hrgnData = hNew;
  139. nAllocRects += RECTBLOCK;
  140. prgnData = (RGNDATA*)GlobalLock( hrgnData );
  141. prgrc = (LPRECT)prgnData->Buffer;
  142. ASSERT(prgnData);
  143. }
  144. else
  145. goto exit; // out of memory
  146. }
  147. // assign region rectangle
  148. int x0 = (int)(pdw0 - pdwFirst);
  149. int x = (int)(pdwPixel - pdwFirst);
  150. int y0 = cyRowN - y;
  151. SetRect( prgrc + prgnData->rdh.nCount,
  152. x0, y0, x, y0+1 /* each rectangle is always 1 pixel high */ );
  153. // merge into bounding box
  154. _InPlaceUnionRect( &prgnData->rdh.rcBound,
  155. prgrc + prgnData->rdh.nCount );
  156. prgnData->rdh.nCount++;
  157. } // while ()
  158. } // for(y)
  159. if( prgnData->rdh.nCount && _IsOnScreenRect(&prgnData->rdh.rcBound) )
  160. {
  161. // Create the region representing the scan line.
  162. hrgnRet = ExtCreateRegion( NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nAllocRects),
  163. prgnData );
  164. }
  165. exit:
  166. // Free region def block.
  167. GlobalUnlock( hrgnData );
  168. GlobalFree( hrgnData );
  169. }
  170. return hrgnRet;
  171. }
  172. //-------------------------------------------------------------------------//
  173. // Creates a region based on a text string in the indicated font.
  174. HRGN WINAPI CreateTextRgn( HFONT hf, LPCTSTR pszText )
  175. {
  176. HRGN hrgnRet = NULL;
  177. if( pszText && *pszText )
  178. {
  179. int cchText = lstrlen( pszText );
  180. // Create a composite DC for assembling the region.
  181. HDC hdcMem = CreateCompatibleDC( NULL );
  182. SetBkMode( hdcMem, TRANSPARENT );
  183. SetTextAlign( hdcMem, TA_TOP|TA_LEFT );
  184. HFONT hfOld = (HFONT)SelectObject( hdcMem, hf );
  185. // Derive a region from a path.
  186. BeginPath( hdcMem );
  187. TextOut( hdcMem, 0, 0, pszText, cchText );
  188. EndPath( hdcMem );
  189. hrgnRet = PathToRegion( hdcMem );
  190. // Clean up composite DC
  191. SelectObject( hdcMem, hfOld );
  192. DeleteDC( hdcMem );
  193. }
  194. return hrgnRet;
  195. }
  196. //-------------------------------------------------------------------------//
  197. // Creates a region based on an arbitrary bitmap, transparency-keyed on a
  198. // RGB value within a specified tolerance. The key value is optional
  199. // (-1 == use the value of the first pixel as the key).
  200. //
  201. HRESULT WINAPI CreateBitmapRgn(
  202. HBITMAP hbm,
  203. int cxOffset,
  204. int cyOffset,
  205. int cx,
  206. int cy,
  207. BOOL fAlphaChannel,
  208. int iAlphaThreshold,
  209. COLORREF rgbMask,
  210. int nMaskTolerance,
  211. OUT HRGN *phrgn)
  212. {
  213. CBitmapPixels BitmapPixels;
  214. DWORD *prgdwPixels;
  215. int cwidth, cheight;
  216. HRESULT hr = BitmapPixels.OpenBitmap(NULL, hbm, TRUE, &prgdwPixels, &cwidth, &cheight);
  217. if (FAILED(hr))
  218. return hr;
  219. if (cx <= 0)
  220. cx = cwidth;
  221. if (cy <= 0)
  222. cy = cheight;
  223. HRGN hrgn = _PixelsToRgn(prgdwPixels, cxOffset, cyOffset, cx, cy, cwidth, cheight, fAlphaChannel,
  224. iAlphaThreshold, rgbMask, nMaskTolerance);
  225. if (! hrgn)
  226. return MakeError32(E_FAIL); // unknown reason for failure
  227. *phrgn = hrgn;
  228. return S_OK;
  229. }
  230. //-------------------------------------------------------------------------//
  231. // Creates a region based on an arbitrary bitmap, transparency-keyed on a
  232. // RGB value within a specified tolerance. The key value is optional (-1 ==
  233. // use the value of the first pixel as the key).
  234. //
  235. HRGN WINAPI CreateScaledBitmapRgn(
  236. HBITMAP hbm,
  237. int cx,
  238. int cy,
  239. COLORREF rgbMask,
  240. int nMaskTolerance )
  241. {
  242. HRGN hrgnRet = NULL;
  243. BITMAP bm;
  244. if( hbm && GetObject( hbm, sizeof(bm), &bm ) )
  245. {
  246. // Create a memory DC to do the pixel walk
  247. HDC hdcMem = NULL;
  248. if( (hdcMem = CreateCompatibleDC(NULL)) != NULL )
  249. {
  250. if( CX_USEDEFAULT == cx )
  251. cx = bm.bmWidth;
  252. if( CY_USEDEFAULT == cy )
  253. cy = bm.bmHeight;
  254. // Create a 32-bit empty bitmap for the walk
  255. BITMAPINFO bmi;
  256. ZeroMemory( &bmi, sizeof(bmi) );
  257. bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  258. bmi.bmiHeader.biWidth = cx;
  259. bmi.bmiHeader.biHeight = cy;
  260. bmi.bmiHeader.biPlanes = 1;
  261. bmi.bmiHeader.biBitCount = 32;
  262. bmi.bmiHeader.biCompression = BI_RGB; // uncompressed.
  263. VOID* pvBits = NULL;
  264. HBITMAP hbmMem = CreateDIBSection( hdcMem, &bmi, DIB_RGB_COLORS, &pvBits, NULL, NULL );
  265. BITMAP bmMem;
  266. if( hbmMem )
  267. {
  268. // Transfer the image to our 32-bit format for the pixel walk.
  269. HBITMAP hbmMemOld = (HBITMAP)SelectObject( hdcMem, hbmMem );
  270. HDC hdc = CreateCompatibleDC( hdcMem );
  271. HBITMAP hbmOld = (HBITMAP)SelectObject( hdc, hbm );
  272. StretchBlt( hdcMem, 0, 0, cx, cy,
  273. hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
  274. SelectObject( hdc, hbmOld );
  275. DeleteDC( hdc );
  276. GetObject( hbmMem, sizeof(bmMem), &bmMem );
  277. ASSERT(bmMem.bmBitsPixel == 32);
  278. ASSERT(bmMem.bmWidthBytes/bmMem.bmWidth == sizeof(DWORD));
  279. LPDWORD pdwBits = (LPDWORD)bmMem.bmBits;
  280. ASSERT(pdwBits != NULL);
  281. hrgnRet = _PixelsToRgn(pdwBits, 0, 0, cx, cy, cx, cy, FALSE, 0, rgbMask, nMaskTolerance);
  282. // Delete 32-bit memory bitmap
  283. SelectObject( hdcMem, hbmMemOld );
  284. DeleteObject( hbmMem );
  285. }
  286. // Delete memory DC
  287. DeleteDC(hdcMem);
  288. }
  289. }
  290. return hrgnRet;
  291. }
  292. //-------------------------------------------------------------------------//
  293. // crete a region built up from rectangular tiles
  294. HRGN WINAPI CreateTiledRectRgn(
  295. IN HRGN hrgnSrc,
  296. IN int cxSrc,
  297. IN int cySrc,
  298. IN int cxDest,
  299. IN int cyDest )
  300. {
  301. HRGN hrgnBound = NULL; // return value
  302. HRGN hrgnTile = _DupRgn( hrgnSrc );
  303. if( hrgnTile )
  304. {
  305. // Build up an unplaced, unclipped composite
  306. HRGN hrgnTmp = NULL;
  307. for( int y = 0; y < cyDest; y += cySrc )
  308. {
  309. for( int x = 0; x < cxDest; x += cxSrc )
  310. {
  311. AddToCompositeRgn( &hrgnTmp, hrgnTile,
  312. (x ? cxSrc : 0), (y ? cySrc : 0) );
  313. }
  314. }
  315. if( NULL != hrgnTmp )
  316. {
  317. // Clip the composite to the specified rectangle
  318. hrgnBound = CreateRectRgn( 0, 0, cxDest, cyDest );
  319. if( hrgnBound )
  320. {
  321. if( ERROR == CombineRgn( hrgnBound, hrgnTmp, hrgnBound, RGN_AND ) )
  322. {
  323. DeleteObject( hrgnBound );
  324. hrgnBound = NULL;
  325. }
  326. }
  327. DeleteObject( hrgnTmp );
  328. }
  329. DeleteObject( hrgnTile );
  330. }
  331. return hrgnBound;
  332. }
  333. //-------------------------------------------------------------------------//
  334. int WINAPI AddToCompositeRgn(
  335. IN OUT HRGN* phrgnComposite,
  336. IN OUT HRGN hrgnSrc,
  337. IN int cxOffset,
  338. IN int cyOffset )
  339. {
  340. int nRet = ERROR;
  341. if( NULL != phrgnComposite && NULL != hrgnSrc )
  342. {
  343. nRet = OffsetRgn( hrgnSrc, cxOffset, cyOffset );
  344. if( nRet != ERROR )
  345. {
  346. int nMode = RGN_OR;
  347. if( NULL == *phrgnComposite )
  348. {
  349. *phrgnComposite = CreateRectRgn(0,0,1,1);
  350. if( NULL == *phrgnComposite )
  351. return ERROR;
  352. nMode = RGN_COPY;
  353. }
  354. nRet = CombineRgn( *phrgnComposite, hrgnSrc, *phrgnComposite, nMode );
  355. }
  356. }
  357. return nRet;
  358. }
  359. //-------------------------------------------------------------------------//
  360. // removes a rectangle from a region.
  361. int WINAPI RemoveFromCompositeRgn(
  362. HRGN hrgnDest,
  363. LPCRECT prcRemove )
  364. {
  365. ASSERT(hrgnDest);
  366. ASSERT(prcRemove);
  367. ASSERT(!IsRectEmpty(prcRemove));
  368. int nRet = ERROR;
  369. RECT rc = *prcRemove;
  370. HRGN hrgn;
  371. if( (hrgn = CreateRectRgnIndirect( &rc )) != NULL )
  372. {
  373. nRet = CombineRgn( hrgnDest, hrgnDest, hrgn, RGN_DIFF );
  374. DeleteObject( hrgn );
  375. }
  376. return nRet;
  377. }
  378. //-------------------------------------------------------------------------//
  379. HRGN WINAPI _DupRgn( HRGN hrgnSrc )
  380. {
  381. if( hrgnSrc )
  382. {
  383. HRGN hrgnDest = CreateRectRgn(0,0,1,1);
  384. if (hrgnDest)
  385. {
  386. if (CombineRgn( hrgnDest, hrgnSrc, NULL, RGN_COPY ) )
  387. return hrgnDest;
  388. DeleteObject(hrgnDest);
  389. }
  390. }
  391. return NULL;
  392. }
  393. //-------------------------------------------------------------------------//
  394. void FixMarginOverlaps(int szDest, int *pm1, int *pm2)
  395. {
  396. int szSrc = (*pm1 + *pm2);
  397. if ((szSrc > szDest) && (szSrc > 0))
  398. {
  399. //---- reduce each but maintain ratio ----
  400. *pm1 = int(.5 + float(*pm1 * szDest)/float(szSrc));
  401. *pm2 = szDest - *pm1;
  402. }
  403. }
  404. //-------------------------------------------------------------------------//
  405. HRESULT _ScaleRectsAndCreateRegion(
  406. RGNDATA *prd,
  407. const RECT *prc,
  408. MARGINS *pMargins,
  409. SIZE *pszSrcImage,
  410. HRGN *phrgn)
  411. {
  412. //---- note: "prd" is region data with the 2 points in each ----
  413. //---- rectangle made relative to its grid. Also, after the points, ----
  414. //---- there is a BYTE for each point signifying the grid id (0-8) ----
  415. //---- that each point lies within. the grid is determined using ----
  416. //---- the original region with the background "margins". This is ----
  417. //---- done to make scaling the points as fast as possible. ----
  418. if (! prd) // required
  419. return MakeError32(E_POINTER);
  420. //---- easy access variables ----
  421. int lw = pMargins->cxLeftWidth;
  422. int rw = pMargins->cxRightWidth;
  423. int th = pMargins->cyTopHeight;
  424. int bh = pMargins->cyBottomHeight;
  425. int iDestW = WIDTH(*prc);
  426. int iDestH = HEIGHT(*prc);
  427. //---- prevent left/right dest margins from overlapping ----
  428. FixMarginOverlaps(iDestW, &lw, &rw);
  429. //---- prevent top/bottom dest margins from overlapping ----
  430. FixMarginOverlaps(iDestH, &th, &bh);
  431. int lwFrom = lw;
  432. int rwFrom = pszSrcImage->cx - rw;
  433. int thFrom = th;
  434. int bhFrom = pszSrcImage->cy - bh;
  435. int lwTo = prc->left + lw;
  436. int rwTo = prc->right - rw;
  437. int thTo = prc->top + th;
  438. int bhTo = prc->bottom - bh;
  439. //---- compute offsets & factors ----
  440. int iLeftXOffset = prc->left;
  441. int iMiddleXOffset = lwTo;
  442. int iRightXOffset = rwTo;
  443. int iTopYOffset = prc->top;
  444. int iMiddleYOffset = thTo;
  445. int iBottomYOffset = bhTo;
  446. int iToMiddleWidth = rwTo - lwTo;
  447. int iFromMiddleWidth = rwFrom - lwFrom;
  448. int iToMiddleHeight = bhTo - thTo;
  449. int iFromMiddleHeight = bhFrom - thFrom;
  450. if (! iFromMiddleWidth) // avoid divide by zero
  451. {
  452. //--- map point to x=0 ----
  453. iToMiddleWidth = 0;
  454. iFromMiddleWidth = 1;
  455. }
  456. if (! iFromMiddleHeight) // avoid divide by zero
  457. {
  458. //--- map point to y=0 ----
  459. iToMiddleHeight = 0;
  460. iFromMiddleHeight = 1;
  461. }
  462. //---- clipping values for adjusted lw/rw/th/bh ----
  463. int lwMaxVal = __max(lw - 1, 0);
  464. int rwMinVal = __min(pMargins->cxRightWidth - rw, __max(pMargins->cxRightWidth-1, 0));
  465. int thMaxVal = __max(th - 1, 0);
  466. int bhMinVal = __min(pMargins->cyBottomHeight - bh, __max(pMargins->cyBottomHeight-1, 0));
  467. //---- allocte a buffer for the new points (rects) ----
  468. int newlen = sizeof(RGNDATAHEADER) + prd->rdh.nRgnSize; // same # of rects
  469. BYTE *newData = (BYTE *)new BYTE[newlen];
  470. RGNDATA *prdNew = (RGNDATA *)newData;
  471. if (! prdNew)
  472. return MakeError32(E_OUTOFMEMORY);
  473. ZeroMemory(&prdNew->rdh, sizeof(prdNew->rdh));
  474. prdNew->rdh.dwSize = sizeof(prdNew->rdh);
  475. prdNew->rdh.iType = RDH_RECTANGLES;
  476. int cRects = prd->rdh.nCount;
  477. prdNew->rdh.nCount = cRects;
  478. SetRect(&prdNew->rdh.rcBound, -1, -1, -1, -1);
  479. //---- step thru our custom data (POINT + BYTE combos) ----
  480. POINT *pt = (POINT *)prd->Buffer;
  481. BYTE *pByte = (BYTE *)prd->Buffer + prd->rdh.nRgnSize;
  482. int cPoints = 2 * cRects;
  483. POINT *ptNew = (POINT *)prdNew->Buffer;
  484. for (int i=0; i < cPoints; i++, pt++, pByte++, ptNew++) // transform each "point"
  485. {
  486. switch (*pByte)
  487. {
  488. //---- in the "don't scale" areas, we clip the translated values ----
  489. //---- for the case where the destination areas are too small ----
  490. //---- using the below "__min()" and "__max()" calls ----
  491. //---- remember: each point has been made 0-relative to its grid ----
  492. case GN_LEFTTOP: // left top
  493. ptNew->x = __min(pt->x, lwMaxVal) + iLeftXOffset;
  494. ptNew->y = __min(pt->y, thMaxVal) + iTopYOffset;
  495. break;
  496. case GN_MIDDLETOP: // middle top
  497. ptNew->x = (pt->x*iToMiddleWidth)/iFromMiddleWidth + iMiddleXOffset;
  498. ptNew->y = __min(pt->y, thMaxVal) + iTopYOffset;
  499. break;
  500. case GN_RIGHTTOP: // right top
  501. ptNew->x = __max(pt->x, rwMinVal) + iRightXOffset;
  502. ptNew->y = __min(pt->y, thMaxVal) + iTopYOffset;
  503. break;
  504. case GN_LEFTMIDDLE: // left middle
  505. ptNew->x = __min(pt->x, lwMaxVal) + iLeftXOffset;
  506. ptNew->y = (pt->y*iToMiddleHeight)/iFromMiddleHeight + iMiddleYOffset;
  507. break;
  508. case GN_MIDDLEMIDDLE: // middle middle
  509. ptNew->x = (pt->x*iToMiddleWidth)/iFromMiddleWidth + iMiddleXOffset;
  510. ptNew->y = (pt->y*iToMiddleHeight)/iFromMiddleHeight + iMiddleYOffset;
  511. break;
  512. case GN_RIGHTMIDDLE: // right middle
  513. ptNew->x = __max(pt->x, rwMinVal) + iRightXOffset;
  514. ptNew->y = (pt->y*iToMiddleHeight)/iFromMiddleHeight + iMiddleYOffset;
  515. break;
  516. case GN_LEFTBOTTOM: // left bottom
  517. ptNew->x = __min(pt->x, lwMaxVal) + iLeftXOffset;
  518. ptNew->y = __max(pt->y, bhMinVal) + iBottomYOffset;
  519. break;
  520. case GN_MIDDLEBOTTOM: // middle bottom
  521. ptNew->x = (pt->x*iToMiddleWidth)/iFromMiddleWidth + iMiddleXOffset;
  522. ptNew->y = __max(pt->y, bhMinVal) + iBottomYOffset;
  523. break;
  524. case GN_RIGHTBOTTOM: // right bottom
  525. ptNew->x = __max(pt->x, rwMinVal) + iRightXOffset;
  526. ptNew->y = __max(pt->y, bhMinVal) + iBottomYOffset;
  527. break;
  528. }
  529. }
  530. //---- compute bounding box of new region ----
  531. RECT *pRect = (RECT *)prdNew->Buffer;
  532. RECT newBox = {-1, -1, -1, -1};
  533. for (i=0; i < cRects; i++, pRect++)
  534. _InPlaceUnionRect(&newBox, pRect);
  535. //---- create the new region ----
  536. prdNew->rdh.rcBound = newBox;
  537. HRGN hrgn = ExtCreateRegion(NULL, newlen, prdNew);
  538. delete [] newData; // free prdNew (aka newdata)
  539. if (! hrgn)
  540. return MakeErrorLast();
  541. *phrgn = hrgn;
  542. return S_OK;
  543. }
  544. //---------------------------------------------------------------------------------//
  545. #ifdef DEBUG
  546. void RegionDebug(
  547. HRGN hrgn)
  548. {
  549. DWORD len = GetRegionData(hrgn, 0, NULL); // get required length
  550. ATLASSERT(len);
  551. RGNDATA *pRgnData = (RGNDATA *) new BYTE[len + sizeof(RGNDATAHEADER)];
  552. DWORD len2 = GetRegionData(hrgn, len, pRgnData);
  553. ASSERT(len == len2);
  554. UNREFERENCED_PARAMETER(len2);
  555. }
  556. #endif