aboutsummaryrefslogtreecommitdiff
path: root/Src/tataki/region
diff options
context:
space:
mode:
Diffstat (limited to 'Src/tataki/region')
-rw-r--r--Src/tataki/region/api_region.cpp1
-rw-r--r--Src/tataki/region/api_region.h201
-rw-r--r--Src/tataki/region/mac/osx_region_hishape.cpp217
-rw-r--r--Src/tataki/region/mac/region.h116
-rw-r--r--Src/tataki/region/region.h5
-rw-r--r--Src/tataki/region/win/region.h137
-rw-r--r--Src/tataki/region/win/win32_region.cpp813
7 files changed, 1490 insertions, 0 deletions
diff --git a/Src/tataki/region/api_region.cpp b/Src/tataki/region/api_region.cpp
new file mode 100644
index 00000000..f9c263ef
--- /dev/null
+++ b/Src/tataki/region/api_region.cpp
@@ -0,0 +1 @@
+#include "api_region.h" \ No newline at end of file
diff --git a/Src/tataki/region/api_region.h b/Src/tataki/region/api_region.h
new file mode 100644
index 00000000..2dbcd51f
--- /dev/null
+++ b/Src/tataki/region/api_region.h
@@ -0,0 +1,201 @@
+#ifndef __WASABI_API_REGION_H
+#define __WASABI_API_REGION_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/export.h>
+
+class NOVTABLE api_region : public Dispatchable
+{
+protected:
+ api_region() {}
+ virtual ~api_region() {}
+
+public:
+ DISPATCH_CODES
+ {
+ REGION_GETOSHANDLE = 50,
+ REGION_CLONE = 100,
+ REGION_DISPOSECLONE = 110,
+ REGION_PTINREGION = 120,
+ REGION_OFFSET = 130,
+ REGION_GETBOX = 140,
+ REGION_SUBTRACTRGN = 150,
+ REGION_SUBTRACTRECT = 160,
+ REGION_ADDRECT = 170,
+ REGION_ADD = 180,
+ REGION_AND = 190,
+ REGION_SETRECT = 200,
+ REGION_EMPTY = 210,
+ REGION_ISEMPTY = 220,
+ REGION_EQUALS = 230,
+ REGION_ENCLOSED = 240,
+ REGION_INTERSECTRGN = 250,
+ REGION_DOESINTERSECTRGN = 251,
+ REGION_INTERSECTRECT = 260,
+ REGION_ISRECT = 270,
+ REGION_SCALE = 280,
+ REGION_DEBUG = 290,
+ REGION_MAKEWNDREGION = 300,
+ REGION_GETNUMRECTS = 310,
+ REGION_ENUMRECT = 320,
+ };
+public:
+ OSREGIONHANDLE getOSHandle(); // avoid as much as you can, should be used only when you need to call the OS api
+
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *r);
+ void subtractRgn(const api_region *r) { subtractRegion(r); } //DEPRECATED
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside = NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+
+ int isRect();
+ void scale(double sx, double sy, bool round = 0);
+ void debug(int async = 0);
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+
+ // this is how you can enumerate the subrects that compose to make up the
+ // entire region
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+};
+
+inline OSREGIONHANDLE api_region::getOSHandle()
+{
+ return _call(REGION_GETOSHANDLE, (OSREGIONHANDLE)NULL);
+}
+
+inline api_region *api_region::clone()
+{
+ return _call(REGION_CLONE, (api_region *)NULL);
+}
+
+inline void api_region::disposeClone(api_region *r)
+{
+ _voidcall(REGION_DISPOSECLONE, r);
+}
+
+inline bool api_region::ptInRegion(const POINT *pt)
+{
+ return _call(REGION_PTINREGION, false, pt);
+}
+
+inline void api_region::offset(int x, int y)
+{
+ _voidcall(REGION_OFFSET, x, y);
+}
+
+inline void api_region::getBox(RECT *r)
+{
+ _voidcall(REGION_GETBOX, r);
+}
+
+inline void api_region::subtractRegion(const api_region *reg)
+{
+ _voidcall(REGION_SUBTRACTRGN, reg);
+}
+
+inline void api_region::subtractRect(const RECT *r)
+{
+ _voidcall(REGION_SUBTRACTRECT, r);
+}
+
+inline void api_region::addRect(const RECT *r)
+{
+ _voidcall(REGION_ADDRECT, r);
+}
+
+inline void api_region::addRegion(const api_region *r)
+{
+ _voidcall(REGION_ADD, r);
+}
+
+inline void api_region::andRegion(const api_region *r)
+{
+ _voidcall(REGION_AND, r);
+}
+
+inline void api_region::setRect(const RECT *r)
+{
+ _voidcall(REGION_SETRECT, r);
+}
+
+inline void api_region::empty()
+{
+ _voidcall(REGION_EMPTY);
+}
+
+inline int api_region::isEmpty()
+{
+ return _call(REGION_ISEMPTY, 0);
+}
+
+inline int api_region::equals(const api_region *r)
+{
+ return _call(REGION_EQUALS, 0, r);
+}
+
+inline int api_region::enclosed(const api_region *r, api_region *outside)
+{
+ return _call(REGION_ENCLOSED, 0, r, outside);
+}
+
+inline int api_region::intersectRgn(const api_region *r, api_region *intersection)
+{
+ return _call(REGION_INTERSECTRGN, 0, r, intersection);
+}
+
+inline int api_region::doesIntersectRgn(const api_region *r)
+{
+ return _call(REGION_DOESINTERSECTRGN, 0, r);
+}
+
+inline int api_region::intersectRect(const RECT *r, api_region *intersection)
+{
+ return _call(REGION_INTERSECTRECT, 0, r, intersection);
+}
+
+inline int api_region::isRect()
+{
+ return _call(REGION_ISRECT, 0);
+}
+
+inline void api_region::scale(double sx, double sy, bool round)
+{
+ _voidcall(REGION_SCALE, sx, sy, round);
+}
+
+inline void api_region::debug(int async)
+{
+ _voidcall(REGION_DEBUG, async);
+}
+
+inline OSREGIONHANDLE api_region::makeWindowRegion()
+{
+ return _call(REGION_MAKEWNDREGION, (OSREGIONHANDLE)NULL);
+}
+
+inline int api_region::getNumRects()
+{
+ return _call(REGION_GETNUMRECTS, 0);
+}
+
+inline int api_region::enumRect(int n, RECT *r)
+{
+ return _call(REGION_ENUMRECT, 0, n, r);
+}
+
+#endif
diff --git a/Src/tataki/region/mac/osx_region_hishape.cpp b/Src/tataki/region/mac/osx_region_hishape.cpp
new file mode 100644
index 00000000..348ba1de
--- /dev/null
+++ b/Src/tataki/region/mac/osx_region_hishape.cpp
@@ -0,0 +1,217 @@
+#include <Carbon/Carbon.h>
+#include <tataki/region/region.h>
+#include <tataki/bitmap/bitmap.h>
+
+RegionI::RegionI() : rgn(0)
+{
+}
+
+RegionI::RegionI(const RECT *r) : rgn(0)
+{
+ setRect(r);
+}
+
+RegionI::RegionI(HIMutableShapeRef _rgn) : rgn(_rgn)
+{
+}
+
+RegionI::RegionI(HIShapeRef _rgn)
+{
+ rgn=HIShapeCreateMutableCopy(_rgn);
+}
+
+RegionI::~RegionI()
+{
+ if (rgn)
+ CFRelease(rgn);
+}
+
+RegionI::RegionI(RgnHandle qdrgn)
+{
+ HIShapeRef shape = HIShapeCreateWithQDRgn(qdrgn);
+ rgn = HIShapeCreateMutableCopy(shape);
+ CFRelease(shape);
+}
+
+RegionI::RegionI(SkinBitmap *bitmap)
+{
+ // TODO: we need to find a much better way to do this
+ RECT r;
+ r.left=0;
+ r.top=0;
+ r.right=bitmap->getWidth();
+ r.bottom=bitmap->getHeight();
+ setRect(&r);
+}
+
+
+OSREGIONHANDLE RegionI::getOSHandle()
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ return rgn;
+}
+
+api_region *RegionI::clone()
+{
+ if (!rgn)
+ return new RegionI();
+ else
+ return new RegionI(HIShapeCreateMutableCopy(rgn));
+}
+
+void RegionI::disposeClone(api_region *r)
+{
+ if (r) // yes we need to check for NULL here because r != static_cast<>(r)
+ delete static_cast<RegionI *>(r);
+}
+
+bool RegionI::ptInRegion(const POINT *pt)
+{
+ if (!rgn)
+ return false;
+ HIPoint hipt = HIPointFromPOINT(pt);
+ return !!HIShapeContainsPoint(rgn, &hipt);
+}
+
+void RegionI::offset(int x, int y)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+
+ HIShapeOffset(rgn, x, y);
+}
+
+void RegionI::getBox(RECT *r)
+{
+ if (!rgn) // TODO: we could manually set r to 0,0,0,0
+ rgn = HIShapeCreateMutable();
+
+ HIRect rect;
+ HIShapeGetBounds(rgn, &rect);
+ *r = RECTFromHIRect(&rect);
+}
+
+void RegionI::subtractRegion(const api_region *r)
+{
+ if (rgn)
+ {
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef sub = reg->getOSHandle();
+ HIShapeDifference(rgn,sub, rgn);
+ }
+}
+
+void RegionI::subtractRect(const RECT *r)
+{
+ if (rgn)
+ {
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef sub = HIShapeCreateWithRect(&rect);
+ HIShapeDifference(rgn, sub, rgn);
+ }
+}
+
+void RegionI::addRect(const RECT *r)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef add = HIShapeCreateWithRect(&rect);
+ HIShapeUnion(rgn, add, rgn);
+}
+
+void RegionI::addRegion(const api_region *r)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef add = reg->getOSHandle();
+ HIShapeUnion(rgn, add, rgn);
+}
+
+void RegionI::andRegion(const api_region *r)
+{
+ if (rgn) // intersection with empty region will always be empty
+ {
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef intersection = reg->getOSHandle();
+ HIShapeIntersect(rgn, intersection, rgn);
+ }
+}
+
+void RegionI::setRect(const RECT *r)
+{
+ if (rgn)
+ CFRelease(rgn);
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef rectRgn = HIShapeCreateWithRect(&rect);
+ rgn = HIShapeCreateMutableCopy(rectRgn);
+ CFRelease(rectRgn);
+}
+
+void RegionI::empty()
+{
+ if (rgn)
+ CFRelease(rgn);
+ rgn=0;
+}
+
+int RegionI::isEmpty()
+{
+ if (!rgn)
+ return 1;
+ return !!HIShapeIsEmpty(rgn);
+}
+
+int RegionI::isRect()
+{
+ if (!rgn)
+ return 1;
+ return !!HIShapeIsRectangular(rgn);
+}
+
+int RegionI::intersectRgn(const api_region *r, api_region *intersection)
+{
+ intersection->empty();
+ intersection->addRegion(this);
+ intersection->andRegion(r);
+ return !intersection->isEmpty();
+}
+
+int RegionI::intersectRect(const RECT *r, api_region *intersection)
+{
+ intersection->setRect(r);
+ intersection->andRegion(this);
+ return !intersection->isEmpty();
+}
+
+#define CBCLASS RegionI
+START_DISPATCH;
+CB(REGION_GETOSHANDLE, getOSHandle);
+CB(REGION_CLONE, clone);
+VCB(REGION_DISPOSECLONE, disposeClone);
+CB(REGION_PTINREGION, ptInRegion);
+VCB(REGION_OFFSET, offset);
+VCB(REGION_GETBOX, getBox);
+VCB(REGION_SUBTRACTRGN, subtractRegion);
+VCB(REGION_SUBTRACTRECT, subtractRect);
+VCB(REGION_ADDRECT, addRect);
+VCB(REGION_ADD, addRegion);
+VCB(REGION_AND, andRegion);
+VCB(REGION_SETRECT, setRect);
+VCB(REGION_EMPTY, empty);
+CB(REGION_ISEMPTY, isEmpty);
+CB(REGION_ISRECT, isRect);
+CB(REGION_INTERSECTRGN, intersectRgn);
+CB(REGION_INTERSECTRECT, intersectRect);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CBCLASS RegionServerI
+START_DISPATCH;
+VCB(REGIONSERVER_ADDREF, addRef);
+VCB(REGIONSERVER_DELREF, delRef);
+CB(REGIONSERVER_GETREGION, getRegion);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/tataki/region/mac/region.h b/Src/tataki/region/mac/region.h
new file mode 100644
index 00000000..f3404ea2
--- /dev/null
+++ b/Src/tataki/region/mac/region.h
@@ -0,0 +1,116 @@
+#ifndef __REGION_H
+#define __REGION_H
+
+#include <tataki/export.h>
+#include <Carbon/Carbon.h>
+#include <bfc/platform/platform.h>
+#include <tataki/region/api_region.h>
+
+class SkinBitmap;
+
+class TATAKIAPI RegionI : public api_region
+{
+public:
+ RegionI();
+ RegionI(const RECT *r);
+ RegionI(RgnHandle qdrgn);
+ RegionI(HIShapeRef _rgn);
+ RegionI(SkinBitmap *bitmap);
+ ~RegionI();
+
+ // api_region
+ OSREGIONHANDLE getOSHandle();
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *r);
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside = NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+
+ int isRect();
+ void scale(double sx, double sy, bool round = 0);
+ void debug(int async = 0);
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+
+ // this is how you can enumerate the subrects that compose to make up the
+ // entire region
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+
+
+private:
+ RegionI(HIMutableShapeRef _rgn);
+ HIMutableShapeRef rgn;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+// TODO: we could take of advantage of HIShapeRef's built in reference counting to implement this
+class RegionServer : public Dispatchable {
+
+protected:
+ RegionServer() {}
+ virtual ~RegionServer() {}
+
+public:
+
+ void addRef(void *client);
+ void delRef(void *client);
+ api_region *getRegion();
+
+ enum {
+ REGIONSERVER_ADDREF = 500,
+ REGIONSERVER_DELREF = 550,
+ REGIONSERVER_GETREGION = 600,
+ };
+};
+
+inline void RegionServer::addRef(void *client) {
+ _voidcall(REGIONSERVER_ADDREF, (api_region *)NULL, client);
+}
+
+inline void RegionServer::delRef(void *client) {
+ _voidcall(REGIONSERVER_DELREF, client);
+}
+
+inline api_region * RegionServer::getRegion() {
+ return _call(REGIONSERVER_GETREGION, (api_region *)NULL);
+}
+
+class TATAKIAPI RegionServerI : public RegionServer {
+public :
+
+ RegionServerI() { numrefs = 0; }
+ virtual ~RegionServerI() {}
+
+ virtual void addRef(void *client) { numrefs++; }
+ virtual void delRef(void *client) { numrefs--; }
+ virtual api_region *getRegion()=0;
+
+ virtual int getNumRefs() { return numrefs; }
+
+protected:
+
+ RECVS_DISPATCH;
+
+private:
+
+ int numrefs;
+};
+#endif
+
+
diff --git a/Src/tataki/region/region.h b/Src/tataki/region/region.h
new file mode 100644
index 00000000..cf03c01c
--- /dev/null
+++ b/Src/tataki/region/region.h
@@ -0,0 +1,5 @@
+#if defined _WIN64 || defined _WIN32
+#include "win/region.h"
+#elif defined(__APPLE__)
+#include "mac/region.h"
+#endif
diff --git a/Src/tataki/region/win/region.h b/Src/tataki/region/win/region.h
new file mode 100644
index 00000000..849fba3e
--- /dev/null
+++ b/Src/tataki/region/win/region.h
@@ -0,0 +1,137 @@
+#ifndef __REGION_H
+#define __REGION_H
+
+#include <tataki/bitmap/bitmap.h>
+#include <bfc/dispatch.h>
+#include <tataki/export.h>
+
+class BaseWnd;
+class Canvas;
+class api_region;
+class RegionServer;
+
+#include <tataki/region/api_region.h>
+
+class TATAKIAPI RegionI : public api_region
+{
+public:
+ RegionI();
+ RegionI(const RegionI *copy);
+ RegionI(const RECT *r);
+ RegionI(int l, int t, int r, int b);
+ RegionI(OSREGIONHANDLE region);
+ RegionI(SkinBitmap *bitmap, RECT *r=NULL, int xoffset=0, int yoffset=0, bool inverted=false, int dothreshold=0, __int8 threshold=0, int threversed=0, int minalpha=1);
+ RegionI(Canvas *c, RECT *defboundbox=NULL);
+ virtual ~RegionI();
+
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *reg);
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside=NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+ int doesIntersectRect(const RECT *r);
+ int isRect();
+ void scale(double sx, double sy, bool round=0);
+ void debug(int async=0);
+
+ // NONPORTABLE
+
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+ OSREGIONHANDLE getOSHandle(); // avoid as much as you can, should be used only by WIN32-dependant classes
+
+ // END NONPORTABLE
+
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+
+ OSREGIONHANDLE 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 __int8 threshold, int thinverse, int minalpha);
+
+private:
+
+ inline void init();
+ void optimize();
+ void deoptimize();
+
+ OSREGIONHANDLE hrgn;
+ OSREGIONHANDLE alphaToRegionRect(SkinBitmap *bitmap, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted=false, int dothreshold=0, unsigned __int8 threshold=0, int thinverse=0, int minalpha=1/* 1..255*/);
+ RECT overlay;
+ int clonecount;
+ RegionI *lastdebug;
+ RegionServer *srv;
+ RECT optrect;
+ int optimized;
+
+protected:
+
+ RECVS_DISPATCH;
+};
+
+class RegionServer : public Dispatchable {
+
+ protected:
+ RegionServer() {}
+ virtual ~RegionServer() {}
+
+ public:
+
+ void addRef(void *client);
+ void delRef(void *client);
+ api_region *getRegion();
+
+ enum {
+ REGIONSERVER_ADDREF = 500,
+ REGIONSERVER_DELREF = 550,
+ REGIONSERVER_GETREGION = 600,
+ };
+};
+
+inline void RegionServer::addRef(void *client) {
+ _voidcall(REGIONSERVER_ADDREF, (api_region *)NULL, client);
+}
+
+inline void RegionServer::delRef(void *client) {
+ _voidcall(REGIONSERVER_DELREF, client);
+}
+
+inline api_region * RegionServer::getRegion() {
+ return _call(REGIONSERVER_GETREGION, (api_region *)NULL);
+}
+
+class TATAKIAPI RegionServerI : public RegionServer
+{
+ public :
+
+ RegionServerI() { numrefs = 0; }
+ virtual ~RegionServerI() {}
+
+ virtual void addRef(void *client) { numrefs++; }
+ virtual void delRef(void *client) { numrefs--; }
+ virtual api_region *getRegion()=0;
+
+ virtual int getNumRefs() { return numrefs; }
+
+ protected:
+
+ RECVS_DISPATCH;
+
+ private:
+
+ int numrefs;
+};
+
+#endif
+
+
diff --git a/Src/tataki/region/win/win32_region.cpp b/Src/tataki/region/win/win32_region.cpp
new file mode 100644
index 00000000..5fb3c3c5
--- /dev/null
+++ b/Src/tataki/region/win/win32_region.cpp
@@ -0,0 +1,813 @@
+#if defined _WIN64 || defined _WIN32
+#include <tataki/api__tataki.h>
+#include "region.h"
+#include <api/imgldr/api_imgldr.h>
+#include <tataki/region/api_region.h>
+#include <tataki/canvas/ifc_canvas.h>
+#include <api/wnd/basewnd.h>
+
+
+#define GETOSHANDLE(x) (const_cast<api_region *>(x)->getOSHandle())
+
+#define CBCLASS RegionI
+START_DISPATCH;
+CB(REGION_GETOSHANDLE, getOSHandle);
+CB(REGION_CLONE, clone);
+VCB(REGION_DISPOSECLONE, disposeClone);
+CB(REGION_PTINREGION, ptInRegion);
+VCB(REGION_OFFSET, offset);
+VCB(REGION_GETBOX, getBox);
+VCB(REGION_SUBTRACTRGN, subtractRegion);
+VCB(REGION_SUBTRACTRECT, subtractRect);
+VCB(REGION_ADDRECT, addRect);
+VCB(REGION_ADD, addRegion);
+VCB(REGION_AND, andRegion);
+VCB(REGION_SETRECT, setRect);
+VCB(REGION_EMPTY, empty);
+CB(REGION_ISEMPTY, isEmpty);
+CB(REGION_EQUALS, equals);
+CB(REGION_ENCLOSED, enclosed);
+CB(REGION_INTERSECTRECT, intersectRect);
+CB(REGION_DOESINTERSECTRGN, doesIntersectRgn);
+CB(REGION_INTERSECTRGN, intersectRgn);
+CB(REGION_ISRECT, isRect);
+VCB(REGION_SCALE, scale);
+VCB(REGION_DEBUG, debug);
+CB(REGION_MAKEWNDREGION, makeWindowRegion);
+CB(REGION_GETNUMRECTS, getNumRects);
+CB(REGION_ENUMRECT, enumRect);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CHECK_REGION \
+ if (hrgn == NULL) hrgn = CreateRectRgn(0,0,0,0);
+
+RegionI::RegionI()
+{
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ init();
+}
+
+RegionI::RegionI(const RECT *r)
+{
+ hrgn = 0;
+ init();
+ optrect = *r;
+ optimized = 1;
+ //hrgn = CreateRectRgn(r->left,r->top,r->right,r->bottom);
+ //if (!hrgn) hrgn = CreateRectRgn(0,0,0,0);
+ //init();
+ //optimize();
+}
+
+RegionI::RegionI(int l, int t, int r, int b)
+{
+ hrgn = 0;
+ init();
+ optrect.left = l;
+ optrect.top = t;
+ optrect.right = r;
+ optrect.bottom = b;
+ optimized = 1;
+
+ //hrgn = CreateRectRgn(l,t,r,b);
+ //if (!hrgn) hrgn = CreateRectRgn(0,0,0,0);
+ //init();
+ //optimize();
+}
+
+RegionI::RegionI(OSREGIONHANDLE r)
+{
+ OSREGIONHANDLE R = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(R, r, r, RGN_COPY);
+ hrgn = R;
+ init();
+ optimize();
+}
+
+RegionI::RegionI(const RegionI *copy)
+{
+ init();
+ if (copy->optimized)
+ {
+ optrect = copy->optrect;
+ optimized = copy->optimized;
+ hrgn = 0;
+ }
+ else
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(hrgn, copy->hrgn, copy->hrgn, RGN_COPY);
+ }
+}
+
+RegionI::RegionI(Canvas *c, RECT *defbounds)
+{
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ if (!GetClipRgn(c->getHDC(), hrgn))
+ {
+ if (defbounds != NULL)
+ {
+ SetRectRgn(hrgn, defbounds->left, defbounds->top, defbounds->right, defbounds->bottom);
+ optrect=*defbounds;
+ optimized=1;
+ }
+ }
+ init();
+ optimize();
+}
+
+RegionI::~RegionI()
+{
+ delete lastdebug;
+ if (srv != NULL) srv->delRef(this);
+ ASSERT(clonecount == 0);
+ if (srv == NULL && hrgn != NULL) DeleteObject(hrgn);
+}
+
+void RegionI::init()
+{
+ srv = NULL;
+ clonecount = 0;
+ lastdebug = NULL;
+ optimized = 0;
+}
+
+api_region *RegionI::clone()
+{
+ api_region *newregion = new RegionI(this);
+ clonecount++;
+ return newregion;
+}
+
+void RegionI::disposeClone(api_region *r)
+{
+ RegionI *ri = static_cast<RegionI *>(r);
+ delete ri; // todo: validate pointer before deleting
+ clonecount--;
+}
+
+// returns a handle that SetWindowRgn understands (non portable). We should NOT delete this handle, windows will delete
+// it by itself upon setting a new region of destroying the window
+OSREGIONHANDLE RegionI::makeWindowRegion()
+{
+ deoptimize();
+ OSREGIONHANDLE R = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(R, hrgn, hrgn, RGN_COPY);
+ optimize();
+ return R;
+}
+
+RegionI::RegionI(SkinBitmap *bitmap, RECT *r, int xoffset, int yoffset, bool inverted, int dothreshold, char threshold, int thinverse, int minalpha)
+{
+ init();
+ const wchar_t *id = bitmap->getBitmapName();
+
+ if (xoffset == 0 && yoffset == 0 && r == NULL && !inverted && !dothreshold && minalpha == 1 && id != NULL && *id != 0)
+ {
+ srv = WASABI_API_IMGLDR->imgldr_requestSkinRegion(id);
+ if (srv != NULL)
+ {
+ srv->addRef(this);
+ hrgn = srv->getRegion()->getOSHandle();
+ }
+ }
+
+ if (srv == NULL)
+ {
+ if (r)
+ hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, TRUE, r->left, r->top, r->right - r->left, r->bottom - r->top, inverted, dothreshold, threshold, thinverse, minalpha);
+ else
+ hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, FALSE, 0, 0, 0, 0, inverted, dothreshold, threshold, thinverse, minalpha);
+
+ if (id != NULL && *id != 0)
+ {
+ if (xoffset == 0 && yoffset == 0 && r == NULL && !inverted && !dothreshold && minalpha == 1)
+ {
+ WASABI_API_IMGLDR->imgldr_cacheSkinRegion(id, this);
+ srv = WASABI_API_IMGLDR->imgldr_requestSkinRegion(id);
+ if (srv != NULL)
+ {
+ srv->addRef(this);
+ DeleteObject(hrgn);
+ hrgn = srv->getRegion()->getOSHandle();
+ }
+ }
+ }
+ }
+ optimize();
+
+}
+
+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)
+{
+ 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);
+}
+
+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)
+{
+ OSREGIONHANDLE hRgn = NULL;
+ if (!pbits32) return NULL;
+
+ RGNDATA *pData;
+ int y, x;
+
+ // For better performances, we will use the ExtCreateRegion() function to create the
+ // region. This function take a RGNDATA structure on entry. We will add rectangles by
+ // amount of ALLOC_UNIT number in this structure.
+ // JF> rects are 8 bytes, so this allocates just under 16kb of memory, no need to REALLOC
+#define MAXRECTS 2000
+ __int8 regionMemory[sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS)] = {0};
+ //pData = (RGNDATA *)MALLOC(sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS));
+ pData = (RGNDATA *)regionMemory;
+ //if (!pData) return NULL;
+
+ pData->rdh.dwSize = sizeof(RGNDATAHEADER);
+ pData->rdh.iType = RDH_RECTANGLES;
+ pData->rdh.nCount = pData->rdh.nRgnSize = 0;
+
+ SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+
+ int x_end = (portion ? _w + _x : bmWidth);
+ int y_end = (portion ? _h + _y : bmHeight);
+ int x_start = (portion ? _x : 0);
+ int y_start = (portion ? _y : 0);
+
+ x_start += bmX;
+ x_end += bmX;
+ y_start += bmY;
+ y_end += bmY;
+
+ unsigned int iv = minalpha << 24; //inverted?0xff000000:0;
+
+ int shiftx = xoffset - bmX;
+ int shifty = yoffset - bmY;
+
+ for (y = y_start; y < y_end; y++)
+ {
+ // Scan each bitmap pixel from left to right
+ unsigned int *lineptr = ((unsigned int *)pbits32) + fullw * y;
+ for (x = x_start; x < x_end; x++)
+ {
+ // Search for a continuous range of "non transparent pixels"
+ int x0 = x;
+ unsigned int *p = lineptr;
+ if (dothreshold)
+ {
+ if (inverted)
+ {
+ if (thinverse)
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) >= iv ||
+ (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
+ break;
+ x++;
+ }
+ }
+ else
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) >= iv ||
+ (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
+ break;
+ x++;
+ }
+ }
+ }
+ else
+ {
+ if (thinverse)
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) < iv ||
+ (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
+ break;
+ x++;
+ }
+ }
+ else
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) < iv ||
+ (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
+ break;
+ x++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (inverted)
+ {
+ while (x < x_end)
+ {
+ if ((p[x] & 0xFF000000) >= iv) break;
+ x++;
+ }
+ }
+ else
+ {
+ while (x < x_end)
+ {
+ if ((p[x] & 0xFF000000) < iv) break;
+ x++;
+ }
+ }
+ }
+
+ if (x > x0)
+ {
+ SetRect(((RECT *)&pData->Buffer) + pData->rdh.nCount, x0 + shiftx, y + shifty, x + shiftx, y + 1 + shifty);
+
+ pData->rdh.nCount++;
+
+ if (x0 + shiftx < pData->rdh.rcBound.left) pData->rdh.rcBound.left = x0 + shiftx;
+ if (y + shifty < pData->rdh.rcBound.top) pData->rdh.rcBound.top = y + shifty;
+ if (x + shiftx > pData->rdh.rcBound.right) pData->rdh.rcBound.right = x + shiftx;
+ if (y + 1 + shifty > pData->rdh.rcBound.bottom) pData->rdh.rcBound.bottom = y + 1 + shifty;
+
+ // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
+ // large (ie: > 4000). Therefore, we have to create the region by multiple steps.
+ if (pData->rdh.nCount == MAXRECTS)
+ {
+ OSREGIONHANDLE h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
+ if (hRgn)
+ {
+ CombineRgn(hRgn, hRgn, h, RGN_OR);
+ DeleteObject(h);
+ }
+ else hRgn = h;
+ pData->rdh.nCount = 0;
+ SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+ }
+ }
+ }
+ }
+
+ // Create or extend the region with the remaining rectangles
+ OSREGIONHANDLE h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
+ if (hRgn)
+ {
+ CombineRgn(hRgn, hRgn, h, RGN_OR);
+ DeleteObject(h);
+ }
+ else
+ hRgn = h;
+
+ // Clean up
+ //FREE(pData);
+
+ return hRgn;
+}
+
+bool RegionI::ptInRegion(const POINT *pt)
+{
+ if (optimized) return !!PtInRect(&optrect, *pt);
+ CHECK_REGION
+ return !!PtInRegion(hrgn, pt->x, pt->y);
+}
+
+void RegionI::offset(int x, int y)
+{
+ if (optimized)
+ {
+ optrect.left += x;
+ optrect.top += y;
+ optrect.right += x;
+ optrect.bottom += y;
+ return ;
+ }
+ CHECK_REGION
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ if (x == 0 && y == 0) return ;
+ deoptimize(); // because addregion may have optimized it
+ OffsetRgn(hrgn, x, y);
+ optimize();
+}
+
+void RegionI::getBox(RECT *r)
+{
+ if (optimized)
+ {
+ *r = optrect;
+ return ;
+ }
+ CHECK_REGION
+ GetRgnBox(hrgn, r);
+}
+
+OSREGIONHANDLE RegionI::getOSHandle()
+{
+ deoptimize();
+ CHECK_REGION
+ return hrgn;
+}
+
+void RegionI::subtractRect(const RECT *r)
+{
+ RegionI s(r);
+ subtractRegion(&s);
+}
+
+void RegionI::subtractRegion(const api_region *reg)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ deoptimize();
+ CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_DIFF);
+ optimize();
+}
+
+void RegionI::andRegion(const api_region *reg)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+
+ deoptimize();
+ CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_AND);
+ optimize();
+}
+
+void RegionI::addRect(const RECT *r)
+{
+ RegionI a(r);
+ addRegion(&a);
+}
+
+void RegionI::addRegion(const api_region *reg)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ deoptimize();
+ ASSERT(reg != NULL);
+ CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_OR);
+ optimize();
+}
+
+int RegionI::isEmpty()
+{
+ RECT r;
+ getBox(&r);
+ if (r.left == r.right || r.bottom == r.top) return 1;
+ return 0;
+}
+
+int RegionI::enclosed(const api_region *r, api_region *outside)
+{
+ deoptimize();
+ OSREGIONHANDLE del = NULL;
+ if (!outside)
+ del = CreateRectRgn(0, 0, 0, 0);
+ int rs = CombineRgn(outside ? outside->getOSHandle() : del, hrgn, GETOSHANDLE(r), RGN_DIFF);
+ if (del != NULL) DeleteObject(del);
+ optimize();
+ return rs == NULLREGION;
+}
+
+#define IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND)
+
+int RegionI::intersectRgn(const api_region *r, api_region *intersection)
+{
+ ASSERT(intersection != NULL);
+ ASSERT(intersection != this);
+ int rs;
+ if (optimized)
+ {
+ deoptimize();
+ rs = IntersectRgn(intersection->getOSHandle(), hrgn, GETOSHANDLE(r));
+ DeleteObject(hrgn);
+ hrgn=NULL;
+ optimized=1;
+ }
+ else
+ {
+ rs = IntersectRgn(intersection->getOSHandle(), hrgn, GETOSHANDLE(r));
+ }
+
+ return (rs != NULLREGION && rs != ERROR);
+}
+
+int RegionI::doesIntersectRgn(const api_region *r)
+{
+ if (optimized)
+ {
+ return RectInRegion(GETOSHANDLE(r), &optrect);
+ }
+ else
+ {
+ CHECK_REGION
+ HRGN del = CreateRectRgn(0, 0, 0, 0);
+ int rs = IntersectRgn(del, hrgn, GETOSHANDLE(r));
+ DeleteObject(del);
+ return (rs != NULLREGION && rs != ERROR);
+ }
+
+}
+
+int RegionI::intersectRect(const RECT *r, api_region *intersection)
+{
+ int rs;
+ ASSERT(intersection != NULL);
+ ASSERT(intersection != this);
+ if (optimized)
+ {
+ RECT temp = optrect;
+ rs = IntersectRect(&temp, &optrect, r);
+ intersection->setRect(&temp);
+ return rs;
+ }
+ else
+ {
+ CHECK_REGION
+
+ OSREGIONHANDLE iRgn = intersection->getOSHandle();
+ SetRectRgn(iRgn, r->left, r->top, r->right, r->bottom);
+ rs = IntersectRgn(iRgn, hrgn, iRgn);
+ }
+ return (rs != NULLREGION && rs != ERROR);
+}
+
+int RegionI::doesIntersectRect(const RECT *r)
+{
+ return RectInRegion(hrgn, r);
+}
+
+void RegionI::empty()
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ ASSERT(hrgn != NULL);
+ srv->delRef(this);
+ srv = NULL;
+ optimize();
+ return ;
+ }
+ //deoptimize();
+ if (hrgn != NULL)
+ DeleteObject(hrgn);
+ hrgn=NULL;
+ //hrgn = CreateRectRgn(0, 0, 0, 0);
+ optrect.left=0;
+ optrect.top=0;
+ optrect.right=0;
+ optrect.bottom=0;
+ optimized=1;
+ //ASSERT(hrgn != NULL);
+ //optimize();
+}
+
+void RegionI::setRect(const RECT *r)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgnIndirect(r);
+ srv->delRef(this);
+ srv = NULL;
+ optimize();
+ return ;
+ }
+ //deoptimize();
+ //CHECK_REGION
+ if (hrgn)
+ DeleteObject(hrgn);
+ hrgn=NULL;
+ //SetRectRgn(hrgn, r->left, r->top, r->right, r->bottom);
+ optrect = *r;
+ optimized = 1;
+ //optimize();
+}
+
+int RegionI::equals(const api_region *r)
+{
+ ASSERT(r);
+ api_region *cl = const_cast<api_region*>(r)->clone();
+ cl->subtractRegion(this);
+ int ret = cl->isEmpty();
+ const_cast<api_region*>(r)->disposeClone(cl);
+ cl = clone();
+ cl->subtractRegion(r);
+ ret &= cl->isEmpty();
+ disposeClone(cl);
+ return ret;
+}
+
+int RegionI::isRect()
+{
+ if (optimized) return 1;
+ RECT r;
+ getBox(&r);
+ RegionI n(&r);
+ return equals(&n);
+}
+
+void RegionI::scale(double sx, double sy, bool round)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ deoptimize();
+ CHECK_REGION
+ DWORD size = 0;
+ RECT box;
+ getBox(&box);
+ size = GetRegionData(hrgn, size, NULL);
+ if (!size) return ;
+ RGNDATA *data = (RGNDATA *)MALLOC(size);
+ RECT *r = (RECT *)data->Buffer;
+
+ GetRegionData(hrgn, size, (RGNDATA *)data);
+ double adj = round ? 0.99999 : 0.0;
+ int iadj = round ? 1 : 0;
+
+ if (data->rdh.nCount == 1)
+ {
+ RECT nr = box;
+ nr.left = (int)((double)nr.left * sx - iadj);
+ nr.top = (int)((double)nr.top * sy - iadj);
+ nr.right = (int)((double)nr.right * sx + adj);
+ nr.bottom = (int)((double)nr.bottom * sy + adj);
+ setRect(&nr);
+ FREE(data);
+ return ;
+ }
+
+ for (int i = 0;i < (int)data->rdh.nCount;i++)
+ {
+ r[i].left = (int)((double)r[i].left * sx - iadj);
+ r[i].top = (int)((double)r[i].top * sy - iadj);
+ r[i].right = (int)((double)r[i].right * sx + adj);
+ r[i].bottom = (int)((double)r[i].bottom * sy + adj);
+ }
+
+ OSREGIONHANDLE nhrgn = ExtCreateRegion(NULL, size, data);
+ if (!nhrgn)
+ {
+ nhrgn = CreateRectRgn(0, 0, 0, 0);
+ }
+ FREE(data);
+ DeleteObject(hrgn);
+ hrgn = nhrgn;
+ optimize();
+}
+
+void RegionI::debug(int async)
+{
+ if (!async)
+ {
+ SysCanvas c;
+ RECT r;
+ getBox(&r);
+ // c.fillRect(&r, 0);
+ InvertRgn(c.getHDC(), getOSHandle());
+ Sleep(200);
+ InvertRgn(c.getHDC(), getOSHandle());
+ }
+ else
+ {
+ SysCanvas c;
+ RECT r;
+ getBox(&r);
+ // c.fillRect(&r, 0);
+ if (lastdebug)
+ InvertRgn(c.getHDC(), lastdebug->getOSHandle());
+ delete lastdebug;
+ lastdebug = new RegionI();
+ lastdebug->addRegion(this);
+ InvertRgn(c.getHDC(), getOSHandle());
+ }
+}
+
+// later we can cache this data or something if needed
+int RegionI::getNumRects()
+{
+ if (optimized) return 1;
+ int bytes_needed = GetRegionData(hrgn, 0, NULL) + sizeof(RGNDATA);
+ MemBlock<unsigned char> data(bytes_needed);
+ GetRegionData(hrgn, bytes_needed, (LPRGNDATA)data.getMemory());
+ RGNDATA *rgndata = reinterpret_cast<RGNDATA *>(data.getMemory());
+ return rgndata->rdh.nCount;
+}
+
+int RegionI::enumRect(int n, RECT *r)
+{
+ if (optimized)
+ {
+ if (n == 0)
+ {
+ if (r != NULL) *r = optrect;
+ return 1;
+ }
+ return 0;
+ }
+ if (n < 0) return 0;
+ int bytes_needed = GetRegionData(hrgn, 0, NULL) + sizeof(RGNDATA);
+ MemBlock<unsigned char> data(bytes_needed);
+ GetRegionData(hrgn, bytes_needed, (LPRGNDATA)data.getMemory());
+ RGNDATA *rgndata = reinterpret_cast<RGNDATA *>(data.getMemory());
+ int nrects = rgndata->rdh.nCount;
+ if (n >= nrects) return 0;
+ RECT *rectlist = reinterpret_cast<RECT*>(rgndata->Buffer);
+ *r = rectlist[n];
+ return 1;
+}
+
+void RegionI::optimize()
+{
+ if (optimized) return ;
+ if (srv != NULL) return ; // region is cached and shared, do not optimize
+ CHECK_REGION
+ getBox(&optrect);
+
+ if (IsRectEmpty(&optrect))
+ return;
+
+ RECT br;
+ OSREGIONHANDLE gr = CreateRectRgnIndirect(&optrect);
+ OSREGIONHANDLE res = CreateRectRgn(0, 0, 0, 0);
+
+/*
+ // if they don't intersect, we may be offset
+ IntersectRgn(res, gr, hrgn);
+ GetRgnBox(res, &br);
+ if (br.left == br.right || br.bottom == br.top)
+ {
+ DeleteObject(gr);
+ DeleteObject(res);
+ return ;
+ }
+ */
+
+ // if they intersect, but when subtracting the region from the rect, we get nothing, they're the same, let's optimize
+ CombineRgn(res, gr, hrgn, RGN_DIFF);
+ DeleteObject(gr);
+ GetRgnBox(res, &br);
+ DeleteObject(res);
+ if (br.left == br.right || br.bottom == br.top)
+ {
+ optimized = 1;
+ DeleteObject(hrgn);
+ hrgn = NULL;
+ }
+}
+
+void RegionI::deoptimize()
+{
+ if (!optimized) return ;
+ CHECK_REGION
+ SetRectRgn(hrgn, optrect.left, optrect.top, optrect.right, optrect.bottom);
+ //if (hrgn != NULL) { DeleteObject(hrgn); hrgn = NULL; }
+ //hrgn = CreateRectRgnIndirect(&optrect);
+ //CHECK_REGION
+ optimized = 0;
+}
+
+
+#define CBCLASS RegionServerI
+START_DISPATCH;
+VCB(REGIONSERVER_ADDREF, addRef);
+VCB(REGIONSERVER_DELREF, delRef);
+CB(REGIONSERVER_GETREGION, getRegion);
+END_DISPATCH;
+
+#endif//WIN32