racket/src/wxcommon/Region.cxx
2007-05-03 06:14:41 +00:00

2704 lines
59 KiB
C++

/********************************************************/
/* Regions */
/********************************************************/
#ifndef wxPI
# define wxPI 3.141592653589793
#endif
#define CAIRO_DEV ((cairo_t *)target)
#ifdef wx_mac
typedef struct {
CGContextRef cg;
CGMutablePathRef path;
} PathTarget;
# define CGPATH ((PathTarget *)target)->path
# define CGCG ((PathTarget *)target)->cg
# define PathTargetPath_t CGMutablePathRef
# define CGXFORM (&current_xform)
# define PATHPATH ((CGMutablePathRef)target)
#endif
#ifdef wx_msw
typedef struct {
Graphics *g;
GraphicsPath *path;
int did_one;
} PathTarget;
# define GP ((PathTarget *)target)->path
# define GP_G ((PathTarget *)target)->g
# define GP_DID_ONE ((PathTarget *)target)->did_one
# define PathTargetPath_t GraphicsPath*
# define CURRENT_GP current_path
# define PATH_GP ((GraphicsPath *)target)
#endif
#ifndef WX_USE_CAIRO
typedef int cairo_matrix_p;
#endif
/**************************************************************************/
wxRegion::wxRegion(wxDC *_dc, wxRegion *r, Bool _no_prgn)
{
dc = _dc;
is_ps = wxSubType(dc->__type, wxTYPE_DC_POSTSCRIPT);
locked = 0;
#ifdef wx_msw
lazy_rgn = NULL;
#endif
#ifdef wx_x
rgn = NULL;
#endif
#ifdef wx_mac
rgn = NULL;
#endif
prgn = NULL;
no_prgn = _no_prgn;
if (r) Union(r);
}
wxRegion::~wxRegion()
{
Cleanup();
}
void wxRegion::Cleanup()
{
#ifdef wx_msw
if (lazy_rgn) {
if (real_rgn)
lazy_rgn->DoneRgn(real_rgn);
lazy_rgn = NULL;
}
#endif
#ifdef wx_x
if (rgn) {
XDestroyRegion(rgn);
rgn = NULL;
}
#endif
#ifdef wx_mac
if (rgn) {
DisposeRgn(rgn);
rgn = NULL;
}
#endif
if (!no_prgn) {
prgn = NULL;
}
}
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;
int ix, iy, iw, ih;
Cleanup();
if (!no_prgn) {
prgn = new WXGC_PTRS wxRectanglePathRgn(dc, x, y, width, height);
}
xw = x + width;
yh = y + height;
x = dc->FLogicalToUnscrolledDeviceX(x);
y = dc->FLogicalToUnscrolledDeviceY(y);
xw = dc->FLogicalToUnscrolledDeviceX(xw);
width = xw - x;
yh = dc->FLogicalToUnscrolledDeviceY(yh);
height = yh - y;
if (is_ps) {
/* So bitmap-based region is right */
height = -height;
y = -y;
}
ix = (int)floor(x);
iy = (int)floor(y);
iw = ((int)floor(x + width)) - ix;
ih = ((int)floor(y + height)) - iy;
#ifdef wx_msw
lazy_rgn = new RectLazyRgn(ix, iy, iw, ih);
#endif
#ifdef wx_x
{
XRectangle r;
rgn = XCreateRegion();
r.x = ix;
r.y = iy;
r.width = iw;
r.height = ih;
XUnionRectWithRegion(&r, rgn, rgn);
}
#endif
#ifdef wx_mac
rgn = NewRgn();
SetRectRgn(rgn, ix, iy, ix + iw, iy + ih);
#endif
}
void wxRegion::SetRoundedRectangle(double x, double y, double width, double height, double radius)
{
#ifdef wx_xt
wxRegion *lt, *rt, *lb, *rb, *w, *h, *r;
#endif
#if defined(wx_msw) || defined(wx_mac)
double xw, yh;
int ix, iy, iw, ih;
int xradius, yradius;
#endif
Cleanup();
if (!no_prgn) {
prgn = new WXGC_PTRS wxRoundedRectanglePathRgn(dc, x, y, width, height, radius);
}
// A negative radius value is interpreted to mean
// 'the proportion of the smallest X or Y dimension'
if (radius < 0.0) {
double smallest = 0.0;
if (width < height)
smallest = width;
else
smallest = height;
radius = (double)(- radius * smallest);
} else
radius = dc->FLogicalToDeviceXRel(radius);
#ifdef wx_x
lt = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
rt = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
lb = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
rb = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
w = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
h = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
lt->SetEllipse(x, y, 2 * radius, 2 * radius);
rt->SetEllipse(x + width - 2 * radius, y, 2 * radius, 2 * radius);
rb->SetEllipse(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius);
lb->SetEllipse(x, y + height - 2 * radius, 2 * radius, 2 * radius);
w->SetRectangle(x, y + radius, width, height - 2 * radius);
h->SetRectangle(x + radius, y, width - 2 * radius, height);
r = lt;
r->Union(rt);
r->Union(lb);
r->Union(rb);
r->Union(w);
r->Union(h);
/* A little hack: steal rgn from r: */
rgn = r->rgn;
r->rgn = NULL;
#else
/* Windows and Mac */
xw = x + width;
yh = y + height;
x = dc->FLogicalToUnscrolledDeviceX(x);
y = dc->FLogicalToUnscrolledDeviceY(y);
width = dc->FLogicalToUnscrolledDeviceX(xw) - x;
height = dc->FLogicalToUnscrolledDeviceY(yh) - y;
xradius = (int)(dc->FLogicalToDeviceXRel(radius));
yradius = (int)(dc->FLogicalToDeviceYRel(radius));
ix = (int)floor(x);
iy = (int)floor(y);
iw = ((int)floor(x + width)) - ix;
ih = ((int)floor(y + height)) - iy;
if (is_ps) {
/* So bitmap-based region is right */
height = -height;
y = -y;
}
# ifdef wx_msw
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
port might be, so we have to pick one to be sure that QuickDraw
is allowed. */
{
CGrafPtr savep;
GDHandle savegd;
::GetGWorld(&savep, &savegd);
::SetGWorld(wxGetGrafPtr(), GetMainDevice());
rgn = NewRgn();
OpenRgn();
{
Rect r2;
SetRect(&r2, ix, iy, ix + iw, iy + ih);
FrameRoundRect(&r2, xradius, yradius);
CloseRgn(rgn);
}
::SetGWorld(savep, savegd);
}
# endif
#endif
}
void wxRegion::SetEllipse(double x, double y, double width, double height)
{
double xw, yh;
#if defined(wx_msw) || defined(wx_mac)
int ix, iy, iw, ih;
#endif
Cleanup();
if (!no_prgn) {
#ifdef WX_USE_CAIRO
/* cairo_arc() went bad for clipping, so we avoid it. */
{
wxPath *p;
p = new WXGC_PTRS wxPath();
p->Arc(x, y, width, height, 0, 2 * wxPI, FALSE);
p->Close();
prgn = new WXGC_PTRS wxPathPathRgn(dc, p, 0, 0, wxWINDING_RULE);
}
#else
prgn = new WXGC_PTRS wxArcPathRgn(dc, x, y, width, height, 0, 2 * wxPI);
#endif
}
xw = x + width;
yh = y + height;
x = dc->FLogicalToUnscrolledDeviceX(x);
y = dc->FLogicalToUnscrolledDeviceY(y);
width = dc->FLogicalToUnscrolledDeviceX(xw) - x;
height = dc->FLogicalToUnscrolledDeviceY(yh) - y;
if (is_ps) {
/* So bitmap-based region is right */
height = -height;
y = -y;
}
#if defined(wx_msw) || defined(wx_mac)
ix = (int)floor(x);
iy = (int)floor(y);
iw = ((int)floor(x + width)) - ix;
ih = ((int)floor(y + height)) - iy;
#endif
#ifdef wx_msw
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
port might be, so we have to pick one to be sure that QuickDraw
is allowed. */
{
CGrafPtr savep;
GDHandle savegd;
::GetGWorld(&savep, &savegd);
::SetGWorld(wxGetGrafPtr(), GetMainDevice());
rgn = NewRgn();
OpenRgn();
{
Rect r;
SetRect(&r, ix, iy, ix + iw, iy + ih);
FrameOval(&r);
CloseRgn(rgn);
}
::SetGWorld(savep, savegd);
}
#endif
#ifdef wx_x
{
int npoints;
XPoint *p;
p = wxEllipseToPolygon(width, height, x, y, &npoints);
rgn = XPolygonRegion(p, npoints - 1, WindingRule);
}
#endif
}
#ifdef wx_x
# define POINT XPoint
#endif
#ifdef wx_mac
# define POINT MyPoint
typedef struct { int x, y; } MyPoint;
#endif
typedef struct { double x, y; } FPoint;
void wxRegion::SetPolygon(int n, wxPoint points[], double xoffset, double yoffset, int fillStyle, int delta)
{
POINT *cpoints;
FPoint *fpoints;
int i, v;
double vf;
Cleanup();
if (n < 2)
return;
if (!no_prgn) {
prgn = new WXGC_PTRS wxPolygonPathRgn(dc, n, points, xoffset, yoffset, fillStyle);
}
cpoints = new WXGC_ATOMIC POINT[n];
fpoints = (is_ps ? new WXGC_ATOMIC FPoint[n] : (FPoint *)NULL);
for (i = 0; i < n; i++) {
v = dc->LogicalToUnscrolledDeviceX(points[i+delta].x + xoffset);
cpoints[i].x = v;
v = dc->LogicalToUnscrolledDeviceY(points[i+delta].y + yoffset);
cpoints[i].y = v;
if (fpoints) {
vf = dc->FLogicalToUnscrolledDeviceX(points[i+delta].x + xoffset);
fpoints[i].x = vf;
vf = dc->FLogicalToUnscrolledDeviceY(points[i+delta].y + yoffset);
fpoints[i].y = vf;
}
}
if (is_ps) {
/* So bitmap-based region is right */
for (i = 0; i < n; i++) {
cpoints[i].y = -cpoints[i].y;
}
}
#ifdef wx_msw
lazy_rgn = new PolygonLazyRgn(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? ALTERNATE : WINDING);
#endif
#ifdef wx_x
rgn = XPolygonRegion(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? EvenOddRule : WindingRule);
#endif
#ifdef wx_mac
/* This code uses the current port. We don't know what the current
port might be, so we have to pick one to be sure that QuickDraw
is allowed. */
{
CGrafPtr savep;
GDHandle savegd;
::GetGWorld(&savep, &savegd);
::SetGWorld(wxGetGrafPtr(), GetMainDevice());
rgn = NewRgn();
OpenRgn();
MoveTo(cpoints[0].x, cpoints[0].y);
for (i = 0; i < n; i++) {
LineTo(cpoints[i].x, cpoints[i].y);
}
LineTo(cpoints[0].x, cpoints[0].y);
CloseRgn(rgn);
::SetGWorld(savep, savegd);
}
#endif
}
void wxRegion::SetPath(wxPath *p, double xoffset, double yoffset, int fillStyle)
{
double **ptss, xs, ys;
int *lens, cnt, i, total_cnt, j, k;
wxPoint *a;
Cleanup();
if (!no_prgn) {
prgn = new WXGC_PTRS wxPathPathRgn(dc, p, xoffset, yoffset, fillStyle);
no_prgn = 1;
}
dc->GetUserScale(&xs, &ys);
cnt = p->ToPolygons(&lens, &ptss, xs, ys);
if (!cnt)
return;
total_cnt = 0;
for (i = 0; i < cnt; i++) {
total_cnt += (lens[i] / 2);
}
#ifdef MZ_PRECISE_GC
a = (wxPoint *)GC_malloc_atomic(sizeof(wxPoint) * total_cnt);
#else
a = new WXGC_ATOMIC wxPoint[total_cnt];
#endif
for (i = 0, k = 0; i < cnt; i++) {
for (j = 0; j < lens[i]; j += 2) {
a[k].x = ptss[i][j] + xoffset;
a[k].y = ptss[i][j+1] + yoffset;
k++;
}
}
if (cnt == 1) {
SetPolygon(total_cnt, a, xoffset, yoffset, fillStyle, 0);
} else {
for (i = 0, k = 0; i < cnt; i++) {
j = (lens[i] / 2);
if (i == 0)
SetPolygon(j, a, xoffset, yoffset, fillStyle, k);
else {
wxRegion *r;
r = new WXGC_PTRS wxRegion(dc, NULL, 1);
r->SetPolygon(j, a, xoffset, yoffset, fillStyle, k);
Xor(r);
DELETE_OBJ r;
}
k += j;
}
}
no_prgn = 0;
}
void wxRegion::SetArc(double x, double y, double w, double h, double start, double end)
{
wxRegion *r;
static double pi;
int saw_start = 0, saw_end = 0, closed = 0;
double cx, cy;
wxPoint *a;
int n;
char save_no_prgn;
#ifdef MZ_PRECISE_GC
a = (wxPoint *)GC_malloc_atomic(sizeof(wxPoint) * 20);
#else
a = new WXGC_ATOMIC wxPoint[20];
#endif
save_no_prgn = no_prgn;
if (!no_prgn) {
#ifdef WX_USE_CAIRO
/* cairo_arc() went bad for clipping, so we avoid it. */
{
wxPath *p;
p = new WXGC_PTRS wxPath();
p->MoveTo(x + w / 2, y + h / 2);
p->Arc(x, y, w, h, end, start, FALSE);
p->Close();
prgn = new WXGC_PTRS wxPathPathRgn(dc, p, 0, 0, wxWINDING_RULE);
}
#else
prgn = new WXGC_PTRS wxArcPathRgn(dc, x, y, w, h, start, end);
#endif
no_prgn = 1;
}
SetEllipse(x, y, w, h);
if (start == end) return;
r = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
if (!pi)
pi = 2 * asin((double)1.0);
start = fmod((double)start, 2*pi);
end = fmod((double)end, 2*pi);
if (start < 0)
start += 2*pi;
if (end < 0)
end += 2*pi;
cx = x + w/2;
cy = y + h/2;
a[0].x = ((w+2) / 2) * cos(end) + cx;
a[0].y = ((h+2) / 2) * (-sin(end)) + cy;
a[1].x = cx;
a[1].y = cy;
a[2].x = ((w+2) / 2) * cos(start) + cx;
a[2].y = ((h+2) / 2) * (-sin(start)) + cy;
n = 3;
if (!saw_start && (start < (pi / 2)))
saw_start = 1;
if (!saw_end && (end > start) && (end < (pi / 2)))
saw_end = 1;
if (saw_start && !closed) {
a[n].x = x + w + 2;
a[n++].y = y - 2;
}
if (saw_start && !saw_end) {
a[n].x = cx;
a[n++].y = y - 2;
} else
closed = saw_start;
if (!saw_start && (start < pi))
saw_start = 1;
if (!saw_end && (end > start) && (end < pi))
saw_end = 1;
if (saw_start && !closed) {
a[n].x = x - 2;
a[n++].y = y - 2;
}
if (saw_start && !saw_end) {
a[n].x = x - 2;
a[n++].y = cy;
} else
closed = saw_start;
if (!saw_start && (start < (1.5 * pi)))
saw_start = 1;
if (!saw_end && (end > start) && (end < (1.5 * pi)))
saw_end = 1;
if (saw_start && !closed) {
a[n].x = x - 2;
a[n++].y = y + h + 2;
}
if (saw_start && !saw_end) {
a[n].x = cx;
a[n++].y = y + h + 2;
} else
closed = saw_start;
saw_start = 1;
saw_end = (end > start);
if (saw_start && !closed) {
a[n].x = x + w + 2;
a[n++].y = y + h + 2;
}
if (saw_start && !saw_end) {
a[n].x = x + w + 2;
a[n++].y = cy;
} else
closed = saw_start;
if (!saw_end && (end < (pi / 2)))
saw_end = 1;
if (saw_start && !closed) {
a[n].x = x + w + 2;
a[n++].y = y - 2;
}
if (saw_start && !saw_end) {
a[n].x = cx;
a[n++].y = y - 2;
} else
closed = saw_start;
if (!saw_end && (end < pi))
saw_end = 1;
if (saw_start && !closed) {
a[n].x = x - 2;
a[n++].y = y - 2;
}
if (saw_start && !saw_end) {
a[n].x = x - 2;
a[n++].y = cy;
} else
closed = saw_start;
if (!saw_end && (end < (1.5 * pi)))
saw_end = 1;
if (saw_start && !closed) {
a[n].x = x - 2;
a[n++].y = y + h + 2;
}
if (saw_start && !saw_end) {
a[n].x = cx;
a[n++].y = y + h + 2;
} else
closed = saw_start;
if (!closed) {
a[n].x = x + w + 2;
a[n++].y = y + h + 2;
}
r->SetPolygon(n, a);
Intersect(r);
no_prgn = save_no_prgn;
}
void wxRegion::Union(wxRegion *r)
{
if (r->dc != dc) return;
if (r->ReallyEmpty()) return;
if (!no_prgn) {
if (!r->prgn) abort();
if (!prgn)
prgn = r->prgn;
else {
wxPathRgn *pr;
pr = new WXGC_PTRS wxUnionPathRgn(prgn, r->prgn);
prgn = pr;
}
}
#ifdef wx_msw
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) {
rgn = XCreateRegion();
}
XUnionRegion(rgn, r->rgn, rgn);
#endif
#ifdef wx_mac
if (!rgn) {
rgn = NewRgn();
}
UnionRgn(rgn, r->rgn, rgn);
#endif
}
void wxRegion::Intersect(wxRegion *r)
{
if (r->dc != dc) return;
if (ReallyEmpty())
return;
if (r->ReallyEmpty()) {
Cleanup();
return;
}
if (!no_prgn) {
wxPathRgn *rprgn, *pr;
rprgn = r->prgn;
if (!rprgn) abort();
if (prgn->is_rect
&& rprgn->is_rect
&& (prgn->ox == rprgn->ox)
&& (prgn->oy == rprgn->oy)
&& (prgn->sx == rprgn->sx)
&& (prgn->sy == rprgn->sy)) {
/* Special case: both are rectangles with the same
origin and scale. This is a common case, and it
can be a lot faster making a rectangle directly. */
wxRectanglePathRgn *r1 = (wxRectanglePathRgn *)prgn;
wxRectanglePathRgn *r2 = (wxRectanglePathRgn *)rprgn;
double px, py, pw, ph;
if (r1->x < r2->x)
px = r2->x;
else
px = r1->x;
if (r1->y < r2->y)
py = r2->y;
else
py = r1->y;
if (r1->x + r1->width < r2->x + r2->width)
pw = (r1->x + r1->width) - px;
else
pw = (r2->x + r2->width) - px;
if (r1->y + r1->height < r2->y + r2->height)
ph = (r1->y + r1->height) - py;
else
ph = (r2->y + r2->height) - py;
if ((pw > 0) && (ph > 0))
pr = new WXGC_PTRS wxRectanglePathRgn(dc, px, py, pw, ph);
else {
/* empty */
Cleanup();
return;
}
} else {
pr = new WXGC_PTRS wxIntersectPathRgn(prgn, r->prgn);
}
prgn = pr;
}
#ifdef wx_msw
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;
XIntersectRegion(rgn, r->rgn, rgn);
#endif
#ifdef wx_mac
if (!rgn) return;
SectRgn(rgn, r->rgn, rgn);
#endif
if (ReallyEmpty()) {
Cleanup();
}
}
void wxRegion::Subtract(wxRegion *r)
{
if (r->dc != dc) return;
if (r->ReallyEmpty()) return;
if (!no_prgn) {
/* wxDiffPathRgn is only half a subtract; the result must be intersected with the first part */
wxPathRgn *pr;
if (!r->prgn) abort();
pr = new WXGC_PTRS wxDiffPathRgn(prgn, r->prgn);
pr = new WXGC_PTRS wxIntersectPathRgn(prgn, pr);
prgn = pr;
}
#ifdef wx_msw
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;
XSubtractRegion(rgn, r->rgn, rgn);
#endif
#ifdef wx_mac
if (!rgn) return;
DiffRgn(rgn, r->rgn, rgn);
#endif
if (ReallyEmpty()) {
Cleanup();
return;
}
}
void wxRegion::Xor(wxRegion *r)
{
if (r->dc != dc) return;
if (r->ReallyEmpty()) return;
if (!no_prgn) {
wxPathRgn *pr;
if (!r->prgn) abort();
if (!prgn)
pr = r->prgn;
else
pr = new WXGC_PTRS wxDiffPathRgn(prgn, r->prgn);
prgn = pr;
}
#ifdef wx_msw
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;
XXorRegion(rgn, r->rgn, rgn);
#endif
#ifdef wx_mac
if (!rgn) return;
XorRgn(rgn, r->rgn, rgn);
#endif
if (ReallyEmpty()) {
Cleanup();
return;
}
}
void wxRegion::BoundingBox(double *x, double *y, double *w, double *h)
{
if (Empty()) {
*x = *y = *w = *h = 0;
return;
} else {
double v;
#ifdef wx_msw
RECT r;
HRGN rgn;
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;
*w = r.right - r.left;
*h = r.bottom - r.top;
#endif
#ifdef wx_x
XRectangle r;
XClipBox(rgn, &r);
*x = r.x;
*y = r.y;
*w = r.width;
*h = r.height;
#endif
#ifdef wx_mac
{
Rect r;
GetRegionBounds(rgn,&r);
*x = r.left;
*y = r.top;
*w = r.right - *x;
*h = r.bottom - *y;
}
#endif
if (is_ps) {
/* Bitmap-based region is stored upside-down */
*y = -(*y);
}
v = dc->UnscrolledDeviceToLogicalX((int)*x);
*x = v;
v = dc->UnscrolledDeviceToLogicalY((int)*y);
*y = v;
v = dc->DeviceToLogicalXRel((int)*w);
*w = v;
v = dc->DeviceToLogicalYRel((int)*h);
*h = v;
}
}
Bool wxRegion::Empty()
{
#ifdef wx_msw
RECT r;
HRGN rgn;
Bool is_empty;
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;
return XEmptyRegion(rgn);
#endif
#ifdef wx_mac
if (!rgn) return TRUE;
return EmptyRgn(rgn);
#endif
}
Bool wxRegion::ReallyEmpty()
{
return Empty() && !prgn;
}
Bool wxRegion::IsInRegion(double x, double y)
{
int ix, iy;
if (Empty()) return FALSE;
x = dc->FLogicalToUnscrolledDeviceX(x);
y = dc->FLogicalToUnscrolledDeviceY(y);
ix = (int)floor(x);
iy = (int)floor(y);
#ifdef wx_xt
return XPointInRegion(rgn, ix, iy);
#endif
#ifdef wx_msw
{
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
{
Point p;
p.h = ix;
p.v = iy;
return PtInRgn(p, rgn);
}
#endif
}
void wxRegion::Install(long target, Bool align)
{
if (prgn) {
Bool oe;
#ifdef WX_USE_CAIRO
cairo_new_path(CAIRO_DEV);
#endif
#ifdef wx_mac
CGContextRef cg = (CGContextRef)target;
PathTarget *t;
CGMutablePathRef path;
path = CGPathCreateMutable();
t = (PathTarget *)malloc(sizeof(PathTarget));
t->path = path;
t->cg = cg;
target = (long)t;
#endif
#ifdef wx_msw
Graphics *g = (Graphics *)target;
GraphicsPath *gp;
PathTarget *t;
gp = wxGPathNew(FillModeAlternate);
t = (PathTarget *)malloc(sizeof(PathTarget));
t->path = gp;
t->g = g;
t->did_one = 0;
target = (long)t;
#endif
oe = prgn->Install(target, 0, align);
#ifdef WX_USE_CAIRO
if (oe)
cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_EVEN_ODD);
cairo_clip(CAIRO_DEV);
if (oe)
cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_WINDING);
cairo_new_path(CAIRO_DEV);
#endif
#ifdef wx_mac
CGContextBeginPath(cg);
CGContextAddPath(cg, t->path);
if (oe)
CGContextEOClip(cg);
else
CGContextClip(cg);
CGPathRelease(t->path);
free(t);
#endif
#ifdef wx_msw
wxGSetClip(g, t->path, t->did_one ? CombineModeIntersect : CombineModeReplace);
wxGPathRelease(t->path);
free(t);
#endif
} else {
/* Empty region: */
#ifdef WX_USE_CAIRO
cairo_new_path(CAIRO_DEV);
/* Empty path confuses some versions of Cairo, so
clip to two non-overlapping regions */
cairo_move_to(CAIRO_DEV, 0, 0);
cairo_line_to(CAIRO_DEV, 1, 0);
cairo_line_to(CAIRO_DEV, 1, 1);
cairo_clip(CAIRO_DEV);
cairo_new_path(CAIRO_DEV);
cairo_move_to(CAIRO_DEV, 2, 2);
cairo_line_to(CAIRO_DEV, 3, 2);
cairo_line_to(CAIRO_DEV, 3, 3);
cairo_clip(CAIRO_DEV);
#endif
#ifdef wx_mac
{
CGContextRef cg = (CGContextRef)target;
CGRect r;
r.origin.x = 0;
r.origin.y = 0;
r.size.width = 0;
r.size.height = 0;
CGContextClipToRect(cg, r);
}
#endif
#ifdef wx_msw
{
GraphicsPath *gp;
Graphics *g = (Graphics *)target;
gp = wxGPathNew(FillModeAlternate);
wxGSetClip(g, gp, CombineModeReplace);
wxGPathRelease(gp);
}
#endif
}
}
void wxRegion::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
Bool oe;
s->Out("newpath\n");
oe = prgn->InstallPS(dc, s);
if (oe)
s->Out("eoclip\n");
else
s->Out("clip\n");
}
/***************************************************************************************/
#ifdef wx_mac
static CGAffineTransform current_xform;
#endif
#ifdef wx_msw
static GraphicsPath *current_path;
#endif
wxPathRgn::wxPathRgn(wxDC *dc)
: wxObject(FALSE)
{
if (dc) {
double x, y, xs, ys;
dc->GetDeviceOrigin(&x, &y);
dc->GetUserScale(&xs, &ys);
ox = x;
oy = y;
sx = xs;
sy = ys;
} else {
ox = oy = 0.0;
sx = sy = 1.0;
}
is_rect = 0;
}
wxPathRgn::~wxPathRgn()
{
/* If anything important is added here, change constructor chaining
to wxObject from FALSE to TRUE. Beware that wxPaths can share
wxPathRgns. */
}
double wxPathRgn::XFormX(double _x, Bool align)
{
if (align)
return floor((_x * sx) + ox) + 0.5;
else
return _x;
}
double wxPathRgn::XFormY(double _y, Bool align)
{
if (align)
return floor((_y * sy) + oy) + 0.5;
else
return _y;
}
double wxPathRgn::XFormXB(double _x, Bool align)
{
if (align)
return floor((_x * sx) + ox);
else
return _x;
}
double wxPathRgn::XFormYB(double _y, Bool align)
{
if (align)
return floor((_y * sy) + oy);
else
return _y;
}
double wxPathRgn::XFormW(double _w, double _x, Bool align)
{
if (align)
return floor(((_x + _w) * sx) + ox) - floor((_x * sx) + ox);
else
return _w;
}
double wxPathRgn::XFormH(double _h, double _y, Bool align)
{
if (align)
return floor(((_y + _h) * sy) + oy) - floor((_y * sy) + oy);
else
return _h;
}
void wxPathRgn::PrepareScale(long target, Bool oe, Bool align, void *_m)
{
#ifdef wx_xt
# ifdef WX_USE_CAIRO
if (!align) {
cairo_matrix_p *m = (cairo_matrix_p *)_m;
cairo_set_matrix_create(*m);
cairo_current_matrix(CAIRO_DEV, *m);
cairo_default_matrix(CAIRO_DEV);
cairo_translate(CAIRO_DEV, ox, oy);
cairo_scale(CAIRO_DEV, sx, sy);
}
# endif
#endif
#ifdef wx_mac
if (align) {
current_xform = CGAffineTransformMakeTranslation(0, 0);
} else {
current_xform = CGAffineTransformMakeTranslation(ox, oy);
current_xform = CGAffineTransformScale(current_xform, sx, sy);
}
#endif
#ifdef wx_msw
current_path = wxGPathNew(oe ? FillModeAlternate : FillModeWinding);
#endif
}
void wxPathRgn::RestoreScale(long target, Bool align, void *_m)
{
#ifdef WX_USE_CAIRO
if (!align) {
cairo_matrix_p *m = (cairo_matrix_p *)_m;
cairo__set_matrix(CAIRO_DEV, *m);
cairo_matrix_destroy(*m);
}
#endif
#ifdef wx_mac
#endif
#ifdef wx_msw
if (!align) {
Matrix *m;
m = wxGMatrixNew();
wxGMatrixTranslate(m, ox, oy);
wxGMatrixScale(m, sx, sy);
wxGPathTransform(current_path, m);
wxGMatrixRelease(m);
}
wxGPathAddPath(GP, current_path, TRUE);
wxGPathRelease(current_path);
#endif
}
wxRectanglePathRgn::wxRectanglePathRgn(wxDC *dc_for_scale, double _x, double _y, double _width, double _height)
: wxPathRgn(dc_for_scale)
{
x = _x;
y = _y;
width = _width;
height = _height;
is_rect = 1;
}
Bool wxRectanglePathRgn::Install(long target, Bool reverse, Bool align)
{
double xx, yy, ww, hh;
cairo_matrix_p m;
PrepareScale(target, TRUE, align, &m);
xx = XFormXB(x, align);
yy = XFormYB(y, align);
ww = XFormW(width, x, align);
hh = XFormH(height, y, align);
#ifdef WX_USE_CAIRO
cairo_move_to(CAIRO_DEV, xx, yy);
if (reverse) {
cairo_rel_line_to(CAIRO_DEV, 0, hh);
cairo_rel_line_to(CAIRO_DEV, ww, 0);
cairo_rel_line_to(CAIRO_DEV, 0, -hh);
} else {
cairo_rel_line_to(CAIRO_DEV, ww, 0);
cairo_rel_line_to(CAIRO_DEV, 0, hh);
cairo_rel_line_to(CAIRO_DEV, -ww, 0);
}
cairo_close_path(CAIRO_DEV);
#endif
#ifdef wx_mac
CGPathMoveToPoint(CGPATH, CGXFORM, xx, yy);
if (reverse) {
CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + hh);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + hh);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy);
} else {
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + hh);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + hh);
}
CGPathCloseSubpath(CGPATH);
#endif
#ifdef wx_msw
if (reverse) {
wxGPathAddLine(CURRENT_GP, xx, yy, xx, yy + hh);
wxGPathAddLine(CURRENT_GP, xx, yy + hh, xx + ww, yy + hh);
wxGPathAddLine(CURRENT_GP, xx + ww, yy + hh, xx + ww, yy);
} else {
wxGPathAddLine(CURRENT_GP, xx, yy, xx + ww, yy);
wxGPathAddLine(CURRENT_GP, xx + ww, yy, xx + ww, yy + hh);
wxGPathAddLine(CURRENT_GP, xx + ww, yy + hh, xx, yy + hh);
}
wxGPathCloseFigure(CURRENT_GP);
#endif
RestoreScale(target, align, &m);
return FALSE;
}
Bool wxRectanglePathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
double xx, yy, ww, hh;
xx = dc->FsLogicalToDeviceX(x, ox, sx);
yy = dc->FsLogicalToDeviceY(y, oy, sy);
ww = dc->FsLogicalToDeviceXRel(width, ox, sx);
hh = dc->FsLogicalToDeviceYRel(height, oy, sy);
s->Out(xx); s->Out(" "); s->Out(yy); s->Out(" moveto\n");
s->Out(xx + ww); s->Out(" "); s->Out(yy); s->Out(" lineto\n");
s->Out(xx + ww); s->Out(" "); s->Out(yy - hh); s->Out(" lineto\n");
s->Out(xx); s->Out(" "); s->Out(yy - hh); s->Out(" lineto\n");
s->Out("closepath\n");
return FALSE;
}
wxRoundedRectanglePathRgn::wxRoundedRectanglePathRgn(wxDC *dc_for_scale,
double _x, double _y, double _width, double _height, double _radius)
: wxPathRgn(dc_for_scale)
{
x = _x;
y = _y;
width = _width;
height = _height;
radius = _radius;
if (radius < 0) {
radius = -radius;
if (width > height)
radius = radius * height;
else
radius = radius * width;
}
}
Bool wxRoundedRectanglePathRgn::Install(long target, Bool reverse, Bool align)
{
double xx, yy, ww, hh, rr, rr2;
cairo_matrix_p m;
PrepareScale(target, TRUE, align, &m);
xx = XFormXB(x, align);
yy = XFormYB(y, align);
ww = XFormW(width, x, align);
hh = XFormH(height, y, align);
rr = XFormW(radius, 0, align);
rr2 = XFormH(radius, 0, align);
if (rr2 < rr)
rr = rr2;
#ifdef WX_USE_CAIRO
{
if (reverse) {
cairo_move_to(CAIRO_DEV, xx, yy + rr);
cairo_line_to(CAIRO_DEV, xx, yy + hh - rr);
cairo_arc_negative(CAIRO_DEV, xx + rr, yy + hh - rr, rr, wxPI, 0.5 * wxPI);
cairo_line_to(CAIRO_DEV, xx + ww - rr, yy + hh);
cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + hh - rr, rr, 0.5 * wxPI, 0);
cairo_line_to(CAIRO_DEV, xx + ww, yy + rr);
cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + rr, rr, 2 * wxPI, 1.5 * wxPI);
cairo_line_to(CAIRO_DEV, xx + rr, yy);
cairo_arc_negative(CAIRO_DEV, xx + rr, yy + rr, rr, 1.5 * wxPI, wxPI);
cairo_line_to(CAIRO_DEV, xx, yy + rr);
} else {
cairo_move_to(CAIRO_DEV, xx, yy + rr);
cairo_arc(CAIRO_DEV, xx + rr, yy + rr, rr, wxPI, 1.5 * wxPI);
cairo_line_to(CAIRO_DEV, xx + ww - rr, yy);
cairo_arc(CAIRO_DEV, xx + ww - rr, yy + rr, rr, 1.5 * wxPI, 2 * wxPI);
cairo_line_to(CAIRO_DEV, xx + ww, yy + hh - rr);
cairo_arc(CAIRO_DEV, xx + ww - rr, yy + hh - rr, rr, 0, 0.5 * wxPI);
cairo_line_to(CAIRO_DEV, xx + rr, yy + hh);
cairo_arc(CAIRO_DEV, xx + rr, yy + hh - rr, rr, 0.5 * wxPI, wxPI);
cairo_line_to(CAIRO_DEV, xx, yy + rr);
}
cairo_close_path(CAIRO_DEV);
}
#endif
#ifdef wx_mac
if (reverse) {
CGPathMoveToPoint(CGPATH, CGXFORM, xx + rr, yy);
CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + rr, rr, 1.5 * wxPI, 1.0 * wxPI, TRUE);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + hh - rr);
CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + hh - rr, rr, 1.0 * wxPI, 0.5 * wxPI, TRUE);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww - rr, yy + hh);
CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + hh - rr, rr, 0.5 * wxPI, 0, TRUE);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + rr);
CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + rr, rr, 2 * wxPI, 1.5 * wxPI, TRUE);
} else {
CGPathMoveToPoint(CGPATH, CGXFORM, xx + rr, yy);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww - rr, yy);
CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + rr, rr, 1.5 * wxPI, 2 * wxPI, FALSE);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + hh - rr);
CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + hh - rr, rr, 0, 0.5 * wxPI, FALSE);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx + rr, yy + hh);
CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + hh - rr, rr, 0.5 * wxPI, 1.0 * wxPI, FALSE);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + rr);
CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + rr, rr, 1.0 * wxPI, 1.5 * wxPI, FALSE);
}
CGPathCloseSubpath(CGPATH);
#endif
#ifdef wx_msw
if (reverse) {
wxGPathAddArc(CURRENT_GP, xx, yy, rr * 2, rr * 2, 270, -90);
wxGPathAddLine(CURRENT_GP, xx, yy + rr, xx, yy + hh - rr);
wxGPathAddArc(CURRENT_GP, xx, yy + hh - 2 * rr, 2 * rr, 2 * rr, 180, -90);
wxGPathAddLine(CURRENT_GP, xx + rr, yy + hh, xx + ww - rr, yy + hh);
wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy + hh - 2 * rr, 2 * rr, 2 * rr, 90, -90);
wxGPathAddLine(CURRENT_GP, xx + ww, yy + hh - rr, xx + ww, yy + rr);
wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy, rr * 2, rr * 2, 360, -90);
} else {
wxGPathAddArc(CURRENT_GP, xx, yy, rr * 2, rr * 2, 180, 90);
wxGPathAddLine(CURRENT_GP, xx + rr, yy, xx + ww - rr, yy);
wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy, rr * 2, rr * 2, 270, 90);
wxGPathAddLine(CURRENT_GP, xx + ww, yy + rr, xx + ww, yy + hh - rr);
wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy + hh - 2 * rr, 2 * rr, 2 * rr, 0, 90);
wxGPathAddLine(CURRENT_GP, xx + ww - rr, yy + hh, xx + rr, yy + hh);
wxGPathAddArc(CURRENT_GP, xx, yy + hh - 2 * rr, 2 * rr, 2 * rr, 90, 90);
}
wxGPathCloseFigure(CURRENT_GP);
#endif
RestoreScale(target, align, &m);
return FALSE;
}
Bool wxRoundedRectanglePathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
double xx, yy, ww, hh, rr;
xx = dc->FsLogicalToDeviceX(x, ox, sx);
yy = dc->FsLogicalToDeviceY(y, oy, sy);
ww = dc->FsLogicalToDeviceXRel(width, ox, sx);
hh = dc->FsLogicalToDeviceYRel(height, oy, sy);
if (sx > sy)
rr = dc->FsLogicalToDeviceYRel(radius, oy, sy);
else
rr = dc->FsLogicalToDeviceXRel(radius, ox, sx);
hh = -hh;
s->Out(xx + rr); s->Out(" ");
s->Out(yy); s->Out(" moveto\n");
s->Out(xx + rr); s->Out(" ");
s->Out(yy - rr); s->Out(" ");
s->Out(rr); s->Out(" 90 180 arc\n");
s->Out(xx + rr); s->Out(" ");
s->Out(yy + hh + rr); s->Out(" ");
s->Out(rr); s->Out(" 180 270 arc\n");
s->Out(xx + ww - rr); s->Out(" ");
s->Out(yy + hh + rr); s->Out(" ");
s->Out(rr); s->Out(" 270 0 arc\n");
s->Out(xx + ww - rr); s->Out(" ");
s->Out(yy - rr); s->Out(" ");
s->Out(rr); s->Out(" 0 90 arc\n");
s->Out("closepath\n");
return FALSE;
}
wxPolygonPathRgn::wxPolygonPathRgn(wxDC *dc_for_scale,
int _n, wxPoint _points[], double _xoffset, double _yoffset, int _fillStyle)
: wxPathRgn(dc_for_scale)
{
n = _n;
points = _points;
xoffset = _xoffset;
yoffset = _yoffset;
fillStyle = _fillStyle;
}
Bool wxPolygonPathRgn::Install(long target, Bool reverse, Bool align)
{
#if defined(WX_USE_CAIRO) || defined(wx_msw) || defined(wx_mac)
double xx, yy;
#endif
cairo_matrix_p m;
PrepareScale(target, fillStyle == wxODDEVEN_RULE, align, &m);
#ifdef WX_USE_CAIRO
if (reverse) {
int i;
xx = XFormX(points[n-1].x + xoffset, align);
yy = XFormY(points[n-1].y + yoffset, align);
cairo_move_to(CAIRO_DEV, xx, yy);
for (i = n-1; i--; ) {
xx = XFormX(points[i].x + xoffset, align);
yy = XFormY(points[i].y + yoffset, align);
cairo_line_to(CAIRO_DEV, xx, yy);
}
} else {
int i;
xx = XFormX(points[0].x + xoffset, align);
yy = XFormY(points[0].y + yoffset, align);
cairo_move_to(CAIRO_DEV, xx, yy);
for (i = 1; i < n; i++) {
xx = XFormX(points[i].x + xoffset, align);
yy = XFormY(points[i].y + yoffset, align);
cairo_line_to(CAIRO_DEV, xx, yy);
}
}
cairo_close_path(CAIRO_DEV);
#endif
#ifdef wx_mac
if (reverse) {
int i;
xx = XFormX(points[n-1].x + xoffset, align);
yy = XFormY(points[n-1].y + yoffset, align);
CGPathMoveToPoint(CGPATH, CGXFORM, xx, yy);
for (i = n-1; i--; ) {
xx = XFormX(points[i].x + xoffset, align);
yy = XFormY(points[i].y + yoffset, align);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy);
}
} else {
int i;
xx = XFormX(points[0].x + xoffset, align);
yy = XFormY(points[0].y + yoffset, align);
CGPathMoveToPoint(CGPATH, CGXFORM, xx, yy);
for (i = 1; i < n; i++) {
xx = XFormX(points[i].x + xoffset, align);
yy = XFormY(points[i].y + yoffset, align);
CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy);
}
}
CGPathCloseSubpath(CGPATH);
#endif
#ifdef wx_msw
if (reverse) {
int i;
double xx2, yy2;
for (i = n - 1; i--; ) {
xx = XFormX(points[i+1].x + xoffset, align);
yy = XFormY(points[i+1].y + yoffset, align);
xx2 = XFormX(points[i].x + xoffset, align);
yy2 = XFormY(points[i].y + yoffset, align);
wxGPathAddLine(CURRENT_GP, xx, yy, xx2, yy2);
}
} else {
int i;
double xx2, yy2;
for (i = 0; i < n - 1; i++) {
xx = XFormX(points[i].x + xoffset, align);
yy = XFormY(points[i].y + yoffset, align);
xx2 = XFormX(points[i+1].x + xoffset, align);
yy2 = XFormY(points[i+1].y + yoffset, align);
wxGPathAddLine(CURRENT_GP, xx, yy, xx2, yy2);
}
}
wxGPathCloseFigure(CURRENT_GP);
#endif
RestoreScale(target, align, &m);
return (fillStyle == wxODDEVEN_RULE);
}
Bool wxPolygonPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
double xx, yy;
int i;
xx = dc->FsLogicalToDeviceX(points[0].x + xoffset, ox, sx);
yy = dc->FsLogicalToDeviceY(points[0].y + yoffset, oy, sy);
s->Out(xx); s->Out(" ");
s->Out(yy); s->Out(" moveto\n");
for (i = 1; i < n; i++) {
xx = dc->FsLogicalToDeviceX(points[i].x + xoffset, ox, sx);
yy = dc->FsLogicalToDeviceY(points[i].y + yoffset, oy, sy);
s->Out(xx); s->Out(" ");
s->Out(yy); s->Out(" lineto\n");
}
s->Out("closepath\n");
return (fillStyle == wxODDEVEN_RULE);
}
wxPathPathRgn::wxPathPathRgn(wxDC *dc_for_scale,
wxPath *_p, double _xoffset, double _yoffset, int _fillStyle)
: wxPathRgn(dc_for_scale)
{
p = new WXGC_PTRS wxPath();
p->AddPath(_p);
p->Translate(_xoffset, _yoffset);
fillStyle = _fillStyle;
}
Bool wxPathPathRgn::Install(long target, Bool reverse, Bool align)
{
wxPath *q;
cairo_matrix_p m;
PrepareScale(target, fillStyle == wxODDEVEN_RULE, align, &m);
if (reverse) {
q = new WXGC_PTRS wxPath();
q->AddPath(p);
q->Reverse();
} else
q = p;
if (align) {
#ifdef WX_USE_CAIRO
q->Install(target, 0, 0, ox, oy, sx, sy, TRUE, 0.5, 0.5);
#endif
#ifdef wx_mac
q->Install((long)CGPATH, 0, 0, ox, oy, sx, sy, TRUE, 0.5, 0.5);
#endif
#ifdef wx_msw
q->Install((long)CURRENT_GP, 0, 0, ox, oy, sx, sy, TRUE, 0, 0);
#endif
} else {
#ifdef WX_USE_CAIRO
q->Install(target, 0, 0, 0, 0, 1, 1, FALSE, 0, 0);
#endif
#ifdef wx_mac
q->Install((long)CGPATH, 0, 0, 0, 0, 1, 1, FALSE, 0, 0);
#endif
#ifdef wx_msw
q->Install((long)CURRENT_GP, 0, 0, 0, 0, 1, 1, FALSE, 0, 0);
#endif
}
RestoreScale(target, align, &m);
return (fillStyle == wxODDEVEN_RULE);
}
Bool wxPathPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
p->InstallPS(dc, s, 0, 0);
return (fillStyle == wxODDEVEN_RULE);
}
wxArcPathRgn::wxArcPathRgn(wxDC *dc_for_scale,
double _x, double _y, double _w, double _h, double _start, double _end)
: wxPathRgn(dc_for_scale)
{
x = _x;
y = _y;
w = _w;
h = _h;
start = _start;
end = _end;
}
Bool wxArcPathRgn::Install(long target, Bool reverse, Bool align)
{
double xx, yy, ww, hh;
cairo_matrix_p m;
PrepareScale(target, TRUE, align, &m);
xx = XFormXB(x, align);
yy = XFormYB(y, align);
ww = XFormW(w, x, align);
hh = XFormH(h, y, align);
#ifdef WX_USE_CAIRO
{
cairo_translate(CAIRO_DEV, xx, yy);
cairo_scale(CAIRO_DEV, ww, hh);
if ((start != 0.0) || (end != (2 * wxPI)))
cairo_move_to(CAIRO_DEV, 0.5, 0.5);
if (!reverse)
cairo_arc(CAIRO_DEV, 0.5, 0.5, 0.5, -end, -start);
else
cairo_arc_negative(CAIRO_DEV, 0.5, 0.5, 0.5, -start, -end);
cairo_close_path(CAIRO_DEV);
}
#endif
#ifdef wx_mac
{
CGAffineTransform xform;
xform = CGAffineTransformTranslate(*CGXFORM, xx, yy);
xform = CGAffineTransformScale(xform, ww, hh);
if ((start != 0.0) || (end != (2 * wxPI)))
CGPathMoveToPoint(CGPATH, &xform, 0.5, 0.5);
if (!reverse)
CGPathAddArc(CGPATH, &xform, 0.5, 0.5, 0.5, (2 * wxPI) - end, (2 * wxPI) - start, FALSE);
else
CGPathAddArc(CGPATH, &xform, 0.5, 0.5, 0.5, (2 * wxPI) - start, (2 * wxPI) - end, TRUE);
CGPathCloseSubpath(CGPATH);
}
#endif
#ifdef wx_msw
{
double init, span;
if ((start == 0.0) && (end == 2 * wxPI)) {
if (reverse) {
wxGPathAddArc(CURRENT_GP, xx, yy, ww, hh, 360.0, -360.0);
} else {
wxGPathAddArc(CURRENT_GP, xx, yy, ww, hh, 0.0, 360.0);
}
} else {
init = (2 * wxPI - start) * 180 / wxPI;
init = fmod(init, 360.0);
if (init < 0.0)
init += 360.0;
span = (start - end) * 180 / wxPI;
span = fmod(span, 360.0);
if (span > 0)
span -= 360.0;
if (reverse) {
wxGPathAddPie(CURRENT_GP, xx, yy, ww, hh, init + span, -span);
} else {
wxGPathAddPie(CURRENT_GP, xx, yy, ww, hh, init, span);
}
}
wxGPathCloseFigure(CURRENT_GP);
}
#endif
RestoreScale(target, align, &m);
return FALSE;
}
Bool wxArcPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
double xx, yy, ww, hh;
xx = dc->FsLogicalToDeviceX(x, ox, sx);
yy = dc->FsLogicalToDeviceY(y, oy, sy);
ww = dc->FsLogicalToDeviceXRel(w, ox, sx);
hh = dc->FsLogicalToDeviceYRel(h, oy, sy);
s->Out("matrix currentmatrix ");
s->Out(xx + ww/2); s->Out(" "); s->Out(yy - hh/2); s->Out(" translate ");
s->Out(ww); s->Out(" "); s->Out(hh); s->Out(" scale\n");
if ((start != 0) || (end != 2 * wxPI)) {
s->Out("0 0 moveto\n");
}
s->Out("0 0 0.5 ");
s->Out(start * 180 / wxPI); s->Out(" ");
s->Out(end * 180 / wxPI); s->Out(" arc setmatrix closepath\n");
return FALSE;
}
wxUnionPathRgn::wxUnionPathRgn(wxPathRgn *_f, wxPathRgn *_s)
: wxPathRgn(NULL)
{
if (!_f || !_s)
abort();
a = _f;
b = _s;
}
Bool wxUnionPathRgn::Install(long target, Bool reverse, Bool align)
{
Bool aoe, boe;
aoe = a->Install(target, reverse, align);
boe = b->Install(target, reverse, align);
return aoe || boe;
}
Bool wxUnionPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
Bool aoe, boe;
aoe = a->InstallPS(dc, s);
boe = b->InstallPS(dc, s);
return aoe || boe;
}
wxIntersectPathRgn::wxIntersectPathRgn(wxPathRgn *_f, wxPathRgn *_s)
: wxPathRgn(NULL)
{
if (!_f || !_s)
abort();
a = _f;
b = _s;
}
Bool wxIntersectPathRgn::Install(long target, Bool reverse, Bool align)
{
Bool aoe;
aoe = a->Install(target, reverse, align);
#ifdef WX_USE_CAIRO
if (aoe)
cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_EVEN_ODD);
cairo_clip(CAIRO_DEV);
if (aoe)
cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_WINDING);
cairo_new_path(CAIRO_DEV);
#endif
#if defined(wx_mac)
CGContextBeginPath(CGCG);
CGContextAddPath(CGCG, CGPATH);
if (aoe)
CGContextEOClip(CGCG);
else
CGContextClip(CGCG);
CGPathRelease(CGPATH);
{
CGMutablePathRef p;
p = CGPathCreateMutable();
CGPATH = p;
}
#endif
#if defined(wx_msw)
wxGSetClip(GP_G, GP, GP_DID_ONE ? CombineModeIntersect : CombineModeReplace);
GP_DID_ONE = 1;
wxGPathRelease(GP);
{
GraphicsPath *p;
p = wxGPathNew(FillModeAlternate);
GP = p;
}
#endif
return b->Install(target, reverse, align);
}
Bool wxIntersectPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
Bool aoe;
aoe = a->InstallPS(dc, s);
if (aoe)
s->Out("eoclip\n");
else
s->Out("clip\n");
return b->InstallPS(dc, s);
}
wxDiffPathRgn::wxDiffPathRgn(wxPathRgn *_f, wxPathRgn *_s)
: wxPathRgn(NULL)
{
if (!_f || !_s)
abort();
a = _f;
b = _s;
}
Bool wxDiffPathRgn::Install(long target, Bool reverse, Bool align)
{
Bool aoe, boe;
aoe = a->Install(target, reverse, align);
boe = b->Install(target, !reverse, align);
return aoe || boe;
}
Bool wxDiffPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
{
Bool aoe, boe;
aoe = a->InstallPS(dc, s);
s->Out("reversepath\n");
boe = b->InstallPS(dc, s);
s->Out("reversepath\n");
return aoe || boe;
}
/********************************************************/
/* Paths */
/********************************************************/
#define CMD_CLOSE 1.0
#define CMD_MOVE 2.0
#define CMD_LINE 3.0
#define CMD_CURVE 4.0
#define ROTATE_XY(x, y) { xtmp1 = x; ytmp1 = y; \
xtmp2 = (xx * xtmp1) + (xy * ytmp1); \
ytmp2 = (yy * ytmp1) + (yx * xtmp1); \
x = xtmp2; y = ytmp2; }
wxPath::wxPath()
{
Reset();
}
wxPath::~wxPath()
{
Reset();
}
void wxPath::Reset()
{
ClearCache();
cmd_size = 0;
alloc_cmd_size = 0;
cmds = NULL;
last_cmd = -1;
}
void wxPath::ClearCache()
{
poly_pts = NULL;
}
void wxPath::MakeRoom(int n)
{
ClearCache();
if (cmd_size + n > alloc_cmd_size) {
double *a;
int s;
s = 2 * (alloc_cmd_size + n);
a = new WXGC_ATOMIC double[s];
memcpy(a, cmds, sizeof(double) * cmd_size);
cmds = a;
alloc_cmd_size = s;
}
}
Bool wxPath::IsOpen()
{
return ((last_cmd > -1) && (cmds[last_cmd] != CMD_CLOSE));
}
void wxPath::Close()
{
if ((last_cmd > -1) && (cmds[last_cmd] != CMD_CLOSE)) {
MakeRoom(1);
last_cmd = cmd_size;
cmds[cmd_size++] = CMD_CLOSE;
}
}
void wxPath::MoveTo(double x, double y)
{
Close();
MakeRoom(3);
last_cmd = cmd_size;
cmds[cmd_size++] = CMD_MOVE;
cmds[cmd_size++] = x;
cmds[cmd_size++] = y;
}
void wxPath::LineTo(double x, double y)
{
MakeRoom(3);
last_cmd = cmd_size;
cmds[cmd_size++] = CMD_LINE;
cmds[cmd_size++] = x;
cmds[cmd_size++] = y;
}
void wxPath::Arc(double x, double y, double w, double h, double start, double end, Bool ccw)
{
double delta, angle, rotate;
double x0, y0, x1, y1, x2, y2, x3, y3;
double xx, xy, yy, yx, xtmp1, ytmp1, xtmp2, ytmp2;
int did_one = 0, start_cmd = cmd_size, start_open;
start_open = IsOpen();
/* The arc below is backwards from the MrEd API.... */
{
double s;
s = start;
start = end;
end = s;
}
if (ccw) {
double s;
s = start;
start = end;
end = s;
}
delta = end - start;
if (delta > 2 * wxPI)
delta = 2 * wxPI;
else if (delta < 0) {
delta = fmod(delta, 2 * wxPI);
delta += 2 * wxPI;
}
/* At this point, delta is between 0 and 2pi */
if (delta == 2 * wxPI)
start = 0;
/* Change top-left to center: */
x += w/2;
y += h/2;
/* Make up to 4 curves to represent the arc. */
do {
if (delta > (wxPI / 2))
angle = (wxPI / 2);
else
angle = delta;
/* First generate points for an arc
of `angle' length from -angle/2 to
+angle/2. */
x0 = cos(angle / 2);
y0 = sin(angle / 2);
x1 = (4 - x0) / 3;
y1 = ((1 - x0) * (3 - x0)) / (3 * y0);
x2 = x1;
y2 = -y1;
x3 = x0;
y3 = -y0;
/* Rotate to start: */
rotate = start + (angle / 2);
xx = cos(rotate);
xy = sin(rotate);
yy = xx;
yx = -xy;
ROTATE_XY(x0, y0);
ROTATE_XY(x1, y1);
ROTATE_XY(x2, y2);
ROTATE_XY(x3, y3);
/* Scale and move to match ellipse: */
x0 = (x0 * w/2) + x;
x1 = (x1 * w/2) + x;
x2 = (x2 * w/2) + x;
x3 = (x3 * w/2) + x;
y0 = (y0 * h/2) + y;
y1 = (y1 * h/2) + y;
y2 = (y2 * h/2) + y;
y3 = (y3 * h/2) + y;
if (!did_one) {
if (IsOpen()) {
LineTo(x0, y0);
} else {
MoveTo(x0, y0);
}
}
if (angle)
CurveTo(x1, y1, x2, y2, x3, y3);
else
LineTo(x3, y3);
start += angle;
delta -= angle;
did_one = 1;
} while (delta > 0);
if (!ccw) {
Reverse(start_cmd, start_open);
}
}
void wxPath::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
{
MakeRoom(7);
last_cmd = cmd_size;
cmds[cmd_size++] = CMD_CURVE;
cmds[cmd_size++] = x1;
cmds[cmd_size++] = y1;
cmds[cmd_size++] = x2;
cmds[cmd_size++] = y2;
cmds[cmd_size++] = x3;
cmds[cmd_size++] = y3;
}
void wxPath::Rectangle(double x, double y, double width, double height)
{
MoveTo(x, y);
LineTo(x + width, y);
LineTo(x + width, y + height);
LineTo(x, y + height);
Close();
}
void wxPath::RoundedRectangle(double x, double y, double width, double height, double radius)
{
// A negative radius value is interpreted to mean
// 'the proportion of the smallest X or Y dimension'
if (radius < 0.0) {
double smallest = 0.0;
if (width < height)
smallest = width;
else
smallest = height;
radius = (double)(- radius * smallest);
}
Close();
Arc(x, y, radius * 2, radius * 2, wxPI, 0.5 * wxPI, FALSE);
LineTo(x + width - radius, y);
Arc(x + width - 2 * radius, y, radius * 2, radius * 2, 0.5 * wxPI, 0 * wxPI, FALSE);
LineTo(x + width, y + height - radius);
Arc(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius, 0 * wxPI, 1.5 * wxPI, FALSE);
LineTo(x + radius, y + height);
Arc(x, y + height - 2 * radius, 2 * radius, 2 * radius, 1.5 * wxPI, 1.0 * wxPI, FALSE);
Close();
}
void wxPath::Ellipse(double x, double y, double width, double height)
{
Close();
Arc(x, y, width, height, 0, 2 * wxPI, TRUE);
Close();
}
void wxPath::Lines(int n, wxPoint points[], double xoffset, double yoffset)
{
int i;
for (i = 0; i < n; i++) {
LineTo(points[i].x + xoffset, points[i].y + yoffset);
}
}
void wxPath::Translate(double x, double y)
{
int i = 0;
while (i < cmd_size) {
if (cmds[i] == CMD_CLOSE) {
i += 1;
} else if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
cmds[i+1] += x;
cmds[i+2] += y;
i += 3;
} else if (cmds[i] == CMD_CURVE) {
cmds[i+1] += x;
cmds[i+2] += y;
cmds[i+3] += x;
cmds[i+4] += y;
cmds[i+5] += x;
cmds[i+6] += y;
i += 7;
}
}
}
void wxPath::Scale(double x, double y)
{
int i = 0;
while (i < cmd_size) {
if (cmds[i] == CMD_CLOSE) {
i += 1;
} else if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
cmds[i+1] *= x;
cmds[i+2] *= y;
i += 3;
} else if (cmds[i] == CMD_CURVE) {
cmds[i+1] *= x;
cmds[i+2] *= y;
cmds[i+3] *= x;
cmds[i+4] *= y;
cmds[i+5] *= x;
cmds[i+6] *= y;
i += 7;
}
}
}
void wxPath::Rotate(double a)
{
double xx, xy, yy, yx, xtmp1, ytmp1, xtmp2, ytmp2;
int i = 0;
xx = cos(a);
xy = sin(a);
yy = xx;
yx = -xy;
while (i < cmd_size) {
if (cmds[i] == CMD_CLOSE) {
i += 1;
} else if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
ROTATE_XY(cmds[i+1], cmds[i+2]);
i += 3;
} else if (cmds[i] == CMD_CURVE) {
ROTATE_XY(cmds[i+1], cmds[i+2]);
ROTATE_XY(cmds[i+3], cmds[i+4]);
ROTATE_XY(cmds[i+5], cmds[i+6]);
i += 7;
}
}
}
void wxPath::Reverse(int start_cmd, Bool start_with_line)
{
int e, i, j, pos, n, *cs, controls;
double *a;
while (start_cmd < cmd_size) {
/* Find next starting point: */
if (cmds[start_cmd] == CMD_CLOSE) {
start_cmd += 1;
}
i = start_cmd;
n = 0;
while (i < cmd_size) {
if (cmds[i] == CMD_CLOSE) {
break;
} else {
n++;
if (cmds[i] == CMD_MOVE) {
i += 3;
} else if (cmds[i] == CMD_LINE) {
i += 3;
} else if (cmds[i] == CMD_CURVE) {
i += 7;
}
}
}
e = i;
/* Reverse sub-path in [start_cmd, e) */
a = new WXGC_ATOMIC double[e - start_cmd];
cs = new WXGC_ATOMIC int[n];
/* Traverse again to find command starts: */
n = 0;
i = start_cmd;
while (i < e) {
cs[n++] = i;
if (cmds[i] == CMD_MOVE) {
i += 3;
} else if (cmds[i] == CMD_LINE) {
i += 3;
} else if (cmds[i] == CMD_CURVE) {
i += 7;
}
}
/* Reverse */
controls = -1;
pos = 0;
for (j = n; j--; ) {
i = cs[j];
if (!start_with_line && (j == n - 1)) {
a[pos++] = CMD_MOVE;
} else if (controls >= 0) {
a[pos++] = CMD_CURVE;
a[pos++] = cmds[controls+3];
a[pos++] = cmds[controls+4];
a[pos++] = cmds[controls+1];
a[pos++] = cmds[controls+2];
} else {
a[pos++] = CMD_LINE;
}
if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
a[pos++] = cmds[i+1];
a[pos++] = cmds[i+2];
controls = -1;
} else if (cmds[i] == CMD_CURVE) {
a[pos++] = cmds[i+5];
a[pos++] = cmds[i+6];
controls = i;
}
}
memcpy(cmds + start_cmd, a, (e - start_cmd) * sizeof(double));
start_cmd = e;
}
}
void wxPath::AddPath(wxPath *p)
{
int i, closed_n;
if (!IsOpen()) {
/* Simple case: this path is closed, so just append p */
MakeRoom(p->cmd_size);
last_cmd = cmd_size + p->last_cmd;
for (i = 0; i < p->cmd_size; i++) {
cmds[cmd_size++] = p->cmds[i];
}
} else {
/* Put closed paths in p on the front of this path,
and add unclosed paths to this path's unclosed
path. */
if (p->IsOpen()) {
for (i = 0; i < p->cmd_size; i++) {
if (p->cmds[i] == CMD_CLOSE)
break;
else if (cmds[i] == CMD_CURVE)
i += 7;
else
i += 3;
}
if (i < p->cmd_size) {
closed_n = i + 1;
} else {
closed_n = 0;
}
} else {
/* No open path in p */
closed_n = p->cmd_size;
}
MakeRoom(p->cmd_size);
memmove(cmds + closed_n, cmds, cmd_size * sizeof(double));
memcpy(cmds, p->cmds, closed_n * sizeof(double));
if (closed_n < p->cmd_size) {
/* There was an open path in p... */
memcpy(cmds + cmd_size + closed_n, p->cmds + closed_n, (p->cmd_size - closed_n) * sizeof(double));
/* p's open path must start with CMD_MOVE; change it to CMD_LINE */
cmds[closed_n + cmd_size] = CMD_LINE;
last_cmd = cmd_size + p->last_cmd;
} else {
/* No open path in p, so just adjust last_cmd */
last_cmd += closed_n;
}
cmd_size += p->cmd_size;
}
}
void wxPath::Install(long target, double dx, double dy,
double ox, double oy, double sx, double sy,
Bool align, double pox, double poy)
{
int i = 0;
double lx = 0.0, ly = 0.0, lxx = 0.0, lyy = 0.0;
#ifdef WX_USE_CAIRO
cairo_new_path(CAIRO_DEV);
#endif
while (i < cmd_size) {
if (cmds[i] == CMD_CLOSE) {
#ifdef WX_USE_CAIRO
cairo_close_path(CAIRO_DEV);
#endif
#ifdef wx_mac
CGPathCloseSubpath(PATHPATH);;
#endif
#ifdef wx_msw
wxGPathCloseFigure(PATH_GP);
#endif
i += 1;
} else if (cmds[i] == CMD_MOVE) {
double xx, yy;
xx = (cmds[i+1]+dx) * sx + ox;
yy = (cmds[i+2]+dy) * sy + oy;
if (align) {
xx = floor(xx) + pox;
yy = floor(yy) + poy;
}
#ifdef WX_USE_CAIRO
cairo_move_to(CAIRO_DEV, xx, yy);
#endif
#ifdef wx_mac
CGPathMoveToPoint(PATHPATH, NULL, xx, yy);
#endif
lx = cmds[i+1];
ly = cmds[i+2];
lxx = xx;
lyy = yy;
i += 3;
} else if (cmds[i] == CMD_LINE) {
if ((cmds[i+1] != lx) || (cmds[i+2] != ly)) {
double xx, yy;
xx = (cmds[i+1]+dx) * sx + ox;
yy = (cmds[i+2]+dy) * sy + oy;
if (align) {
xx = floor(xx) + pox;
yy = floor(yy) + poy;
}
#ifdef WX_USE_CAIRO
cairo_line_to(CAIRO_DEV, xx, yy);
#endif
#ifdef wx_mac
CGPathAddLineToPoint(PATHPATH, NULL, xx, yy);
#endif
#ifdef wx_msw
wxGPathAddLine(PATH_GP, lxx, lyy, xx, yy);
#endif
lx = cmds[i+1];
ly = cmds[i+2];
lxx = xx;
lyy = yy;
}
i += 3;
} else if (cmds[i] == CMD_CURVE) {
if ((cmds[i+5] != lx) || (cmds[i+6] != ly)) {
double xx, yy, xx1, yy1, xx2, yy2;
xx = (cmds[i+5]+dx) * sx + ox;
yy = (cmds[i+6]+dy) * sy + oy;
if (align) {
xx = floor(xx) + pox;
yy = floor(yy) + poy;
}
xx1 = (cmds[i+1]+dx) * sx + ox;
yy1 = (cmds[i+2]+dy) * sy + oy;
xx2 = (cmds[i+3]+dx) * sx + ox;
yy2 = (cmds[i+4]+dy) * sy + oy;
#ifdef WX_USE_CAIRO
cairo_curve_to(CAIRO_DEV, xx1, yy1, xx2, yy2, xx, yy);
#endif
#ifdef wx_mac
CGPathAddCurveToPoint(PATHPATH, NULL, xx1, yy1, xx2, yy2, xx, yy);
#endif
#ifdef wx_msw
wxGPathAddBezier(PATH_GP, lxx, lyy, xx1, yy1, xx2, yy2, xx, yy);
#endif
lx = cmds[i+5];
ly = cmds[i+6];
lxx = xx;
lyy = yy;
}
i += 7;
}
}
}
void wxPath::InstallPS(wxPostScriptDC *dc, wxPSStream *s, double dx, double dy)
{
int i = 0;
while (i < cmd_size) {
if (cmds[i] == CMD_CLOSE) {
s->Out("closepath\n");
i += 1;
} else if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
double x, y;
x = dc->FLogicalToDeviceX(cmds[i+1]+ dx);
y = dc->FLogicalToDeviceY(cmds[i+2]+ dy);
s->Out(x); s->Out(" "); s->Out(y);
if (cmds[i] == CMD_LINE)
s->Out(" lineto\n");
else
s->Out(" moveto\n");
i += 3;
} else if (cmds[i] == CMD_CURVE) {
double x1, y1, x2, y2, x3, y3;
x1 = dc->FLogicalToDeviceX(cmds[i+1] + dx);
y1 = dc->FLogicalToDeviceY(cmds[i+2] + dy);
x2 = dc->FLogicalToDeviceX(cmds[i+3] + dx);
y2 = dc->FLogicalToDeviceY(cmds[i+4] + dy);
x3 = dc->FLogicalToDeviceX(cmds[i+5] + dx);
y3 = dc->FLogicalToDeviceY(cmds[i+6] + dy);
s->Out(x1); s->Out(" "); s->Out(y1); s->Out(" ");
s->Out(x2); s->Out(" "); s->Out(y2); s->Out(" ");
s->Out(x3); s->Out(" "); s->Out(y3); s->Out(" ");
s->Out("curveto\n");
i += 7;
}
}
}
static double my_round(double d)
{
double i, frac;
if (d < 0) {
frac = modf(d, &i);
if (frac < -0.5)
return i - 1;
else
return i;
} else {
frac = modf(d, &i);
if (frac < 0.5)
return i;
else
return i + 1;
}
}
int wxPath::ToPolygons(int **_lens, double ***_ptss, double sx, double sy)
{
int i, cnt, *lens, len, alloc_len, need_len;
double lx, ly, **ptss, *pts, *naya;
cnt = 0;
for (i = 0; i < cmd_size; ) {
if (cmds[i] == CMD_CLOSE) {
cnt++;
i += 1;
} else if (cmds[i] == CMD_MOVE) {
i += 3;
} else if (cmds[i] == CMD_LINE) {
i += 3;
} else if (cmds[i] == CMD_CURVE) {
i += 7;
}
}
if (IsOpen())
cnt++;
ptss = new WXGC_PTRS double*[cnt];
lens = new WXGC_ATOMIC int[cnt];
cnt = 0;
pts = NULL;
len = 0;
alloc_len = 0;
lx = ly = 0;
for (i = 0; i < cmd_size; ) {
if (cmds[i] == CMD_CLOSE) {
ptss[cnt] = pts;
lens[cnt] = len;
cnt++;
len = 0;
alloc_len = 0;
pts = NULL;
lx = ly = 0;
i += 1;
} else {
if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
need_len = 1;
} else if (cmds[i] == CMD_CURVE) {
double dx, dy;
dx = sx * (lx - cmds[i + 5]);
dy = sy * (ly - cmds[i + 6]);
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (dx > dy)
need_len = (int)ceil(dx);
else
need_len = (int)ceil(dy);
need_len += 1;
} else {
need_len = 0;
}
if (len + (2 * need_len) > alloc_len) {
int l;
l = (len + (2 * need_len)) * 2;
naya = new WXGC_ATOMIC double[l];
memcpy(naya, pts, len * sizeof(double));
pts = naya;
alloc_len = l;
}
if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
lx = cmds[i+1];
ly = cmds[i+2];
pts[len++] = lx;
pts[len++] = ly;
i += 3;
} else if (cmds[i] == CMD_CURVE) {
int d;
double x0 = lx, x1 = cmds[i+1], x2 = cmds[i+3], x3 = cmds[i+5];
double y0 = ly, y1 = cmds[i+2], y2 = cmds[i+4], y3 = cmds[i+6];
double ax = (((x3 - (x2 * 3)) + (x1 * 3)) - x0);
double ay = (((y3 - (y2 * 3)) + (y1 * 3)) - y0);
double bx = (((x2 * 3) - (x1 * 6)) + (x0 * 3));
double by = (((y2 * 3) - (y1 * 6)) + (y0 * 3));
double cx = ((x1 * 3) - (x0 * 3));
double cy = ((y1 * 3) - (y0 * 3));
double dx = x0, dy = y0, tt, x, y;
for (d = 0; d < need_len; d++) {
tt = ((double)d / (double)(need_len - 1));
x = ((((((tt * ax) + bx) * tt) + cx) * tt) + dx);
y = ((((((tt * ay) + by) * tt) + cy) * tt) + dy);
if ((d > 0) && (d < need_len-1)) {
/* We've generating points to map to pixels
after scaling, so round intermediate points.
End point have to be floored, for consistency
with everything else, so leave them alone. */
x = my_round(x * sx) / sx;
y = my_round(y * sy) / sy;
}
pts[len++] = x;
pts[len++] = y;
}
lx = x3;
ly = y3;
i += 7;
}
}
}
if (IsOpen()) {
ptss[cnt] = pts;
lens[cnt] = len;
cnt++;
}
*_lens = lens;
*_ptss = ptss;
return cnt;
}
void wxPath::BoundingBox(double *_x1, double *_y1, double *_x2, double *_y2)
{
double x1, x2, y1, y2;
int i;
if (cmd_size) {
/* First command must be move-to: */
x1 = cmds[1];
y1 = cmds[2];
x2 = x1;
y2 = y1;
for (i = 3; i < cmd_size; ) {
if (cmds[i] == CMD_CLOSE) {
i += 1;
} else if ((cmds[i] == CMD_MOVE)
|| (cmds[i] == CMD_LINE)) {
if (cmds[i+1] < x1)
x1 = cmds[i+1];
if (cmds[i+1] > x2)
x2 = cmds[i+1];
if (cmds[i+2] < y1)
y1 = cmds[i+2];
if (cmds[i+2] > y2)
y2 = cmds[i+2];
i += 3;
} else if (cmds[i] == CMD_CURVE) {
int j;
for (j = 0; j < 6; j += 2) {
if (cmds[i+j+1] < x1)
x1 = cmds[i+j+1];
if (cmds[i+j+1] > x2)
x2 = cmds[i+j+1];
if (cmds[i+j+2] < y1)
y1 = cmds[i+j+2];
if (cmds[i+j+2] > y2)
y2 = cmds[i+j+2];
}
i += 7;
}
}
} else {
x1 = y1 = x2 = y2 = 0.0;
}
*_x1 = x1;
*_x2 = x2;
*_y1 = y1;
*_y2 = y2;
}