delay creation of Windows GDI regions as long as possible, to avoid overruning the GDI limit

svn: r6122
This commit is contained in:
Matthew Flatt 2007-05-03 02:52:40 +00:00
parent ff700eae1b
commit 9ed4e691c8
6 changed files with 398 additions and 39 deletions

View File

@ -3662,7 +3662,7 @@ int wxHiEventTrampoline(int (*_wha_f)(void *), void *wha_data)
if (het->in_progress) {
/* We have leftover work; jump and finish it (non-atomically).
But don't swap until we've juped back in, because the jump-in
But don't swap until we've jumped back in, because the jump-in
point might be trying to suspend the thread (and that should
complete before any swap). */
scheme_end_atomic_no_swap();

View File

@ -53,6 +53,7 @@
#ifdef wx_msw
# include "wx_pdf.h"
extern void wx_release_lazy_regions();
#endif
#include <stdlib.h>
@ -250,6 +251,9 @@ START_XFORM_SKIP;
static void collect_start_callback(void)
{
#ifdef wx_msw
wx_release_lazy_regions();
#endif
draw_gc_bm(1);
orig_collect_start_callback();
}

View File

@ -38,6 +38,8 @@ typedef struct {
typedef int cairo_matrix_p;
#endif
/**************************************************************************/
wxRegion::wxRegion(wxDC *_dc, wxRegion *r, Bool _no_prgn)
{
dc = _dc;
@ -45,7 +47,7 @@ wxRegion::wxRegion(wxDC *_dc, wxRegion *r, Bool _no_prgn)
locked = 0;
#ifdef wx_msw
rgn = NULL;
lazy_rgn = NULL;
#endif
#ifdef wx_x
rgn = NULL;
@ -66,9 +68,10 @@ wxRegion::~wxRegion()
void wxRegion::Cleanup()
{
#ifdef wx_msw
if (rgn) {
DeleteObject(rgn);
rgn = NULL;
if (lazy_rgn) {
if (real_rgn)
lazy_rgn->DoneRgn(real_rgn);
lazy_rgn = NULL;
}
#endif
#ifdef wx_x
@ -88,6 +91,35 @@ void wxRegion::Cleanup()
}
}
void wxRegion::Lock(int delta)
{
#ifdef wx_msw
if (!locked) {
if (lazy_rgn) {
real_rgn = lazy_rgn->GetRgn();
}
}
#endif
locked += delta;
#ifdef wx_msw
if (!locked) {
if (lazy_rgn) {
lazy_rgn->DoneRgn(real_rgn);
real_rgn = NULL;
}
}
#endif
}
#ifdef wx_msw
HRGN wxRegion::GetRgn()
{
return real_rgn;
}
#endif
void wxRegion::SetRectangle(double x, double y, double width, double height)
{
double xw, yh;
@ -120,7 +152,7 @@ void wxRegion::SetRectangle(double x, double y, double width, double height)
ih = ((int)floor(y + height)) - iy;
#ifdef wx_msw
rgn = CreateRectRgn(ix, iy, ix + iw, iy + ih);
lazy_rgn = new RectLazyRgn(ix, iy, iw, ih);
#endif
#ifdef wx_x
{
@ -217,7 +249,7 @@ void wxRegion::SetRoundedRectangle(double x, double y, double width, double heig
}
# ifdef wx_msw
rgn = CreateRoundRectRgn(ix, iy, ix + iw, iy + ih, xradius, yradius);
lazy_rgn = new RoundRectLazyRgn(ix, iy, iw, ih, xradius, yradius);
# endif
# ifdef wx_mac
/* This code uses the current port. We don't know what the current
@ -290,7 +322,7 @@ void wxRegion::SetEllipse(double x, double y, double width, double height)
#endif
#ifdef wx_msw
rgn = CreateEllipticRgn(ix, iy, ix + iw, iy + ih);
lazy_rgn = new EllipticLazyRgn(ix, iy, iw, ih);
#endif
#ifdef wx_mac
/* This code uses the current port. We don't know what the current
@ -375,7 +407,7 @@ void wxRegion::SetPolygon(int n, wxPoint points[], double xoffset, double yoffse
}
#ifdef wx_msw
rgn = CreatePolygonRgn(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? ALTERNATE : WINDING);
lazy_rgn = new PolygonLazyRgn(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? ALTERNATE : WINDING);
#endif
#ifdef wx_x
rgn = XPolygonRegion(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? EvenOddRule : WindingRule);
@ -648,11 +680,13 @@ void wxRegion::Union(wxRegion *r)
}
#ifdef wx_msw
if (!rgn) {
rgn = CreateRectRgn(0, 0, 1, 1);
CombineRgn(rgn, r->rgn, rgn, RGN_COPY);
} else
CombineRgn(rgn, r->rgn, rgn, RGN_OR);
if (!lazy_rgn) {
lazy_rgn = r->lazy_rgn;
} else if (!r->lazy_rgn) {
/* no change */
} else {
lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_OR);
}
#endif
#ifdef wx_x
if (!rgn) {
@ -684,8 +718,13 @@ void wxRegion::Intersect(wxRegion *r)
}
#ifdef wx_msw
if (!rgn) return;
CombineRgn(rgn, r->rgn, rgn, RGN_AND);
if (!lazy_rgn) return;
if (!r->lazy_rgn) {
lazy_rgn = NULL;
return;
}
lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_AND);
#endif
#ifdef wx_x
if (!rgn) return;
@ -716,8 +755,12 @@ void wxRegion::Subtract(wxRegion *r)
}
#ifdef wx_msw
if (!rgn) return;
CombineRgn(rgn, rgn, r->rgn, RGN_DIFF);
if (!lazy_rgn) return;
if (!r->lazy_rgn) {
/* No change */
return;
}
lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_DIFF);
#endif
#ifdef wx_x
if (!rgn) return;
@ -750,8 +793,12 @@ void wxRegion::Xor(wxRegion *r)
}
#ifdef wx_msw
if (!rgn) return;
CombineRgn(rgn, rgn, r->rgn, RGN_XOR);
if (!lazy_rgn) return;
if (!r->lazy_rgn) {
return;
}
lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_XOR);
#endif
#ifdef wx_x
if (!rgn) return;
@ -777,8 +824,21 @@ void wxRegion::BoundingBox(double *x, double *y, double *w, double *h)
double v;
#ifdef wx_msw
RECT r;
HRGN rgn;
GetRgnBox(rgn, &r);
if (real_rgn)
rgn = real_rgn;
else
rgn = lazy_rgn->GetRgn();
if (rgn)
GetRgnBox(rgn, &r);
else {
r.left = r.top = r.right = r.bottom = 0;
}
if (!real_rgn)
lazy_rgn->DoneRgn(rgn);
*x = r.left;
*y = r.top;
@ -826,9 +886,25 @@ Bool wxRegion::Empty()
{
#ifdef wx_msw
RECT r;
if (!rgn) return TRUE;
HRGN rgn;
Bool is_empty;
return (GetRgnBox(rgn, &r) == NULLREGION);
if (!lazy_rgn) return TRUE;
if (real_rgn)
rgn = real_rgn;
else
rgn = lazy_rgn->GetRgn();
if (!rgn)
is_empty = 1;
else
is_empty = (GetRgnBox(rgn, &r) == NULLREGION);
if (!real_rgn)
lazy_rgn->DoneRgn(rgn);
return is_empty;
#endif
#ifdef wx_x
if (!rgn) return TRUE;
@ -849,7 +925,7 @@ Bool wxRegion::IsInRegion(double x, double y)
{
int ix, iy;
if (!rgn) return FALSE;
if (Empty()) return FALSE;
x = dc->FLogicalToUnscrolledDeviceX(x);
y = dc->FLogicalToUnscrolledDeviceY(y);
@ -862,7 +938,25 @@ Bool wxRegion::IsInRegion(double x, double y)
return XPointInRegion(rgn, ix, iy);
#endif
#ifdef wx_msw
return PtInRegion(rgn, ix, iy);
{
HRGN rgn;
Bool in_rgn;
if (real_rgn)
rgn = real_rgn;
else
rgn = lazy_rgn->GetRgn();
if (rgn)
in_rgn = PtInRegion(rgn, ix, iy);
else
in_rgn = 0;
if (!real_rgn)
lazy_rgn->DoneRgn(rgn);
return in_rgn;
}
#endif
#ifdef wx_mac
{

View File

@ -41,12 +41,17 @@ typedef void *XtRegion;
class wxPathRgn;
class wxPath;
#ifdef wx_msw
class LazyRgn;
#endif
class wxRegion : public wxObject
{
public:
#ifdef wx_msw
HRGN rgn;
LazyRgn *lazy_rgn;
HRGN real_rgn;
HRGN GetRgn();
#endif
#ifdef wx_x
XtRegion rgn;
@ -56,12 +61,15 @@ class wxRegion : public wxObject
#endif
wxPathRgn *prgn;
wxDC *dc;
char is_ps, locked, no_prgn;
char is_ps, no_prgn;
int locked;
wxRegion(wxDC *dc, wxRegion *r = NULL, Bool no_prgn = FALSE);
~wxRegion();
inline wxDC *GetDC() { return dc; }
void Lock(int v);
void SetRectangle(double x, double y, double width, double height);
void SetRoundedRectangle(double x, double y, double width, double height, double radius = 20.0);

View File

@ -704,6 +704,253 @@ wxIntPoint::~wxIntPoint (void)
{
}
/**************************************************************************/
#include "../../../wxcommon/FontDirectory.cxx"
/**************************************************************************/
#ifdef wx_msw
class LazyRgn : public wxObject {
public:
int used_refcount;
HRGN cached_rgn, used_rgn;
LazyRgn *lazy_cache_prev, *lazy_cache_next;
LazyRgn();
HRGN GetRgn();
virtual HRGN DetatchRgn(HRGN rgn);
virtual void DoneRgn(HRGN rgn);
virtual HRGN ToRegion();
void Chain();
void Unchain();
};
static LazyRgn *lazy_rgn_cache;
int lazy_cache_count;
#define MAX_CACHE_SIZE 100
LazyRgn::LazyRgn() : wxObject(WXGC_NO_CLEANUP) { }
HRGN LazyRgn::DetatchRgn(HRGN rgn)
{
if (rgn) {
HRGN rgn2;
rgn2 = CreateRectRgn(0, 0, 1, 1);
CombineRgn(rgn2, rgn, rgn2, RGN_COPY);
DoneRgn(rgn);
return rgn2;
} else {
DoneRgn(rgn);
return NULL;
}
}
void LazyRgn::DoneRgn(HRGN rgn)
{
if (rgn && (rgn == used_rgn)) {
--used_refcount;
if (!used_refcount) {
used_rgn = NULL;
if (rgn) {
cached_rgn = rgn;
if (lazy_cache_count >= MAX_CACHE_SIZE) {
LazyRgn *l;
for (l = lazy_rgn_cache; l->lazy_cache_next; l = l->lazy_cache_next) { }
l->Unchain();
DeleteObject(l->cached_rgn);
l->cached_rgn = NULL;
}
Chain();
}
}
} else {
if (rgn)
DeleteObject(rgn);
}
}
HRGN LazyRgn::GetRgn()
{
if (used_rgn) {
} else if (cached_rgn) {
used_rgn = cached_rgn;
Unchain();
cached_rgn = NULL;
} else {
used_rgn = ToRegion();
}
if (used_rgn)
used_refcount++;
return used_rgn;
}
HRGN LazyRgn::ToRegion() { return NULL; }
void LazyRgn::Chain()
{
lazy_cache_next = lazy_rgn_cache;
lazy_cache_prev = NULL;
lazy_rgn_cache = this;
if (lazy_cache_next)
lazy_cache_next->lazy_cache_prev = this;
lazy_cache_count++;
}
void LazyRgn::Unchain()
{
if (lazy_cache_next)
lazy_cache_next->lazy_cache_prev = lazy_cache_prev;
if (lazy_cache_prev)
lazy_cache_prev->lazy_cache_next = lazy_cache_next;
else
lazy_rgn_cache = lazy_cache_next;
--lazy_cache_count;
}
#ifdef MZ_PRECISE_GC
START_XFORM_SKIP;
#endif
void wx_release_lazy_regions(void)
{
LazyRgn *l;
for (l = lazy_rgn_cache; l; l = l->lazy_cache_next) {
DeleteObject(l->cached_rgn);
l->cached_rgn = NULL;
}
lazy_rgn_cache = NULL;
lazy_cache_count = 0;
}
#ifdef MZ_PRECISE_GC
END_XFORM_SKIP;
#endif
/* - - - - - - - - - - - - - - - - - - */
class RectLazyRgn : public LazyRgn {
public:
int ix, iy, iw, ih;
RectLazyRgn(int _ix, int _iy, int _iw, int _ih);
virtual HRGN ToRegion();
};
RectLazyRgn::RectLazyRgn(int _ix, int _iy, int _iw, int _ih) {
ix = _ix;
iy = _iy;
iw = _iw;
ih = _ih;
}
HRGN RectLazyRgn::ToRegion()
{
return CreateRectRgn(ix, iy, ix + iw, iy + ih);
}
/* - - - - - - - - - - - - - - - - - - */
class RoundRectLazyRgn : public LazyRgn {
public:
int ix, iy, iw, ih, xradius, yradius;
RoundRectLazyRgn(int _ix, int _iy, int _iw, int _ih, int _xr, int _yr);
virtual HRGN ToRegion();
};
RoundRectLazyRgn::RoundRectLazyRgn(int _ix, int _iy, int _iw, int _ih, int _xradius, int _yradius) {
ix = _ix;
iy = _iy;
iw = _iw;
ih = _ih;
xradius = _xradius;
yradius = _yradius;
}
HRGN RoundRectLazyRgn::ToRegion()
{
return CreateRoundRectRgn(ix, iy, ix + iw, iy + ih, xradius, yradius);
}
/* - - - - - - - - - - - - - - - - - - */
class EllipticLazyRgn : public LazyRgn {
public:
int ix, iy, iw, ih;
EllipticLazyRgn(int _ix, int _iy, int _iw, int _ih);
virtual HRGN ToRegion();
};
EllipticLazyRgn::EllipticLazyRgn(int _ix, int _iy, int _iw, int _ih) {
ix = _ix;
iy = _iy;
iw = _iw;
ih = _ih;
}
HRGN EllipticLazyRgn::ToRegion()
{
return CreateEllipticRgn(ix, iy, ix + iw, iy + ih);
}
/* - - - - - - - - - - - - - - - - - - */
class PolygonLazyRgn : public LazyRgn {
public:
POINT *cpoints;
int n, mode;
PolygonLazyRgn(POINT *_cpoints, int _n, int _mode);
virtual HRGN ToRegion();
};
PolygonLazyRgn::PolygonLazyRgn(POINT *_cpoints, int _n, int _mode)
{
cpoints = _cpoints;
n = _n;
mode = _mode;
}
HRGN PolygonLazyRgn::ToRegion()
{
return CreatePolygonRgn(cpoints, n, mode);
}
/* - - - - - - - - - - - - - - - - - - */
class UnionLazyRgn : public LazyRgn {
public:
LazyRgn *a, *b;
int mode;
UnionLazyRgn(LazyRgn *_a, LazyRgn *_b, int _mode);
virtual HRGN ToRegion();
};
UnionLazyRgn::UnionLazyRgn(LazyRgn *_a, LazyRgn *_b, int _mode)
{
a = _a;
b = _b;
mode = _mode;
}
HRGN UnionLazyRgn::ToRegion()
{
HRGN ar, br;
ar = a->GetRgn();
br = b->GetRgn();
ar = a->DetatchRgn(ar);
CombineRgn(ar, ar, br, mode);
b->DoneRgn(br);
return ar;
}
#endif
/**************************************************************************/
#include "../../../wxcommon/Region.cxx"

View File

@ -153,7 +153,7 @@ wxDC::~wxDC(void)
if (current_pen) current_pen->Lock(-1);
if (current_brush) current_brush->Lock(-1);
if (clipping) --clipping->locked;
if (clipping) clipping->Lock(-1);
if (filename)
delete[] filename;
@ -417,25 +417,27 @@ void wxDC::SetClippingRegion(wxRegion *c)
if (c && (c->dc != this)) return;
if (clipping)
--clipping->locked;
clipping->Lock(-1);
clipping = c;
if (clipping)
clipping->locked++;
clipping->Lock(1);
dc = ThisDC(FALSE);
if (dc) DoClipping(dc);
DoneDC(dc);
}
static HRGN empty_rgn;
static HRGN empty_rgn, full_rgn;
void wxDC::DoClipping(HDC dc)
{
if (clipping) {
if (clipping->rgn) {
SelectClipRgn(dc, clipping->rgn);
HRGN rgn;
rgn = clipping->GetRgn();
if (rgn) {
SelectClipRgn(dc, rgn);
OffsetClipRgn(dc, canvas_scroll_dx, canvas_scroll_dy);
} else {
if (!empty_rgn)
@ -443,10 +445,9 @@ void wxDC::DoClipping(HDC dc)
SelectClipRgn(dc, empty_rgn);
}
} else {
HRGN rgn;
rgn = CreateRectRgn(0, 0, 32000, 32000);
SelectClipRgn(dc, rgn);
DeleteObject(rgn);
if (!full_rgn)
full_rgn = CreateRectRgn(0, 0, 32000, 32000);
SelectClipRgn(dc, full_rgn);
}
}
@ -1204,8 +1205,13 @@ void wxDC::DrawPath(wxPath *p, double xoffset, double yoffset,int fillStyle)
k += j;
}
if (clipping && clipping->rgn)
CombineRgn(rgn, clipping->rgn, rgn, RGN_AND);
if (clipping) {
HRGN crgn;
crgn = clipping->GetRgn();
if (crgn) {
CombineRgn(rgn, crgn, rgn, RGN_AND);
}
}
SelectClipRgn(dc, rgn);