Source code of Windows XP (NT5)
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.

927 lines
28 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. //------------//
  10. // Helpers:
  11. //-------------------------------------------------------------------------//
  12. #define CX_USEDEFAULT -1
  13. #define CY_USEDEFAULT -1
  14. #define _ABS( val1, val2 ) ((val1)>(val2) ? (val1)-(val2) : (val2)-(val1))
  15. //-------------------------------------------------------------------------//
  16. inline BOOL IsColorMatch( COLORREF rgb1, COLORREF rgb2, int nTolerance = 0 )
  17. {
  18. if( nTolerance == 0 )
  19. return (rgb1 << 8) == (rgb2 << 8);
  20. return _ABS(GetRValue(rgb1),GetRValue(rgb2)) <= nTolerance &&
  21. _ABS(GetGValue(rgb1),GetGValue(rgb2)) <= nTolerance &&
  22. _ABS(GetBValue(rgb1),GetBValue(rgb2)) <= nTolerance;
  23. }
  24. //-------------------------------------------------------------------------//
  25. inline BOOL _IsNormalRect( IN LPCRECT prc )
  26. {
  27. return (prc->right >= prc->left) &&
  28. (prc->bottom >= prc->top);
  29. }
  30. //-------------------------------------------------------------------------//
  31. inline BOOL _IsOnScreenRect( IN LPCRECT prc )
  32. {
  33. return prc->left >= 0 && prc->top >= 0 &&
  34. prc->right >= 0 && prc->bottom >= 0;
  35. }
  36. //-------------------------------------------------------------------------//
  37. inline void _InPlaceUnionRect( IN OUT LPRECT prcDest, IN LPCRECT prcSrc )
  38. {
  39. _ASSERTE(prcDest);
  40. _ASSERTE(prcSrc);
  41. _ASSERTE(_IsNormalRect(prcSrc));
  42. if( prcDest->left == -1 || prcDest->left > prcSrc ->left )
  43. prcDest->left = prcSrc ->left;
  44. if( prcDest->right == -1 || prcDest->right < prcSrc ->right )
  45. prcDest->right = prcSrc ->right;
  46. if( prcDest->top == -1 || prcDest->top > prcSrc ->top )
  47. prcDest->top = prcSrc ->top;
  48. if( prcDest->bottom == -1 || prcDest->bottom < prcSrc ->bottom )
  49. prcDest->bottom = prcSrc ->bottom;
  50. }
  51. //-------------------------------------------------------------------------//
  52. // Walks the pixels and computes the region
  53. HRGN WINAPI _PixelsToRgn(
  54. DWORD *pdwBits,
  55. int cxImageOffset, // image cell horz offset
  56. int cyImageOffset, // image cell vert offset
  57. int cxImage, // image cell width
  58. int cyImage, // image cell height
  59. int cxSrc, // src bitmap width
  60. int cySrc, // src bitmap height
  61. BOOL fAlphaChannel,
  62. int iAlphaThreshold,
  63. COLORREF rgbMask,
  64. int nMaskTolerance )
  65. {
  66. // Establish a series of rectangles, each corresponding to a scan line (row)
  67. // in the bitmap, that will comprise the region.
  68. const UINT RECTBLOCK = 512;
  69. UINT nAllocRects = 0;
  70. HRGN hrgnRet = NULL;
  71. HGLOBAL hrgnData = GlobalAlloc( GMEM_MOVEABLE,
  72. sizeof(RGNDATAHEADER) + (sizeof(RECT) * (nAllocRects + RECTBLOCK)) );
  73. if( hrgnData )
  74. {
  75. nAllocRects += RECTBLOCK;
  76. RGNDATA* prgnData = (RGNDATA*)GlobalLock( hrgnData );
  77. LPRECT prgrc = (LPRECT)prgnData->Buffer;
  78. ZeroMemory( prgnData, sizeof(prgnData->rdh) );
  79. prgnData->rdh.dwSize = sizeof(prgnData->rdh);
  80. prgnData->rdh.iType = RDH_RECTANGLES;
  81. SetRect( &prgnData->rdh.rcBound, -1, -1, -1, -1 );
  82. int cxMax = cxImageOffset + cxImage;
  83. int cyMax = cyImageOffset + cyImage;
  84. // Compute a transparency mask if not specified.
  85. if( -1 == rgbMask )
  86. rgbMask = pdwBits[cxImageOffset + ((cyMax-1) * cxSrc)];
  87. //---- pixels in pdwBits[] have RBG's reversed ----
  88. //---- reverse our mask to match ----
  89. rgbMask = REVERSE3(rgbMask);
  90. //---- rows in pdwBits[] are reversed (bottom to top) ----
  91. for( int y = cyImageOffset; y < cyMax; y++ ) // working bottom-to-top
  92. {
  93. //---- Scanning pixels left to right ----
  94. DWORD *pdwFirst = &pdwBits[cxImageOffset + y * cxSrc];
  95. DWORD *pdwLast = pdwFirst + cxImage - 1;
  96. DWORD *pdwPixel = pdwFirst;
  97. while (pdwPixel <= pdwLast)
  98. {
  99. //---- skip TRANSPARENT pixels to find next OPAQUE (on this row) ----
  100. if (fAlphaChannel)
  101. {
  102. while ((pdwPixel <= pdwLast) && (ALPHACHANNEL(*pdwPixel) < iAlphaThreshold))
  103. pdwPixel++;
  104. }
  105. else
  106. {
  107. while ((pdwPixel <= pdwLast) && (IsColorMatch(*pdwPixel, rgbMask, nMaskTolerance)))
  108. pdwPixel++;
  109. }
  110. if (pdwPixel > pdwLast) // too far; try next row
  111. break;
  112. DWORD *pdw0 = pdwPixel;
  113. pdwPixel++; // skip over current opaque pixel
  114. //---- skip OPAQUE pixels to find next TRANSPARENT (on this row) ----
  115. if (fAlphaChannel)
  116. {
  117. while ((pdwPixel <= pdwLast) && (ALPHACHANNEL(*pdwPixel) >= iAlphaThreshold))
  118. pdwPixel++;
  119. }
  120. else
  121. {
  122. while ((pdwPixel <= pdwLast) && (! IsColorMatch(*pdwPixel, rgbMask, nMaskTolerance)))
  123. pdwPixel++;
  124. }
  125. //---- got a stream of 1 or more opaque pixels on this row ----
  126. // allocate more region rects if necessary (a particularly complex line)
  127. if( prgnData->rdh.nCount >= nAllocRects )
  128. {
  129. GlobalUnlock( hrgnData );
  130. prgnData = NULL;
  131. hrgnData = GlobalReAlloc( hrgnData,
  132. sizeof(RGNDATAHEADER) + (sizeof(RECT) * (nAllocRects + RECTBLOCK)),
  133. GMEM_MOVEABLE );
  134. if( hrgnData )
  135. {
  136. nAllocRects += RECTBLOCK;
  137. prgnData = (RGNDATA*)GlobalLock( hrgnData );
  138. prgrc = (LPRECT)prgnData->Buffer;
  139. _ASSERTE(prgnData);
  140. }
  141. }
  142. // assign region rectangle
  143. int x0 = (int)(pdw0 - pdwFirst);
  144. int x = (int)(pdwPixel - pdwFirst);
  145. int y0 = y - cyImageOffset;
  146. SetRect( prgrc + prgnData->rdh.nCount,
  147. x0, cyMax - (y0+1),
  148. x, cyMax - y0 );
  149. // merge into bounding box
  150. _InPlaceUnionRect( &prgnData->rdh.rcBound,
  151. prgrc + prgnData->rdh.nCount );
  152. prgnData->rdh.nCount++;
  153. } // while ()
  154. } // for(y)
  155. if( prgnData->rdh.nCount && _IsOnScreenRect(&prgnData->rdh.rcBound) )
  156. {
  157. // Create the region representing the scan line.
  158. hrgnRet = ExtCreateRegion( NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nAllocRects),
  159. prgnData );
  160. }
  161. // Free region def block.
  162. GlobalUnlock( hrgnData );
  163. GlobalFree( hrgnData );
  164. }
  165. return hrgnRet;
  166. }
  167. //-------------------------------------------------------------------------//
  168. // Creates a region based on a text string in the indicated font.
  169. HRGN WINAPI CreateTextRgn( HFONT hf, LPCTSTR pszText )
  170. {
  171. HRGN hrgnRet = NULL;
  172. if( pszText && *pszText )
  173. {
  174. int cchText = lstrlen( pszText );
  175. // Create a composite DC for assembling the region.
  176. HDC hdcMem = CreateCompatibleDC( NULL );
  177. SetBkMode( hdcMem, TRANSPARENT );
  178. SetTextAlign( hdcMem, TA_TOP|TA_LEFT );
  179. HFONT hfOld = (HFONT)SelectObject( hdcMem, hf );
  180. // Derive a region from a path.
  181. BeginPath( hdcMem );
  182. TextOut( hdcMem, 0, 0, pszText, cchText );
  183. EndPath( hdcMem );
  184. hrgnRet = PathToRegion( hdcMem );
  185. // Clean up composite DC
  186. SelectObject( hdcMem, hfOld );
  187. DeleteDC( hdcMem );
  188. }
  189. return hrgnRet;
  190. }
  191. //-------------------------------------------------------------------------//
  192. // Creates a region based on an arbitrary bitmap, transparency-keyed on a
  193. // RGB value within a specified tolerance. The key value is optional
  194. // (-1 == use the value of the first pixel as the key).
  195. //
  196. HRESULT WINAPI CreateBitmapRgn(
  197. HBITMAP hbm,
  198. int cxOffset,
  199. int cyOffset,
  200. int cx,
  201. int cy,
  202. BOOL fAlphaChannel,
  203. int iAlphaThreshold,
  204. COLORREF rgbMask,
  205. int nMaskTolerance,
  206. OUT HRGN *phrgn)
  207. {
  208. CBitmapPixels BitmapPixels;
  209. DWORD *prgdwPixels;
  210. int cwidth, cheight;
  211. HRESULT hr = BitmapPixels.OpenBitmap(NULL, hbm, TRUE, &prgdwPixels, &cwidth, &cheight);
  212. if (FAILED(hr))
  213. return hr;
  214. if (cx <= 0)
  215. cx = cwidth;
  216. if (cy <= 0)
  217. cy = cheight;
  218. HRGN hrgn = _PixelsToRgn(prgdwPixels, cxOffset, cyOffset, cx, cy, cwidth, cheight, fAlphaChannel,
  219. iAlphaThreshold, rgbMask, nMaskTolerance);
  220. if (! hrgn)
  221. return E_FAIL;
  222. *phrgn = hrgn;
  223. return S_OK;
  224. }
  225. //-------------------------------------------------------------------------//
  226. // Creates a region based on an arbitrary bitmap, transparency-keyed on a
  227. // RGB value within a specified tolerance. The key value is optional (-1 ==
  228. // use the value of the first pixel as the key).
  229. //
  230. HRGN WINAPI CreateScaledBitmapRgn(
  231. HBITMAP hbm,
  232. int cx,
  233. int cy,
  234. COLORREF rgbMask,
  235. int nMaskTolerance )
  236. {
  237. HRGN hrgnRet = NULL;
  238. BITMAP bm;
  239. if( hbm && GetObject( hbm, sizeof(bm), &bm ) )
  240. {
  241. // Create a memory DC to do the pixel walk
  242. HDC hdcMem = NULL;
  243. if( (hdcMem = CreateCompatibleDC(NULL)) != NULL )
  244. {
  245. if( CX_USEDEFAULT == cx )
  246. cx = bm.bmWidth;
  247. if( CY_USEDEFAULT == cy )
  248. cy = bm.bmHeight;
  249. // Create a 32-bit empty bitmap for the walk
  250. BITMAPINFO bmi;
  251. ZeroMemory( &bmi, sizeof(bmi) );
  252. bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  253. bmi.bmiHeader.biWidth = cx;
  254. bmi.bmiHeader.biHeight = cy;
  255. bmi.bmiHeader.biPlanes = 1;
  256. bmi.bmiHeader.biBitCount = 32;
  257. bmi.bmiHeader.biCompression = BI_RGB; // uncompressed.
  258. VOID* pvBits = NULL;
  259. HBITMAP hbmMem = CreateDIBSection( hdcMem, &bmi, DIB_RGB_COLORS, &pvBits, NULL, NULL );
  260. BITMAP bmMem;
  261. if( hbmMem )
  262. {
  263. // Transfer the image to our 32-bit format for the pixel walk.
  264. HBITMAP hbmMemOld = (HBITMAP)SelectObject( hdcMem, hbmMem );
  265. HDC hdc = CreateCompatibleDC( hdcMem );
  266. HBITMAP hbmOld = (HBITMAP)SelectObject( hdc, hbm );
  267. StretchBlt( hdcMem, 0, 0, cx, cy,
  268. hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
  269. SelectObject( hdc, hbmOld );
  270. DeleteDC( hdc );
  271. GetObject( hbmMem, sizeof(bmMem), &bmMem );
  272. _ASSERTE(bmMem.bmBitsPixel == 32);
  273. _ASSERTE(bmMem.bmWidthBytes/bmMem.bmWidth == sizeof(DWORD));
  274. LPDWORD pdwBits = (LPDWORD)bmMem.bmBits;
  275. _ASSERTE(pdwBits != NULL);
  276. hrgnRet = _PixelsToRgn(pdwBits, 0, 0, cx, cy, cx, cy, FALSE, 0, rgbMask, nMaskTolerance);
  277. // Delete 32-bit memory bitmap
  278. SelectObject( hdcMem, hbmMemOld );
  279. DeleteObject( hbmMem );
  280. }
  281. // Delete memory DC
  282. DeleteDC(hdcMem);
  283. }
  284. }
  285. return hrgnRet;
  286. }
  287. //-------------------------------------------------------------------------//
  288. int WINAPI AddToCompositeRgn(
  289. IN OUT HRGN* phrgnComposite,
  290. IN OUT HRGN hrgnSrc,
  291. IN int cxOffset,
  292. IN int cyOffset )
  293. {
  294. int nRet = ERROR;
  295. if( NULL != phrgnComposite && NULL != hrgnSrc )
  296. {
  297. nRet = OffsetRgn( hrgnSrc, cxOffset, cyOffset );
  298. if( nRet != ERROR )
  299. {
  300. int nMode = RGN_OR;
  301. if( NULL == *phrgnComposite )
  302. {
  303. *phrgnComposite = CreateRectRgn(0,0,1,1);
  304. if( NULL == *phrgnComposite )
  305. return ERROR;
  306. nMode = RGN_COPY;
  307. }
  308. nRet = CombineRgn( *phrgnComposite, hrgnSrc, *phrgnComposite, nMode );
  309. }
  310. }
  311. return nRet;
  312. }
  313. //-------------------------------------------------------------------------//
  314. int WINAPI RemoveFromCompositeRgn(
  315. HRGN hrgnDest,
  316. LPCRECT prcRemove )
  317. {
  318. _ASSERTE(hrgnDest);
  319. _ASSERTE(prcRemove);
  320. _ASSERTE(!IsRectEmpty(prcRemove));
  321. int nRet = ERROR;
  322. RECT rc = *prcRemove;
  323. HRGN hrgn;
  324. if( (hrgn = CreateRectRgnIndirect( &rc )) != NULL )
  325. {
  326. nRet = CombineRgn( hrgnDest, hrgnDest, hrgn, RGN_DIFF );
  327. DeleteObject( hrgn );
  328. }
  329. return nRet;
  330. }
  331. //-------------------------------------------------------------------------//
  332. HRGN WINAPI CreateTiledRectRgn(
  333. IN HRGN hrgnSrc,
  334. IN int cxSrc,
  335. IN int cySrc,
  336. IN int cxDest,
  337. IN int cyDest )
  338. {
  339. HRGN hrgnBound = NULL; // return value
  340. HRGN hrgnTile = _DupRgn( hrgnSrc );
  341. if( hrgnTile )
  342. {
  343. // Build up an unplaced, unclipped composite
  344. HRGN hrgnTmp = NULL;
  345. for( int y = 0; y < cyDest; y += cySrc )
  346. {
  347. for( int x = 0; x < cxDest; x += cxSrc )
  348. {
  349. AddToCompositeRgn( &hrgnTmp, hrgnTile,
  350. (x ? cxSrc : 0), (y ? cySrc : 0) );
  351. }
  352. }
  353. if( NULL != hrgnTmp )
  354. {
  355. // Clip the composite to the specified rectangle
  356. hrgnBound = CreateRectRgn( 0, 0, cxDest, cyDest );
  357. if( hrgnBound )
  358. {
  359. if( ERROR == CombineRgn( hrgnBound, hrgnTmp, hrgnBound, RGN_AND ) )
  360. {
  361. DeleteObject( hrgnBound );
  362. hrgnBound = NULL;
  363. }
  364. }
  365. DeleteObject( hrgnTmp );
  366. }
  367. DeleteObject( hrgnTile );
  368. }
  369. return hrgnBound;
  370. }
  371. //-------------------------------------------------------------------------//
  372. HRGN WINAPI _DupRgn( HRGN hrgnSrc )
  373. {
  374. if( hrgnSrc )
  375. {
  376. HRGN hrgnDest = CreateRectRgn(0,0,1,1);
  377. if (hrgnDest)
  378. {
  379. if (CombineRgn( hrgnDest, hrgnSrc, NULL, RGN_COPY ) )
  380. return hrgnDest;
  381. DeleteObject(hrgnDest);
  382. }
  383. }
  384. return NULL;
  385. }
  386. //-------------------------------------------------------------------------//
  387. // _InternalHitTestRgn()
  388. typedef enum // _InternalHitTestRgn return values:
  389. {
  390. HTRGN_ERROR = 0x0000,
  391. HTRGN_LEFT = 0x0001,
  392. HTRGN_TOP = 0x0002,
  393. HTRGN_RIGHT = 0x0004,
  394. HTRGN_BOTTOM = 0x0008,
  395. HTRGN_INSIDE = 0x0010,
  396. HTRGN_OUTSIDE = 0x0020,
  397. } HTRGN;
  398. UINT WINAPI _InternalHitTestRgn(
  399. HRGN hrgn,
  400. POINT pt,
  401. DWORD dwHitMask,
  402. UINT cxMargin,
  403. UINT cyMargin )
  404. {
  405. UINT nRet = HTRGN_ERROR;
  406. RECT rcBox;
  407. nRet |= PtInRegion( hrgn, pt.x, pt.y ) ? HTRGN_INSIDE : HTRGN_OUTSIDE;
  408. dwHitMask &= ~(HTRGN_INSIDE|HTRGN_OUTSIDE);
  409. if( (nRet & HTRGN_INSIDE) != 0 &&
  410. (dwHitMask != 0) && GetRgnBox( hrgn, &rcBox ) )
  411. {
  412. int x, y;
  413. if( dwHitMask & HTRGN_LEFT )
  414. {
  415. if( cxMargin )
  416. {
  417. // move left until we're out of the region.
  418. for( x = pt.x; x >= rcBox.left && PtInRegion( hrgn, x, pt.y ); x-- );
  419. // are we still in test range?
  420. if( pt.x - x < (int)cxMargin )
  421. nRet |= HTRGN_LEFT;
  422. }
  423. else
  424. nRet |= HTRGN_LEFT;
  425. }
  426. if( dwHitMask & HTRGN_RIGHT )
  427. {
  428. if( cxMargin )
  429. {
  430. // move right until we're out of the region.
  431. for( x = pt.x; x <= rcBox.right && PtInRegion( hrgn, x, pt.y ); x++ );
  432. // are we still in test range?
  433. if( x - pt.x < (int)cxMargin )
  434. nRet |= HTRGN_RIGHT;
  435. }
  436. else
  437. nRet |= HTRGN_RIGHT;
  438. }
  439. if( dwHitMask & HTRGN_TOP )
  440. {
  441. if( cyMargin )
  442. {
  443. // move up until we're out of the region.
  444. for( y = pt.y; y >= rcBox.top && PtInRegion( hrgn, pt.x, y ); y-- );
  445. // are we still in test range?
  446. if( pt.y - y < (int)cyMargin )
  447. nRet |= HTRGN_TOP;
  448. }
  449. else
  450. nRet |= HTRGN_TOP;
  451. }
  452. if( dwHitMask & HTRGN_BOTTOM )
  453. {
  454. if( cyMargin )
  455. {
  456. // move left until we're out of the region.
  457. for( y = pt.y; y <= rcBox.bottom && PtInRegion( hrgn, pt.x, y ); y++ );
  458. // are we still in test range?
  459. if( y - pt.y < (int)cyMargin )
  460. nRet |= HTRGN_BOTTOM;
  461. }
  462. else
  463. nRet |= HTRGN_BOTTOM;
  464. }
  465. }
  466. return nRet;
  467. }
  468. //-------------------------------------------------------------------------//
  469. UINT _HitMaskFromHitCode( BOOL fHasCaption, WORD wSegmentHTCode, WORD* pnHTDefault )
  470. {
  471. UINT nHitMask = 0;
  472. WORD nHTDefault = HTBORDER;
  473. switch (wSegmentHTCode)
  474. {
  475. case HTLEFT:
  476. nHitMask = HTRGN_LEFT;
  477. break;
  478. case HTTOPLEFT:
  479. nHitMask = HTRGN_TOP | HTRGN_LEFT;
  480. if( fHasCaption )
  481. nHTDefault = HTCAPTION;
  482. break;
  483. case HTBOTTOMLEFT:
  484. nHitMask = HTRGN_BOTTOM | HTRGN_LEFT;
  485. break;
  486. case HTTOP:
  487. nHitMask = HTRGN_TOP;
  488. if( fHasCaption )
  489. nHTDefault = HTCAPTION;
  490. break;
  491. case HTBOTTOM:
  492. nHitMask = HTRGN_BOTTOM;
  493. break;
  494. case HTTOPRIGHT:
  495. nHitMask = HTRGN_TOP | HTRGN_RIGHT;
  496. if( fHasCaption )
  497. nHTDefault = HTCAPTION;
  498. break;
  499. case HTRIGHT:
  500. nHitMask = HTRGN_RIGHT;
  501. break;
  502. case HTBOTTOMRIGHT:
  503. nHitMask = HTRGN_BOTTOM | HTRGN_RIGHT;
  504. break;
  505. }
  506. if( pnHTDefault ) *pnHTDefault = nHTDefault;
  507. return nHitMask;
  508. }
  509. //-------------------------------------------------------------------------//
  510. WORD _HitCodeFromHitMask( UINT nHitMask, WORD nHTDefault )
  511. {
  512. switch( nHitMask )
  513. {
  514. case HTRGN_LEFT:
  515. return HTLEFT;
  516. case HTRGN_RIGHT:
  517. return HTRIGHT;
  518. case HTRGN_TOP:
  519. return HTTOP;
  520. case HTRGN_BOTTOM:
  521. return HTBOTTOM;
  522. case HTRGN_TOP|HTRGN_LEFT:
  523. return HTTOPLEFT;
  524. case HTRGN_TOP|HTRGN_RIGHT:
  525. return HTTOPRIGHT;
  526. case HTRGN_BOTTOM|HTRGN_LEFT:
  527. return HTBOTTOMLEFT;
  528. case HTRGN_BOTTOM|HTRGN_RIGHT:
  529. return HTBOTTOMRIGHT;
  530. }
  531. return nHTDefault;
  532. }
  533. //-------------------------------------------------------------------------//
  534. WORD WINAPI _HitTestRgn( // can merge with _HitTestRgn() when it has no other callers
  535. HRGN hrgn,
  536. POINT pt,
  537. WORD wSegmentHTCode,
  538. BOOL fHasCaption,
  539. UINT cxMargin,
  540. UINT cyMargin )
  541. {
  542. WORD nHTDefault = HTBORDER;
  543. UINT nHitMask = _HitMaskFromHitCode( fHasCaption, wSegmentHTCode, &nHTDefault );
  544. UINT fHTRgn = _InternalHitTestRgn( hrgn, pt, nHitMask|HTRGN_INSIDE,
  545. cxMargin, cyMargin );
  546. if( fHTRgn & HTRGN_INSIDE )
  547. {
  548. fHTRgn &= ~HTRGN_INSIDE;
  549. return _HitCodeFromHitMask( fHTRgn, nHTDefault );
  550. }
  551. return HTNOWHERE;
  552. }
  553. //-------------------------------------------------------------------------//
  554. HRESULT WINAPI _ScaleRectsAndCreateRegion(
  555. RGNDATA *prd,
  556. const RECT *prc,
  557. MARGINS *pMargins,
  558. HRGN *phrgn)
  559. {
  560. //---- note: "prd" is region data with the 2 points in each ----
  561. //---- rectangle made relative to its grid. Also, after the points, ----
  562. //---- there is a BYTE for each point signifying the grid id (0-8) ----
  563. //---- that each point lies within. the grid is determined using ----
  564. //---- the original region with the background "margins". This is ----
  565. //---- done to make scaling the points as fast as possible. ----
  566. if (! prd) // required
  567. return E_POINTER;
  568. RECT rcBox = prd->rdh.rcBound;
  569. //---- compute margin values ----
  570. int lwFrom = rcBox.left + pMargins->cxLeftWidth;
  571. int rwFrom = rcBox.right - pMargins->cxRightWidth;
  572. int thFrom = rcBox.top + pMargins->cyTopHeight;
  573. int bhFrom = rcBox.bottom - pMargins->cyBottomHeight;
  574. int lwTo = prc->left + pMargins->cxLeftWidth;
  575. int rwTo = prc->right - pMargins->cxRightWidth;
  576. int thTo = prc->top + pMargins->cyTopHeight;
  577. int bhTo = prc->bottom - pMargins->cyBottomHeight;
  578. //---- compute offsets & factors ----
  579. int iLeftXOffset = prc->left;
  580. int iMiddleXOffset = lwTo;
  581. int iRightXOffset = rwTo;
  582. int iTopYOffset = prc->top;
  583. int iMiddleYOffset = thTo;
  584. int iBottomYOffset = bhTo;
  585. int iXMult = rwTo - lwTo;
  586. int iXDiv = rwFrom - lwFrom;
  587. int iYMult = bhTo - thTo;
  588. int iYDiv = bhFrom - thFrom;
  589. //---- allocte a buffer for the new points (rects) ----
  590. int newlen = sizeof(RGNDATAHEADER) + prd->rdh.nRgnSize; // same # of rects
  591. BYTE *newData = (BYTE *)new BYTE[newlen];
  592. RGNDATA *prdNew = (RGNDATA *)newData;
  593. if (! prdNew)
  594. return E_OUTOFMEMORY;
  595. ZeroMemory(prdNew, sizeof(prd->rdh));
  596. prdNew->rdh.dwSize = sizeof(prdNew->rdh);
  597. prdNew->rdh.iType = RDH_RECTANGLES;
  598. int cRects = prd->rdh.nCount;
  599. prdNew->rdh.nCount = cRects;
  600. SetRect(&prdNew->rdh.rcBound, -1, -1, -1, -1);
  601. //---- step thru our custom data (POINT + BYTE combos) ----
  602. POINT *pt = (POINT *)prd->Buffer;
  603. BYTE *pByte = (BYTE *)prd->Buffer + prd->rdh.nRgnSize;
  604. int cPoints = 2 * cRects;
  605. POINT *ptNew = (POINT *)prdNew->Buffer;
  606. for (int i=0; i < cPoints; i++, pt++, pByte++, ptNew++) // transform each "point"
  607. {
  608. switch (*pByte)
  609. {
  610. case GN_LEFTTOP: // left top
  611. ptNew->x = pt->x + iLeftXOffset;
  612. ptNew->y = pt->y + iTopYOffset;
  613. break;
  614. case GN_MIDDLETOP: // middle top
  615. ptNew->x = (pt->x*iXMult)/iXDiv + iMiddleXOffset;
  616. ptNew->y = pt->y + iTopYOffset;
  617. break;
  618. case GN_RIGHTTOP: // right top
  619. ptNew->x = pt->x + iRightXOffset;
  620. ptNew->y = pt->y + iTopYOffset;
  621. break;
  622. case GN_LEFTMIDDLE: // left middle
  623. ptNew->x = pt->x + iLeftXOffset;
  624. ptNew->y = (pt->y*iYMult)/iYDiv + iMiddleYOffset;
  625. break;
  626. case GN_MIDDLEMIDDLE: // middle middle
  627. ptNew->x = (pt->x*iXMult)/iXDiv + iMiddleXOffset;
  628. ptNew->y = (pt->y*iYMult)/iYDiv + iMiddleYOffset;
  629. break;
  630. case GN_RIGHTMIDDLE: // right middle
  631. ptNew->x = pt->x + iRightXOffset;
  632. ptNew->y = (pt->y*iYMult)/iYDiv + iMiddleYOffset;
  633. break;
  634. case GN_LEFTBOTTOM: // left bottom
  635. ptNew->x = pt->x + iLeftXOffset;
  636. ptNew->y = pt->y + iBottomYOffset;
  637. break;
  638. case GN_MIDDLEBOTTOM: // middle bottom
  639. ptNew->x = (pt->x*iXMult)/iXDiv + iMiddleXOffset;
  640. ptNew->y = pt->y + iBottomYOffset;
  641. break;
  642. case GN_RIGHTBOTTOM: // right bottom
  643. ptNew->x = pt->x + iRightXOffset;
  644. ptNew->y = pt->y + iBottomYOffset;
  645. break;
  646. }
  647. }
  648. //---- compute bounding box of new region ----
  649. RECT *pRect = (RECT *)prdNew->Buffer;
  650. RECT newBox = {-1, -1, -1, -1};
  651. for (i=0; i < cRects; i++, pRect++)
  652. _InPlaceUnionRect(&newBox, pRect);
  653. //---- create the new region ----
  654. prdNew->rdh.rcBound = newBox;
  655. HRGN hrgn = ExtCreateRegion(NULL, newlen, prdNew);
  656. delete [] newData; // free prdNew (aka newdata)
  657. if (! hrgn)
  658. return GetLastError();
  659. *phrgn = hrgn;
  660. return S_OK;
  661. }
  662. //-------------------------------------------------------------------------//
  663. WORD WINAPI _DefaultHitCodeFromSegCode( BOOL fHasCaption, WORD wSegHTcode )
  664. {
  665. WORD nHTDefault;
  666. _HitMaskFromHitCode( fHasCaption, wSegHTcode, &nHTDefault );
  667. return nHTDefault;
  668. }
  669. //---------------------------------------------------------------------------------//
  670. #ifdef _DEBUG
  671. void RegionDebug(
  672. HRGN hrgn)
  673. {
  674. DWORD len = GetRegionData(hrgn, 0, NULL); // get required length
  675. ASSERT(len);
  676. RGNDATA *pRgnData = (RGNDATA *) new BYTE[len + sizeof(RGNDATAHEADER)];
  677. DWORD len2 = GetRegionData(hrgn, len, pRgnData);
  678. ASSERT(len == len2);
  679. int cnt = pRgnData->rdh.nCount;
  680. RECT rect = pRgnData->rdh.rcBound;
  681. }
  682. #endif
  683. //-------------------------------------------------------------------------
  684. CBitmapPixels::CBitmapPixels()
  685. {
  686. _hdrBitmap = NULL;
  687. _iWidth = 0;
  688. _iHeight = 0;
  689. }
  690. //-------------------------------------------------------------------------
  691. CBitmapPixels::~CBitmapPixels()
  692. {
  693. if (_hdrBitmap)
  694. delete [] (BYTE *)_hdrBitmap;
  695. }
  696. //-------------------------------------------------------------------------
  697. HRESULT CBitmapPixels::OpenBitmap(HDC hdc, HBITMAP bitmap, BOOL fForceRGB32,
  698. DWORD OUT **pPixels, OPTIONAL OUT int *piWidth, OPTIONAL OUT int *piHeight,
  699. OPTIONAL OUT int *piBytesPerPixel, OPTIONAL OUT int *piBytesPerRow)
  700. {
  701. if (! pPixels)
  702. return E_INVALIDARG;
  703. BITMAP bminfo;
  704. GetObject(bitmap, sizeof(bminfo), &bminfo);
  705. _iWidth = bminfo.bmWidth;
  706. _iHeight = bminfo.bmHeight;
  707. int iBytesPerPixel;
  708. if ((fForceRGB32) || (bminfo.bmBitsPixel == 32))
  709. iBytesPerPixel = 4;
  710. else
  711. iBytesPerPixel = 3;
  712. int iRawBytes = _iWidth * iBytesPerPixel;
  713. int iBytesPerRow = 4*((iRawBytes+3)/4);
  714. int size = sizeof(BITMAPINFOHEADER) + _iHeight*iBytesPerRow;
  715. BYTE *dibBuff = new BYTE[size+100]; // avoid random GetDIBits() failures with 100 bytes padding (?)
  716. if (! dibBuff)
  717. return E_OUTOFMEMORY;
  718. _hdrBitmap = (BITMAPINFOHEADER *)dibBuff;
  719. memset(_hdrBitmap, 0, sizeof(BITMAPINFOHEADER));
  720. _hdrBitmap->biSize = sizeof(BITMAPINFOHEADER);
  721. _hdrBitmap->biWidth = _iWidth;
  722. _hdrBitmap->biHeight = _iHeight;
  723. _hdrBitmap->biPlanes = 1;
  724. _hdrBitmap->biBitCount = 8*iBytesPerPixel;
  725. _hdrBitmap->biCompression = BI_RGB;
  726. bool fNeedRelease = false;
  727. if (! hdc)
  728. {
  729. hdc = GetWindowDC(NULL);
  730. fNeedRelease = true;
  731. }
  732. int linecnt = GetDIBits(hdc, bitmap, 0, _iHeight, DIBDATA(_hdrBitmap), (BITMAPINFO *)_hdrBitmap,
  733. DIB_RGB_COLORS);
  734. ASSERT(linecnt == _iHeight);
  735. if (fNeedRelease)
  736. ReleaseDC(NULL, hdc);
  737. *pPixels = (DWORD *)DIBDATA(_hdrBitmap);
  738. if (piWidth)
  739. *piWidth = _iWidth;
  740. if (piHeight)
  741. *piHeight = _iHeight;
  742. if (piBytesPerPixel)
  743. *piBytesPerPixel = iBytesPerPixel;
  744. if (piBytesPerRow)
  745. *piBytesPerRow = iBytesPerRow;
  746. return S_OK;
  747. }
  748. //-------------------------------------------------------------------------
  749. void CBitmapPixels::CloseBitmap(HDC hdc, HBITMAP hBitmap)
  750. {
  751. if (_hdrBitmap)
  752. {
  753. if (hBitmap) // rewrite bitmap
  754. {
  755. bool fNeedRelease = false;
  756. if (! hdc)
  757. {
  758. hdc = GetWindowDC(NULL);
  759. fNeedRelease = true;
  760. }
  761. SetDIBits(hdc, hBitmap, 0, _iHeight, DIBDATA(_hdrBitmap), (BITMAPINFO *)_hdrBitmap,
  762. DIB_RGB_COLORS);
  763. if ((fNeedRelease) && (hdc))
  764. ReleaseDC(NULL, hdc);
  765. }
  766. delete [] (BYTE *)_hdrBitmap;
  767. _hdrBitmap = NULL;
  768. }
  769. }