win32_region.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. #if defined _WIN64 || defined _WIN32
  2. #include <tataki/api__tataki.h>
  3. #include "region.h"
  4. #include <api/imgldr/api_imgldr.h>
  5. #include <tataki/region/api_region.h>
  6. #include <tataki/canvas/ifc_canvas.h>
  7. #include <api/wnd/basewnd.h>
  8. #define GETOSHANDLE(x) (const_cast<api_region *>(x)->getOSHandle())
  9. #define CBCLASS RegionI
  10. START_DISPATCH;
  11. CB(REGION_GETOSHANDLE, getOSHandle);
  12. CB(REGION_CLONE, clone);
  13. VCB(REGION_DISPOSECLONE, disposeClone);
  14. CB(REGION_PTINREGION, ptInRegion);
  15. VCB(REGION_OFFSET, offset);
  16. VCB(REGION_GETBOX, getBox);
  17. VCB(REGION_SUBTRACTRGN, subtractRegion);
  18. VCB(REGION_SUBTRACTRECT, subtractRect);
  19. VCB(REGION_ADDRECT, addRect);
  20. VCB(REGION_ADD, addRegion);
  21. VCB(REGION_AND, andRegion);
  22. VCB(REGION_SETRECT, setRect);
  23. VCB(REGION_EMPTY, empty);
  24. CB(REGION_ISEMPTY, isEmpty);
  25. CB(REGION_EQUALS, equals);
  26. CB(REGION_ENCLOSED, enclosed);
  27. CB(REGION_INTERSECTRECT, intersectRect);
  28. CB(REGION_DOESINTERSECTRGN, doesIntersectRgn);
  29. CB(REGION_INTERSECTRGN, intersectRgn);
  30. CB(REGION_ISRECT, isRect);
  31. VCB(REGION_SCALE, scale);
  32. VCB(REGION_DEBUG, debug);
  33. CB(REGION_MAKEWNDREGION, makeWindowRegion);
  34. CB(REGION_GETNUMRECTS, getNumRects);
  35. CB(REGION_ENUMRECT, enumRect);
  36. END_DISPATCH;
  37. #undef CBCLASS
  38. #define CHECK_REGION \
  39. if (hrgn == NULL) hrgn = CreateRectRgn(0,0,0,0);
  40. RegionI::RegionI()
  41. {
  42. hrgn = CreateRectRgn(0, 0, 0, 0);
  43. init();
  44. }
  45. RegionI::RegionI(const RECT *r)
  46. {
  47. hrgn = 0;
  48. init();
  49. optrect = *r;
  50. optimized = 1;
  51. //hrgn = CreateRectRgn(r->left,r->top,r->right,r->bottom);
  52. //if (!hrgn) hrgn = CreateRectRgn(0,0,0,0);
  53. //init();
  54. //optimize();
  55. }
  56. RegionI::RegionI(int l, int t, int r, int b)
  57. {
  58. hrgn = 0;
  59. init();
  60. optrect.left = l;
  61. optrect.top = t;
  62. optrect.right = r;
  63. optrect.bottom = b;
  64. optimized = 1;
  65. //hrgn = CreateRectRgn(l,t,r,b);
  66. //if (!hrgn) hrgn = CreateRectRgn(0,0,0,0);
  67. //init();
  68. //optimize();
  69. }
  70. RegionI::RegionI(OSREGIONHANDLE r)
  71. {
  72. OSREGIONHANDLE R = CreateRectRgn(0, 0, 0, 0);
  73. CombineRgn(R, r, r, RGN_COPY);
  74. hrgn = R;
  75. init();
  76. optimize();
  77. }
  78. RegionI::RegionI(const RegionI *copy)
  79. {
  80. init();
  81. if (copy->optimized)
  82. {
  83. optrect = copy->optrect;
  84. optimized = copy->optimized;
  85. hrgn = 0;
  86. }
  87. else
  88. {
  89. hrgn = CreateRectRgn(0, 0, 0, 0);
  90. CombineRgn(hrgn, copy->hrgn, copy->hrgn, RGN_COPY);
  91. }
  92. }
  93. RegionI::RegionI(Canvas *c, RECT *defbounds)
  94. {
  95. hrgn = CreateRectRgn(0, 0, 0, 0);
  96. if (!GetClipRgn(c->getHDC(), hrgn))
  97. {
  98. if (defbounds != NULL)
  99. {
  100. SetRectRgn(hrgn, defbounds->left, defbounds->top, defbounds->right, defbounds->bottom);
  101. optrect=*defbounds;
  102. optimized=1;
  103. }
  104. }
  105. init();
  106. optimize();
  107. }
  108. RegionI::~RegionI()
  109. {
  110. delete lastdebug;
  111. if (srv != NULL) srv->delRef(this);
  112. ASSERT(clonecount == 0);
  113. if (srv == NULL && hrgn != NULL) DeleteObject(hrgn);
  114. }
  115. void RegionI::init()
  116. {
  117. srv = NULL;
  118. clonecount = 0;
  119. lastdebug = NULL;
  120. optimized = 0;
  121. }
  122. api_region *RegionI::clone()
  123. {
  124. api_region *newregion = new RegionI(this);
  125. clonecount++;
  126. return newregion;
  127. }
  128. void RegionI::disposeClone(api_region *r)
  129. {
  130. RegionI *ri = static_cast<RegionI *>(r);
  131. delete ri; // todo: validate pointer before deleting
  132. clonecount--;
  133. }
  134. // returns a handle that SetWindowRgn understands (non portable). We should NOT delete this handle, windows will delete
  135. // it by itself upon setting a new region of destroying the window
  136. OSREGIONHANDLE RegionI::makeWindowRegion()
  137. {
  138. deoptimize();
  139. OSREGIONHANDLE R = CreateRectRgn(0, 0, 0, 0);
  140. CombineRgn(R, hrgn, hrgn, RGN_COPY);
  141. optimize();
  142. return R;
  143. }
  144. RegionI::RegionI(SkinBitmap *bitmap, RECT *r, int xoffset, int yoffset, bool inverted, int dothreshold, char threshold, int thinverse, int minalpha)
  145. {
  146. init();
  147. const wchar_t *id = bitmap->getBitmapName();
  148. if (xoffset == 0 && yoffset == 0 && r == NULL && !inverted && !dothreshold && minalpha == 1 && id != NULL && *id != 0)
  149. {
  150. srv = WASABI_API_IMGLDR->imgldr_requestSkinRegion(id);
  151. if (srv != NULL)
  152. {
  153. srv->addRef(this);
  154. hrgn = srv->getRegion()->getOSHandle();
  155. }
  156. }
  157. if (srv == NULL)
  158. {
  159. if (r)
  160. hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, TRUE, r->left, r->top, r->right - r->left, r->bottom - r->top, inverted, dothreshold, threshold, thinverse, minalpha);
  161. else
  162. hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, FALSE, 0, 0, 0, 0, inverted, dothreshold, threshold, thinverse, minalpha);
  163. if (id != NULL && *id != 0)
  164. {
  165. if (xoffset == 0 && yoffset == 0 && r == NULL && !inverted && !dothreshold && minalpha == 1)
  166. {
  167. WASABI_API_IMGLDR->imgldr_cacheSkinRegion(id, this);
  168. srv = WASABI_API_IMGLDR->imgldr_requestSkinRegion(id);
  169. if (srv != NULL)
  170. {
  171. srv->addRef(this);
  172. DeleteObject(hrgn);
  173. hrgn = srv->getRegion()->getOSHandle();
  174. }
  175. }
  176. }
  177. }
  178. optimize();
  179. }
  180. OSREGIONHANDLE RegionI::alphaToRegionRect(SkinBitmap *bitmap, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted, int dothreshold, unsigned char threshold, int thinverse, int minalpha)
  181. {
  182. return alphaToRegionRect(bitmap->getBits(), bitmap->getX(), bitmap->getY(), bitmap->getWidth(), bitmap->getHeight(), bitmap->getFullWidth(), bitmap->getFullHeight(), xoffset, yoffset, portion, _x, _y, _w, _h, inverted, dothreshold, threshold, thinverse, minalpha);
  183. }
  184. OSREGIONHANDLE RegionI::alphaToRegionRect(void *pbits32, int bmX, int bmY, int bmWidth, int bmHeight, int fullw, int fullh, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted, int dothreshold, unsigned char threshold, int thinverse, int minalpha)
  185. {
  186. OSREGIONHANDLE hRgn = NULL;
  187. if (!pbits32) return NULL;
  188. RGNDATA *pData;
  189. int y, x;
  190. // For better performances, we will use the ExtCreateRegion() function to create the
  191. // region. This function take a RGNDATA structure on entry. We will add rectangles by
  192. // amount of ALLOC_UNIT number in this structure.
  193. // JF> rects are 8 bytes, so this allocates just under 16kb of memory, no need to REALLOC
  194. #define MAXRECTS 2000
  195. __int8 regionMemory[sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS)] = {0};
  196. //pData = (RGNDATA *)MALLOC(sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS));
  197. pData = (RGNDATA *)regionMemory;
  198. //if (!pData) return NULL;
  199. pData->rdh.dwSize = sizeof(RGNDATAHEADER);
  200. pData->rdh.iType = RDH_RECTANGLES;
  201. pData->rdh.nCount = pData->rdh.nRgnSize = 0;
  202. SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  203. int x_end = (portion ? _w + _x : bmWidth);
  204. int y_end = (portion ? _h + _y : bmHeight);
  205. int x_start = (portion ? _x : 0);
  206. int y_start = (portion ? _y : 0);
  207. x_start += bmX;
  208. x_end += bmX;
  209. y_start += bmY;
  210. y_end += bmY;
  211. unsigned int iv = minalpha << 24; //inverted?0xff000000:0;
  212. int shiftx = xoffset - bmX;
  213. int shifty = yoffset - bmY;
  214. for (y = y_start; y < y_end; y++)
  215. {
  216. // Scan each bitmap pixel from left to right
  217. unsigned int *lineptr = ((unsigned int *)pbits32) + fullw * y;
  218. for (x = x_start; x < x_end; x++)
  219. {
  220. // Search for a continuous range of "non transparent pixels"
  221. int x0 = x;
  222. unsigned int *p = lineptr;
  223. if (dothreshold)
  224. {
  225. if (inverted)
  226. {
  227. if (thinverse)
  228. {
  229. while (x < x_end)
  230. {
  231. unsigned int a = p[x];
  232. if ((a&0xff000000) >= iv ||
  233. (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
  234. break;
  235. x++;
  236. }
  237. }
  238. else
  239. {
  240. while (x < x_end)
  241. {
  242. unsigned int a = p[x];
  243. if ((a&0xff000000) >= iv ||
  244. (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
  245. break;
  246. x++;
  247. }
  248. }
  249. }
  250. else
  251. {
  252. if (thinverse)
  253. {
  254. while (x < x_end)
  255. {
  256. unsigned int a = p[x];
  257. if ((a&0xff000000) < iv ||
  258. (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
  259. break;
  260. x++;
  261. }
  262. }
  263. else
  264. {
  265. while (x < x_end)
  266. {
  267. unsigned int a = p[x];
  268. if ((a&0xff000000) < iv ||
  269. (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
  270. break;
  271. x++;
  272. }
  273. }
  274. }
  275. }
  276. else
  277. {
  278. if (inverted)
  279. {
  280. while (x < x_end)
  281. {
  282. if ((p[x] & 0xFF000000) >= iv) break;
  283. x++;
  284. }
  285. }
  286. else
  287. {
  288. while (x < x_end)
  289. {
  290. if ((p[x] & 0xFF000000) < iv) break;
  291. x++;
  292. }
  293. }
  294. }
  295. if (x > x0)
  296. {
  297. SetRect(((RECT *)&pData->Buffer) + pData->rdh.nCount, x0 + shiftx, y + shifty, x + shiftx, y + 1 + shifty);
  298. pData->rdh.nCount++;
  299. if (x0 + shiftx < pData->rdh.rcBound.left) pData->rdh.rcBound.left = x0 + shiftx;
  300. if (y + shifty < pData->rdh.rcBound.top) pData->rdh.rcBound.top = y + shifty;
  301. if (x + shiftx > pData->rdh.rcBound.right) pData->rdh.rcBound.right = x + shiftx;
  302. if (y + 1 + shifty > pData->rdh.rcBound.bottom) pData->rdh.rcBound.bottom = y + 1 + shifty;
  303. // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
  304. // large (ie: > 4000). Therefore, we have to create the region by multiple steps.
  305. if (pData->rdh.nCount == MAXRECTS)
  306. {
  307. OSREGIONHANDLE h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
  308. if (hRgn)
  309. {
  310. CombineRgn(hRgn, hRgn, h, RGN_OR);
  311. DeleteObject(h);
  312. }
  313. else hRgn = h;
  314. pData->rdh.nCount = 0;
  315. SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  316. }
  317. }
  318. }
  319. }
  320. // Create or extend the region with the remaining rectangles
  321. OSREGIONHANDLE h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
  322. if (hRgn)
  323. {
  324. CombineRgn(hRgn, hRgn, h, RGN_OR);
  325. DeleteObject(h);
  326. }
  327. else
  328. hRgn = h;
  329. // Clean up
  330. //FREE(pData);
  331. return hRgn;
  332. }
  333. bool RegionI::ptInRegion(const POINT *pt)
  334. {
  335. if (optimized) return !!PtInRect(&optrect, *pt);
  336. CHECK_REGION
  337. return !!PtInRegion(hrgn, pt->x, pt->y);
  338. }
  339. void RegionI::offset(int x, int y)
  340. {
  341. if (optimized)
  342. {
  343. optrect.left += x;
  344. optrect.top += y;
  345. optrect.right += x;
  346. optrect.bottom += y;
  347. return ;
  348. }
  349. CHECK_REGION
  350. if (srv)
  351. {
  352. hrgn = CreateRectRgn(0, 0, 0, 0);
  353. RegionServer *s = srv;
  354. srv = NULL;
  355. addRegion(s->getRegion());
  356. s->delRef(this);
  357. }
  358. if (x == 0 && y == 0) return ;
  359. deoptimize(); // because addregion may have optimized it
  360. OffsetRgn(hrgn, x, y);
  361. optimize();
  362. }
  363. void RegionI::getBox(RECT *r)
  364. {
  365. if (optimized)
  366. {
  367. *r = optrect;
  368. return ;
  369. }
  370. CHECK_REGION
  371. GetRgnBox(hrgn, r);
  372. }
  373. OSREGIONHANDLE RegionI::getOSHandle()
  374. {
  375. deoptimize();
  376. CHECK_REGION
  377. return hrgn;
  378. }
  379. void RegionI::subtractRect(const RECT *r)
  380. {
  381. RegionI s(r);
  382. subtractRegion(&s);
  383. }
  384. void RegionI::subtractRegion(const api_region *reg)
  385. {
  386. if (srv)
  387. {
  388. hrgn = CreateRectRgn(0, 0, 0, 0);
  389. RegionServer *s = srv;
  390. srv = NULL;
  391. addRegion(s->getRegion());
  392. s->delRef(this);
  393. }
  394. deoptimize();
  395. CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_DIFF);
  396. optimize();
  397. }
  398. void RegionI::andRegion(const api_region *reg)
  399. {
  400. if (srv)
  401. {
  402. hrgn = CreateRectRgn(0, 0, 0, 0);
  403. RegionServer *s = srv;
  404. srv = NULL;
  405. addRegion(s->getRegion());
  406. s->delRef(this);
  407. }
  408. deoptimize();
  409. CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_AND);
  410. optimize();
  411. }
  412. void RegionI::addRect(const RECT *r)
  413. {
  414. RegionI a(r);
  415. addRegion(&a);
  416. }
  417. void RegionI::addRegion(const api_region *reg)
  418. {
  419. if (srv)
  420. {
  421. hrgn = CreateRectRgn(0, 0, 0, 0);
  422. RegionServer *s = srv;
  423. srv = NULL;
  424. addRegion(s->getRegion());
  425. s->delRef(this);
  426. }
  427. deoptimize();
  428. ASSERT(reg != NULL);
  429. CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_OR);
  430. optimize();
  431. }
  432. int RegionI::isEmpty()
  433. {
  434. RECT r;
  435. getBox(&r);
  436. if (r.left == r.right || r.bottom == r.top) return 1;
  437. return 0;
  438. }
  439. int RegionI::enclosed(const api_region *r, api_region *outside)
  440. {
  441. deoptimize();
  442. OSREGIONHANDLE del = NULL;
  443. if (!outside)
  444. del = CreateRectRgn(0, 0, 0, 0);
  445. int rs = CombineRgn(outside ? outside->getOSHandle() : del, hrgn, GETOSHANDLE(r), RGN_DIFF);
  446. if (del != NULL) DeleteObject(del);
  447. optimize();
  448. return rs == NULLREGION;
  449. }
  450. #define IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND)
  451. int RegionI::intersectRgn(const api_region *r, api_region *intersection)
  452. {
  453. ASSERT(intersection != NULL);
  454. ASSERT(intersection != this);
  455. int rs;
  456. if (optimized)
  457. {
  458. deoptimize();
  459. rs = IntersectRgn(intersection->getOSHandle(), hrgn, GETOSHANDLE(r));
  460. DeleteObject(hrgn);
  461. hrgn=NULL;
  462. optimized=1;
  463. }
  464. else
  465. {
  466. rs = IntersectRgn(intersection->getOSHandle(), hrgn, GETOSHANDLE(r));
  467. }
  468. return (rs != NULLREGION && rs != ERROR);
  469. }
  470. int RegionI::doesIntersectRgn(const api_region *r)
  471. {
  472. if (optimized)
  473. {
  474. return RectInRegion(GETOSHANDLE(r), &optrect);
  475. }
  476. else
  477. {
  478. CHECK_REGION
  479. HRGN del = CreateRectRgn(0, 0, 0, 0);
  480. int rs = IntersectRgn(del, hrgn, GETOSHANDLE(r));
  481. DeleteObject(del);
  482. return (rs != NULLREGION && rs != ERROR);
  483. }
  484. }
  485. int RegionI::intersectRect(const RECT *r, api_region *intersection)
  486. {
  487. int rs;
  488. ASSERT(intersection != NULL);
  489. ASSERT(intersection != this);
  490. if (optimized)
  491. {
  492. RECT temp = optrect;
  493. rs = IntersectRect(&temp, &optrect, r);
  494. intersection->setRect(&temp);
  495. return rs;
  496. }
  497. else
  498. {
  499. CHECK_REGION
  500. OSREGIONHANDLE iRgn = intersection->getOSHandle();
  501. SetRectRgn(iRgn, r->left, r->top, r->right, r->bottom);
  502. rs = IntersectRgn(iRgn, hrgn, iRgn);
  503. }
  504. return (rs != NULLREGION && rs != ERROR);
  505. }
  506. int RegionI::doesIntersectRect(const RECT *r)
  507. {
  508. return RectInRegion(hrgn, r);
  509. }
  510. void RegionI::empty()
  511. {
  512. if (srv)
  513. {
  514. hrgn = CreateRectRgn(0, 0, 0, 0);
  515. ASSERT(hrgn != NULL);
  516. srv->delRef(this);
  517. srv = NULL;
  518. optimize();
  519. return ;
  520. }
  521. //deoptimize();
  522. if (hrgn != NULL)
  523. DeleteObject(hrgn);
  524. hrgn=NULL;
  525. //hrgn = CreateRectRgn(0, 0, 0, 0);
  526. optrect.left=0;
  527. optrect.top=0;
  528. optrect.right=0;
  529. optrect.bottom=0;
  530. optimized=1;
  531. //ASSERT(hrgn != NULL);
  532. //optimize();
  533. }
  534. void RegionI::setRect(const RECT *r)
  535. {
  536. if (srv)
  537. {
  538. hrgn = CreateRectRgnIndirect(r);
  539. srv->delRef(this);
  540. srv = NULL;
  541. optimize();
  542. return ;
  543. }
  544. //deoptimize();
  545. //CHECK_REGION
  546. if (hrgn)
  547. DeleteObject(hrgn);
  548. hrgn=NULL;
  549. //SetRectRgn(hrgn, r->left, r->top, r->right, r->bottom);
  550. optrect = *r;
  551. optimized = 1;
  552. //optimize();
  553. }
  554. int RegionI::equals(const api_region *r)
  555. {
  556. ASSERT(r);
  557. api_region *cl = const_cast<api_region*>(r)->clone();
  558. cl->subtractRegion(this);
  559. int ret = cl->isEmpty();
  560. const_cast<api_region*>(r)->disposeClone(cl);
  561. cl = clone();
  562. cl->subtractRegion(r);
  563. ret &= cl->isEmpty();
  564. disposeClone(cl);
  565. return ret;
  566. }
  567. int RegionI::isRect()
  568. {
  569. if (optimized) return 1;
  570. RECT r;
  571. getBox(&r);
  572. RegionI n(&r);
  573. return equals(&n);
  574. }
  575. void RegionI::scale(double sx, double sy, bool round)
  576. {
  577. if (srv)
  578. {
  579. hrgn = CreateRectRgn(0, 0, 0, 0);
  580. RegionServer *s = srv;
  581. srv = NULL;
  582. addRegion(s->getRegion());
  583. s->delRef(this);
  584. }
  585. deoptimize();
  586. CHECK_REGION
  587. DWORD size = 0;
  588. RECT box;
  589. getBox(&box);
  590. size = GetRegionData(hrgn, size, NULL);
  591. if (!size) return ;
  592. RGNDATA *data = (RGNDATA *)MALLOC(size);
  593. RECT *r = (RECT *)data->Buffer;
  594. GetRegionData(hrgn, size, (RGNDATA *)data);
  595. double adj = round ? 0.99999 : 0.0;
  596. int iadj = round ? 1 : 0;
  597. if (data->rdh.nCount == 1)
  598. {
  599. RECT nr = box;
  600. nr.left = (int)((double)nr.left * sx - iadj);
  601. nr.top = (int)((double)nr.top * sy - iadj);
  602. nr.right = (int)((double)nr.right * sx + adj);
  603. nr.bottom = (int)((double)nr.bottom * sy + adj);
  604. setRect(&nr);
  605. FREE(data);
  606. return ;
  607. }
  608. for (int i = 0;i < (int)data->rdh.nCount;i++)
  609. {
  610. r[i].left = (int)((double)r[i].left * sx - iadj);
  611. r[i].top = (int)((double)r[i].top * sy - iadj);
  612. r[i].right = (int)((double)r[i].right * sx + adj);
  613. r[i].bottom = (int)((double)r[i].bottom * sy + adj);
  614. }
  615. OSREGIONHANDLE nhrgn = ExtCreateRegion(NULL, size, data);
  616. if (!nhrgn)
  617. {
  618. nhrgn = CreateRectRgn(0, 0, 0, 0);
  619. }
  620. FREE(data);
  621. DeleteObject(hrgn);
  622. hrgn = nhrgn;
  623. optimize();
  624. }
  625. void RegionI::debug(int async)
  626. {
  627. if (!async)
  628. {
  629. SysCanvas c;
  630. RECT r;
  631. getBox(&r);
  632. // c.fillRect(&r, 0);
  633. InvertRgn(c.getHDC(), getOSHandle());
  634. Sleep(200);
  635. InvertRgn(c.getHDC(), getOSHandle());
  636. }
  637. else
  638. {
  639. SysCanvas c;
  640. RECT r;
  641. getBox(&r);
  642. // c.fillRect(&r, 0);
  643. if (lastdebug)
  644. InvertRgn(c.getHDC(), lastdebug->getOSHandle());
  645. delete lastdebug;
  646. lastdebug = new RegionI();
  647. lastdebug->addRegion(this);
  648. InvertRgn(c.getHDC(), getOSHandle());
  649. }
  650. }
  651. // later we can cache this data or something if needed
  652. int RegionI::getNumRects()
  653. {
  654. if (optimized) return 1;
  655. int bytes_needed = GetRegionData(hrgn, 0, NULL) + sizeof(RGNDATA);
  656. MemBlock<unsigned char> data(bytes_needed);
  657. GetRegionData(hrgn, bytes_needed, (LPRGNDATA)data.getMemory());
  658. RGNDATA *rgndata = reinterpret_cast<RGNDATA *>(data.getMemory());
  659. return rgndata->rdh.nCount;
  660. }
  661. int RegionI::enumRect(int n, RECT *r)
  662. {
  663. if (optimized)
  664. {
  665. if (n == 0)
  666. {
  667. if (r != NULL) *r = optrect;
  668. return 1;
  669. }
  670. return 0;
  671. }
  672. if (n < 0) return 0;
  673. int bytes_needed = GetRegionData(hrgn, 0, NULL) + sizeof(RGNDATA);
  674. MemBlock<unsigned char> data(bytes_needed);
  675. GetRegionData(hrgn, bytes_needed, (LPRGNDATA)data.getMemory());
  676. RGNDATA *rgndata = reinterpret_cast<RGNDATA *>(data.getMemory());
  677. int nrects = rgndata->rdh.nCount;
  678. if (n >= nrects) return 0;
  679. RECT *rectlist = reinterpret_cast<RECT*>(rgndata->Buffer);
  680. *r = rectlist[n];
  681. return 1;
  682. }
  683. void RegionI::optimize()
  684. {
  685. if (optimized) return ;
  686. if (srv != NULL) return ; // region is cached and shared, do not optimize
  687. CHECK_REGION
  688. getBox(&optrect);
  689. if (IsRectEmpty(&optrect))
  690. return;
  691. RECT br;
  692. OSREGIONHANDLE gr = CreateRectRgnIndirect(&optrect);
  693. OSREGIONHANDLE res = CreateRectRgn(0, 0, 0, 0);
  694. /*
  695. // if they don't intersect, we may be offset
  696. IntersectRgn(res, gr, hrgn);
  697. GetRgnBox(res, &br);
  698. if (br.left == br.right || br.bottom == br.top)
  699. {
  700. DeleteObject(gr);
  701. DeleteObject(res);
  702. return ;
  703. }
  704. */
  705. // if they intersect, but when subtracting the region from the rect, we get nothing, they're the same, let's optimize
  706. CombineRgn(res, gr, hrgn, RGN_DIFF);
  707. DeleteObject(gr);
  708. GetRgnBox(res, &br);
  709. DeleteObject(res);
  710. if (br.left == br.right || br.bottom == br.top)
  711. {
  712. optimized = 1;
  713. DeleteObject(hrgn);
  714. hrgn = NULL;
  715. }
  716. }
  717. void RegionI::deoptimize()
  718. {
  719. if (!optimized) return ;
  720. CHECK_REGION
  721. SetRectRgn(hrgn, optrect.left, optrect.top, optrect.right, optrect.bottom);
  722. //if (hrgn != NULL) { DeleteObject(hrgn); hrgn = NULL; }
  723. //hrgn = CreateRectRgnIndirect(&optrect);
  724. //CHECK_REGION
  725. optimized = 0;
  726. }
  727. #define CBCLASS RegionServerI
  728. START_DISPATCH;
  729. VCB(REGIONSERVER_ADDREF, addRef);
  730. VCB(REGIONSERVER_DELREF, delRef);
  731. CB(REGIONSERVER_GETREGION, getRegion);
  732. END_DISPATCH;
  733. #endif//WIN32