Back to index

plt-scheme  4.2.1
Region.cxx
Go to the documentation of this file.
00001 /********************************************************/
00002 /*                       Regions                        */
00003 /********************************************************/
00004 
00005 #ifndef wxPI
00006 # define wxPI 3.141592653589793
00007 #endif
00008 
00009 #define CAIRO_DEV ((cairo_t *)target)
00010 
00011 #ifdef wx_mac
00012 typedef struct {
00013   CGContextRef cg;
00014   CGMutablePathRef path;
00015 } PathTarget;
00016 # define CGPATH ((PathTarget *)target)->path
00017 # define CGCG ((PathTarget *)target)->cg
00018 # define PathTargetPath_t CGMutablePathRef
00019 # define CGXFORM (&current_xform)
00020 # define PATHPATH ((CGMutablePathRef)target)
00021 #endif
00022 
00023 #ifdef wx_msw
00024 typedef struct {
00025   Graphics *g;
00026   GraphicsPath *path;
00027   int did_one;
00028 } PathTarget;
00029 # define GP ((PathTarget *)target)->path
00030 # define GP_G ((PathTarget *)target)->g
00031 # define GP_DID_ONE ((PathTarget *)target)->did_one
00032 # define PathTargetPath_t GraphicsPath*
00033 # define CURRENT_GP current_path
00034 # define PATH_GP ((GraphicsPath *)target)
00035 #endif
00036 
00037 #ifndef WX_USE_CAIRO
00038 typedef int cairo_matrix_p;
00039 #endif
00040 
00041 /**************************************************************************/
00042 
00043 wxRegion::wxRegion(wxDC *_dc, wxRegion *r, Bool _no_prgn)
00044 {
00045   dc = _dc;
00046   is_ps = wxSubType(dc->__type, wxTYPE_DC_POSTSCRIPT);
00047   locked = 0;
00048  
00049 #ifdef wx_msw
00050   lazy_rgn = NULL;
00051 #endif
00052 #ifdef wx_x
00053   rgn = NULL;
00054 #endif
00055 #ifdef wx_mac
00056   rgn = NULL;
00057 #endif
00058   prgn = NULL;
00059   no_prgn = _no_prgn;
00060   if (r) Union(r);
00061 }
00062 
00063 wxRegion::~wxRegion()
00064 {
00065   Cleanup();
00066 }
00067 
00068 void wxRegion::Cleanup()
00069 {  
00070 #ifdef wx_msw
00071   if (lazy_rgn) {
00072     if (real_rgn)
00073       lazy_rgn->DoneRgn(real_rgn);
00074     lazy_rgn = NULL;
00075   }
00076 #endif
00077 #ifdef wx_x
00078   if (rgn) {
00079     XDestroyRegion(rgn);
00080     rgn = NULL;
00081   }
00082 #endif
00083 #ifdef wx_mac
00084   if (rgn) {
00085     DisposeRgn(rgn);
00086     rgn = NULL;
00087   }
00088 #endif
00089   if (!no_prgn) {
00090     prgn = NULL;
00091   }
00092 }
00093 
00094 void wxRegion::Lock(int delta)
00095 {
00096 #ifdef wx_msw
00097   if (!locked) {
00098     if (lazy_rgn) {
00099       real_rgn = lazy_rgn->GetRgn();
00100     }
00101   }
00102 #endif  
00103 
00104   locked += delta;
00105 
00106 #ifdef wx_msw
00107   if (!locked) {
00108     if (lazy_rgn) {
00109       lazy_rgn->DoneRgn(real_rgn);
00110       real_rgn = NULL;
00111     }
00112   }
00113 #endif
00114 }
00115 
00116 #ifdef wx_msw
00117 HRGN wxRegion::GetRgn()
00118 {
00119   return real_rgn;
00120 }
00121 #endif
00122 
00123 void wxRegion::SetRectangle(double x, double y, double width, double height)
00124 {
00125   double xw, yh;
00126   int ix, iy, iw, ih;
00127 
00128   Cleanup();
00129 
00130   if (!no_prgn) {
00131     prgn = new WXGC_PTRS wxRectanglePathRgn(dc, x, y, width, height);
00132   }
00133 
00134   xw = x + width;
00135   yh = y + height;
00136   x = dc->FLogicalToUnscrolledDeviceX(x);
00137   y = dc->FLogicalToUnscrolledDeviceY(y);
00138   xw = dc->FLogicalToUnscrolledDeviceX(xw);
00139   width = xw - x;
00140   yh = dc->FLogicalToUnscrolledDeviceY(yh);
00141   height = yh - y;
00142 
00143   if (is_ps) {
00144     /* So bitmap-based region is right */
00145     height = -height;
00146     y  = -y;
00147   }
00148 
00149   ix = (int)floor(x);
00150   iy = (int)floor(y);
00151   iw = ((int)floor(x + width)) - ix;
00152   ih = ((int)floor(y + height)) - iy;
00153 
00154 #ifdef wx_msw
00155   lazy_rgn = new RectLazyRgn(ix, iy, iw, ih);
00156 #endif
00157 #ifdef wx_x
00158   {
00159     XRectangle r;
00160     rgn = XCreateRegion();
00161     r.x = ix;
00162     r.y = iy;
00163     r.width = iw;
00164     r.height = ih;
00165     XUnionRectWithRegion(&r, rgn, rgn);
00166   }
00167 #endif
00168 #ifdef wx_mac
00169   rgn = NewRgn();
00170   SetRectRgn(rgn, ix, iy, ix + iw, iy + ih);
00171 #endif
00172 }
00173 
00174 void wxRegion::SetRoundedRectangle(double x, double y, double width, double height, double radius)
00175 {
00176 #ifdef wx_xt
00177   wxRegion *lt, *rt, *lb, *rb, *w, *h, *r;
00178 #endif
00179 #if defined(wx_msw) || defined(wx_mac)
00180   double xw, yh;
00181   int ix, iy, iw, ih;
00182   int xradius, yradius;
00183 #endif
00184 
00185   Cleanup();
00186 
00187   if (!no_prgn) {
00188     prgn = new WXGC_PTRS wxRoundedRectanglePathRgn(dc, x, y, width, height, radius);
00189   }
00190 
00191   // A negative radius value is interpreted to mean
00192   // 'the proportion of the smallest X or Y dimension'
00193   if (radius < 0.0) {
00194     double smallest = 0.0;
00195     if (width < height)
00196       smallest = width;
00197     else
00198       smallest = height;
00199     radius = (double)(- radius * smallest);
00200   } else
00201     radius = dc->FLogicalToDeviceXRel(radius);
00202 
00203 #ifdef wx_x
00204   lt = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00205   rt = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00206   lb = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00207   rb = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00208   w = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00209   h = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00210 
00211   lt->SetEllipse(x, y, 2 * radius, 2 * radius);
00212   rt->SetEllipse(x + width - 2 * radius, y, 2 * radius, 2 * radius);
00213   rb->SetEllipse(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius);
00214   lb->SetEllipse(x, y + height - 2 * radius, 2 * radius, 2 * radius);
00215 
00216   w->SetRectangle(x, y + radius, width, height - 2 * radius);
00217   h->SetRectangle(x + radius, y, width - 2 * radius, height);
00218 
00219   r = lt;
00220   r->Union(rt);
00221   r->Union(lb);
00222   r->Union(rb);
00223   r->Union(w);
00224   r->Union(h);
00225 
00226   /* A little hack: steal rgn from r: */
00227   rgn = r->rgn;
00228   r->rgn = NULL;
00229 #else
00230   /* Windows and Mac */
00231   xw = x + width;
00232   yh = y + height;
00233   x = dc->FLogicalToUnscrolledDeviceX(x);
00234   y = dc->FLogicalToUnscrolledDeviceY(y);
00235   width = dc->FLogicalToUnscrolledDeviceX(xw) - x;
00236   height = dc->FLogicalToUnscrolledDeviceY(yh) - y;
00237   xradius = (int)(dc->FLogicalToDeviceXRel(radius));
00238   yradius = (int)(dc->FLogicalToDeviceYRel(radius));
00239 
00240   ix = (int)floor(x);
00241   iy = (int)floor(y);
00242   iw = ((int)floor(x + width)) - ix;
00243   ih = ((int)floor(y + height)) - iy;
00244 
00245   if (is_ps) {
00246     /* So bitmap-based region is right */
00247     height = -height;
00248     y = -y;
00249   }
00250 
00251 # ifdef wx_msw
00252   lazy_rgn = new RoundRectLazyRgn(ix, iy, iw, ih, xradius, yradius);
00253 # endif
00254 # ifdef wx_mac
00255   /* This code uses the current port. We don't know what the current
00256      port might be, so we have to pick one to be sure that QuickDraw
00257      is allowed. */
00258   {
00259     CGrafPtr savep;
00260     GDHandle savegd;
00261     
00262     ::GetGWorld(&savep, &savegd);  
00263     ::SetGWorld(wxGetGrafPtr(), GetMainDevice());
00264 
00265     rgn = NewRgn();
00266     OpenRgn();
00267     {
00268       Rect r2;
00269       SetRect(&r2, ix, iy, ix + iw, iy + ih);
00270       FrameRoundRect(&r2, xradius, yradius);
00271       CloseRgn(rgn);
00272     }
00273 
00274     ::SetGWorld(savep, savegd);
00275   }    
00276 # endif
00277 #endif
00278 }
00279 
00280 void wxRegion::SetEllipse(double x, double y, double width, double height)
00281 {
00282   double xw, yh;
00283 #if defined(wx_msw) || defined(wx_mac)
00284   int ix, iy, iw, ih;
00285 #endif
00286 
00287   Cleanup();
00288 
00289   if (!no_prgn) {
00290 #ifdef WX_USE_CAIRO
00291     /* cairo_arc() went bad for clipping, so we avoid it. */
00292     {
00293       wxPath *p;
00294       p = new WXGC_PTRS wxPath();
00295       p->Arc(x, y, width, height, 0, 2 * wxPI, FALSE);
00296       p->Close();
00297       prgn = new WXGC_PTRS wxPathPathRgn(dc, p, 0, 0, wxWINDING_RULE);
00298     }
00299 #else
00300     prgn = new WXGC_PTRS wxArcPathRgn(dc, x, y, width, height, 0, 2 * wxPI);
00301 #endif
00302   }
00303 
00304   xw = x + width;
00305   yh = y + height;
00306   x = dc->FLogicalToUnscrolledDeviceX(x);
00307   y = dc->FLogicalToUnscrolledDeviceY(y);
00308   width = dc->FLogicalToUnscrolledDeviceX(xw) - x;
00309   height = dc->FLogicalToUnscrolledDeviceY(yh) - y;
00310 
00311   if (is_ps) {
00312     /* So bitmap-based region is right */
00313     height = -height;
00314     y = -y;
00315   }
00316 
00317 #if defined(wx_msw) || defined(wx_mac)
00318   ix = (int)floor(x);
00319   iy = (int)floor(y);
00320   iw = ((int)floor(x + width)) - ix;
00321   ih = ((int)floor(y + height)) - iy;
00322 #endif
00323 
00324 #ifdef wx_msw
00325   lazy_rgn = new EllipticLazyRgn(ix, iy, iw, ih);
00326 #endif
00327 #ifdef wx_mac
00328   /* This code uses the current port. We don't know what the current
00329      port might be, so we have to pick one to be sure that QuickDraw
00330      is allowed. */
00331   {
00332     CGrafPtr savep;
00333     GDHandle savegd;
00334     
00335     ::GetGWorld(&savep, &savegd);  
00336     ::SetGWorld(wxGetGrafPtr(), GetMainDevice());
00337 
00338     rgn = NewRgn();
00339     OpenRgn();
00340     {
00341       Rect r;
00342       SetRect(&r, ix, iy, ix + iw, iy + ih);
00343       FrameOval(&r);
00344       CloseRgn(rgn);
00345     }
00346 
00347     ::SetGWorld(savep, savegd);
00348   }
00349 #endif
00350 
00351 #ifdef wx_x
00352   {
00353     int npoints;
00354     XPoint *p;
00355     p = wxEllipseToPolygon(width, height, x, y, &npoints);
00356     rgn = XPolygonRegion(p, npoints - 1, WindingRule);
00357   }
00358 #endif
00359 }
00360 
00361 #ifdef wx_x
00362 # define POINT XPoint
00363 #endif
00364 #ifdef wx_mac
00365 # define POINT MyPoint
00366   typedef struct { int x, y; } MyPoint;
00367 #endif
00368 
00369 typedef struct { double x, y; } FPoint;
00370 
00371 void wxRegion::SetPolygon(int n, wxPoint points[], double xoffset, double yoffset, int fillStyle, int delta)
00372 {
00373   POINT *cpoints;
00374   FPoint *fpoints;
00375   int i, v;
00376   double vf;
00377 
00378   Cleanup();
00379 
00380   if (n < 2)
00381     return;
00382 
00383   if (!no_prgn) {
00384     prgn = new WXGC_PTRS wxPolygonPathRgn(dc, n, points, xoffset, yoffset, fillStyle);
00385   }
00386 
00387   cpoints = new WXGC_ATOMIC POINT[n];
00388   fpoints = (is_ps ? new WXGC_ATOMIC FPoint[n] : (FPoint *)NULL);
00389   for (i = 0; i < n; i++) {
00390     v = dc->LogicalToUnscrolledDeviceX(points[i+delta].x + xoffset);
00391     cpoints[i].x = v;
00392     v = dc->LogicalToUnscrolledDeviceY(points[i+delta].y + yoffset);
00393     cpoints[i].y = v;
00394     if (fpoints) {
00395       vf = dc->FLogicalToUnscrolledDeviceX(points[i+delta].x + xoffset);
00396       fpoints[i].x = vf;
00397       vf = dc->FLogicalToUnscrolledDeviceY(points[i+delta].y + yoffset);
00398       fpoints[i].y = vf;
00399     }
00400   }
00401 
00402   if (is_ps) {
00403     /* So bitmap-based region is right */
00404     for (i = 0; i < n; i++) {
00405       cpoints[i].y = -cpoints[i].y;
00406     }
00407   }
00408 
00409 #ifdef wx_msw
00410   lazy_rgn = new PolygonLazyRgn(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? ALTERNATE : WINDING);
00411 #endif
00412 #ifdef wx_x
00413   rgn = XPolygonRegion(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? EvenOddRule : WindingRule);
00414 #endif
00415 #ifdef wx_mac
00416   /* This code uses the current port. We don't know what the current
00417      port might be, so we have to pick one to be sure that QuickDraw
00418      is allowed. */
00419   {
00420     CGrafPtr savep;
00421     GDHandle savegd;
00422     
00423     ::GetGWorld(&savep, &savegd);  
00424     ::SetGWorld(wxGetGrafPtr(), GetMainDevice());
00425 
00426     rgn = NewRgn();
00427     OpenRgn();
00428     MoveTo(cpoints[0].x, cpoints[0].y);
00429     for (i = 0; i < n; i++) {
00430       LineTo(cpoints[i].x, cpoints[i].y);
00431     }
00432     LineTo(cpoints[0].x, cpoints[0].y);
00433     CloseRgn(rgn);
00434 
00435     ::SetGWorld(savep, savegd);
00436   }
00437 #endif
00438 }
00439 
00440 void wxRegion::SetPath(wxPath *p, double xoffset, double yoffset, int fillStyle)
00441 {
00442   double **ptss, xs, ys;
00443   int *lens, cnt, i, total_cnt, j, k;
00444   wxPoint *a;
00445 
00446   Cleanup();
00447 
00448   if (!no_prgn) {
00449     prgn = new WXGC_PTRS wxPathPathRgn(dc, p, xoffset, yoffset, fillStyle);
00450     no_prgn = 1;
00451   }
00452 
00453   dc->GetUserScale(&xs, &ys);
00454   cnt = p->ToPolygons(&lens, &ptss, xs, ys);
00455 
00456   if (!cnt)
00457     return;
00458   
00459   total_cnt = 0;
00460   for (i = 0; i < cnt; i++) {
00461     total_cnt += (lens[i] / 2);
00462   }
00463 
00464 #ifdef MZ_PRECISE_GC
00465   a = (wxPoint *)GC_malloc_atomic(sizeof(wxPoint) * total_cnt);
00466 #else
00467   a = new WXGC_ATOMIC wxPoint[total_cnt];
00468 #endif
00469 
00470   for (i = 0, k = 0; i < cnt; i++) {
00471     for (j = 0; j < lens[i]; j += 2) {
00472       a[k].x = ptss[i][j] + xoffset;
00473       a[k].y = ptss[i][j+1] + yoffset;
00474       k++;
00475     }
00476   }
00477 
00478   if (cnt == 1) {
00479     SetPolygon(total_cnt, a, xoffset, yoffset, fillStyle, 0);
00480   } else {
00481     for (i = 0, k = 0; i < cnt; i++) {
00482       j = (lens[i] / 2);
00483       if (i == 0)
00484        SetPolygon(j, a, xoffset, yoffset, fillStyle, k);
00485       else {
00486        wxRegion *r;
00487        r = new WXGC_PTRS wxRegion(dc, NULL, 1);
00488        r->SetPolygon(j, a, xoffset, yoffset, fillStyle, k);
00489        Xor(r);
00490        DELETE_OBJ r;
00491       }
00492       k += j;
00493     }
00494   }      
00495   
00496   no_prgn = 0;
00497 }
00498 
00499 void wxRegion::SetArc(double x, double y, double w, double h, double start, double end)
00500 {
00501   wxRegion *r;
00502   static double pi;
00503   int saw_start = 0, saw_end = 0, closed = 0;
00504   double cx, cy;
00505   wxPoint *a;
00506   int n;
00507   char save_no_prgn;
00508 
00509 #ifdef MZ_PRECISE_GC
00510   a = (wxPoint *)GC_malloc_atomic(sizeof(wxPoint) * 20);
00511 #else
00512   a = new WXGC_ATOMIC wxPoint[20];
00513 #endif
00514 
00515   save_no_prgn = no_prgn;
00516   if (!no_prgn) {
00517 #ifdef WX_USE_CAIRO
00518     /* cairo_arc() went bad for clipping, so we avoid it. */
00519     {
00520       wxPath *p;
00521       p = new WXGC_PTRS wxPath();
00522       p->MoveTo(x + w / 2, y + h / 2);
00523       p->Arc(x, y, w, h, end, start, FALSE);
00524       p->Close();
00525       prgn = new WXGC_PTRS wxPathPathRgn(dc, p, 0, 0, wxWINDING_RULE);
00526     }
00527 #else
00528     prgn = new WXGC_PTRS wxArcPathRgn(dc, x, y, w, h, start, end);
00529 #endif
00530     no_prgn = 1;
00531   }
00532 
00533   SetEllipse(x, y, w, h);
00534 
00535   if (start == end) return;
00536 
00537   r = new WXGC_PTRS wxRegion(dc, NULL, TRUE);
00538 
00539   if (!pi)
00540     pi = 2 * asin((double)1.0);
00541 
00542   start = fmod((double)start, 2*pi);
00543   end = fmod((double)end, 2*pi);
00544   if (start < 0)
00545     start += 2*pi;
00546   if (end < 0)
00547     end += 2*pi;
00548 
00549   cx = x + w/2;
00550   cy = y + h/2;
00551 
00552   a[0].x = ((w+2) / 2) * cos(end) + cx;
00553   a[0].y = ((h+2) / 2) * (-sin(end)) + cy;
00554 
00555   a[1].x = cx;
00556   a[1].y = cy;
00557 
00558   a[2].x = ((w+2) / 2) * cos(start) + cx;
00559   a[2].y = ((h+2) / 2) * (-sin(start)) + cy;
00560 
00561   n = 3;
00562 
00563   if (!saw_start && (start < (pi / 2)))
00564     saw_start = 1;
00565   if (!saw_end && (end > start) && (end < (pi / 2)))
00566     saw_end = 1;
00567   if (saw_start && !closed) {
00568     a[n].x = x + w + 2;
00569     a[n++].y = y - 2;
00570   }
00571   if (saw_start && !saw_end) {
00572     a[n].x = cx;
00573     a[n++].y = y - 2;
00574   } else
00575     closed = saw_start;
00576 
00577   if (!saw_start && (start < pi))
00578     saw_start = 1;
00579   if (!saw_end && (end > start) && (end < pi))
00580     saw_end = 1;
00581   if (saw_start && !closed) {
00582     a[n].x = x - 2;
00583     a[n++].y = y - 2;
00584   }
00585   if (saw_start && !saw_end) {
00586     a[n].x = x - 2;
00587     a[n++].y = cy;
00588   } else
00589     closed = saw_start;
00590 
00591   if (!saw_start && (start < (1.5 * pi)))
00592     saw_start = 1;
00593   if (!saw_end && (end > start) && (end < (1.5 * pi)))
00594     saw_end = 1;
00595   if (saw_start && !closed) {
00596     a[n].x = x - 2;
00597     a[n++].y = y + h + 2;
00598   }
00599   if (saw_start && !saw_end) {
00600     a[n].x = cx;
00601     a[n++].y = y + h + 2;
00602   } else
00603     closed = saw_start;
00604 
00605   saw_start = 1;
00606   saw_end = (end > start);
00607   
00608   if (saw_start && !closed) {
00609     a[n].x = x + w + 2;
00610     a[n++].y = y + h + 2;
00611   }
00612   if (saw_start && !saw_end) {
00613     a[n].x = x + w + 2;
00614     a[n++].y = cy;    
00615   } else
00616     closed = saw_start;
00617 
00618   if (!saw_end && (end < (pi / 2)))
00619     saw_end = 1;
00620   if (saw_start && !closed) {
00621     a[n].x = x + w + 2;
00622     a[n++].y = y - 2;
00623   }
00624   if (saw_start && !saw_end) {
00625     a[n].x = cx;
00626     a[n++].y = y - 2; 
00627   } else
00628     closed = saw_start;
00629   
00630   if (!saw_end && (end < pi))
00631     saw_end = 1;
00632   if (saw_start && !closed) {
00633     a[n].x = x - 2;
00634     a[n++].y = y - 2;
00635   }
00636   if (saw_start && !saw_end) {
00637     a[n].x = x - 2;
00638     a[n++].y = cy;    
00639   } else
00640     closed = saw_start;
00641 
00642   if (!saw_end && (end < (1.5 * pi)))
00643     saw_end = 1;
00644   if (saw_start && !closed) {
00645     a[n].x = x - 2;
00646     a[n++].y = y + h + 2;
00647   } 
00648   if (saw_start && !saw_end) {
00649     a[n].x = cx;
00650     a[n++].y = y + h + 2;
00651   } else
00652     closed = saw_start;
00653 
00654   if (!closed) {
00655     a[n].x = x + w + 2;
00656     a[n++].y = y + h + 2;
00657   }
00658 
00659   r->SetPolygon(n, a);
00660 
00661   Intersect(r);
00662 
00663   no_prgn = save_no_prgn;
00664 }
00665 
00666 void wxRegion::Union(wxRegion *r)
00667 {
00668   if (r->dc != dc) return;
00669   if (r->ReallyEmpty()) return;
00670 
00671   if (!no_prgn) {
00672     if (!r->prgn) abort();
00673     if (!prgn)
00674       prgn = r->prgn;
00675     else {
00676       wxPathRgn *pr;
00677       pr = new WXGC_PTRS wxUnionPathRgn(prgn, r->prgn);
00678       prgn = pr;
00679     }
00680   }
00681 
00682 #ifdef wx_msw
00683   if (!lazy_rgn) {
00684     lazy_rgn = r->lazy_rgn;
00685   } else if (!r->lazy_rgn) {
00686     /* no change */
00687   } else {
00688     lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_OR);
00689   }
00690 #endif
00691 #ifdef wx_x
00692   if (!rgn) {
00693     rgn = XCreateRegion();
00694   }
00695   XUnionRegion(rgn, r->rgn, rgn);
00696 #endif
00697 #ifdef wx_mac
00698   if (!rgn) {
00699     rgn = NewRgn();
00700   }
00701   UnionRgn(rgn, r->rgn, rgn);
00702 #endif
00703 }
00704 
00705 void wxRegion::Intersect(wxRegion *r)
00706 {
00707   if (r->dc != dc) return;
00708   if (ReallyEmpty())
00709     return;
00710   if (r->ReallyEmpty()) {
00711     Cleanup();
00712     return;
00713   }
00714 
00715   if (!no_prgn) {
00716     wxPathRgn *rprgn, *pr;
00717     rprgn = r->prgn;
00718     if (!rprgn) abort();
00719     if (prgn->is_rect 
00720        && rprgn->is_rect
00721        && (prgn->ox == rprgn->ox)
00722        && (prgn->oy == rprgn->oy)
00723        && (prgn->sx == rprgn->sx)
00724        && (prgn->sy == rprgn->sy)) {
00725       /* Special case: both are rectangles with the same
00726         origin and scale. This is a common case, and it 
00727         can be a lot faster making a rectangle directly. */
00728       wxRectanglePathRgn *r1 = (wxRectanglePathRgn *)prgn;
00729       wxRectanglePathRgn *r2 = (wxRectanglePathRgn *)rprgn;
00730       double px, py, pw, ph;
00731 
00732       if (r1->x < r2->x)
00733        px = r2->x;
00734       else
00735        px = r1->x;
00736       if (r1->y < r2->y)
00737        py = r2->y;
00738       else
00739        py = r1->y;
00740       if (r1->x + r1->width < r2->x + r2->width)
00741        pw = (r1->x + r1->width) - px;
00742       else
00743        pw = (r2->x + r2->width) - px;
00744       if (r1->y + r1->height < r2->y + r2->height)
00745        ph = (r1->y + r1->height) - py;
00746       else
00747        ph = (r2->y + r2->height) - py;
00748       
00749       if ((pw > 0) && (ph > 0))
00750        pr = new WXGC_PTRS wxRectanglePathRgn(dc, px, py, pw, ph);
00751       else {
00752        /* empty */
00753        Cleanup();
00754        return;
00755       }
00756     } else {
00757       pr = new WXGC_PTRS wxIntersectPathRgn(prgn, r->prgn);
00758     }
00759     prgn = pr;
00760   }
00761 
00762 #ifdef wx_msw
00763   if (!lazy_rgn) return;
00764   if (!r->lazy_rgn) {
00765     lazy_rgn = NULL;
00766     return;
00767   }
00768   
00769   lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_AND);
00770 #endif
00771 #ifdef wx_x
00772   if (!rgn) return;
00773   XIntersectRegion(rgn, r->rgn, rgn);
00774 #endif
00775 #ifdef wx_mac
00776   if (!rgn) return;
00777   SectRgn(rgn, r->rgn, rgn);
00778 #endif
00779 
00780   if (ReallyEmpty()) {
00781     Cleanup();
00782   }
00783 }
00784 
00785 void wxRegion::Subtract(wxRegion *r)
00786 {
00787   if (r->dc != dc) return;
00788   if (r->ReallyEmpty()) return;
00789 
00790   if (!no_prgn) {
00791     /* wxDiffPathRgn is only half a subtract; the result must be intersected with the first part */
00792     wxPathRgn *pr;
00793     if (!r->prgn) abort();
00794     pr = new WXGC_PTRS wxDiffPathRgn(prgn, r->prgn);
00795     pr = new WXGC_PTRS wxIntersectPathRgn(prgn, pr);
00796     prgn = pr;
00797   }
00798 
00799 #ifdef wx_msw
00800   if (!lazy_rgn) return;
00801   if (!r->lazy_rgn) {
00802     /* No change */
00803     return;
00804   }
00805   lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_DIFF);
00806 #endif
00807 #ifdef wx_x
00808   if (!rgn) return;
00809   XSubtractRegion(rgn, r->rgn, rgn);
00810 #endif
00811 #ifdef wx_mac
00812   if (!rgn) return;
00813   DiffRgn(rgn, r->rgn, rgn);
00814 #endif
00815 
00816   if (ReallyEmpty()) {
00817     Cleanup();
00818     return;
00819   }
00820 }
00821   
00822 void wxRegion::Xor(wxRegion *r)
00823 {
00824   if (r->dc != dc) return;
00825   if (r->ReallyEmpty()) return;
00826 
00827   if (!no_prgn) {
00828     wxPathRgn *pr;
00829     if (!r->prgn) abort();
00830     if (!prgn)
00831       pr = r->prgn;
00832     else
00833       pr = new WXGC_PTRS wxDiffPathRgn(prgn, r->prgn);
00834     prgn = pr;
00835   }
00836 
00837 #ifdef wx_msw
00838   if (!lazy_rgn) return;
00839   if (!r->lazy_rgn) {
00840     return;
00841   }
00842   
00843   lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_XOR);
00844 #endif
00845 #ifdef wx_x
00846   if (!rgn) return;
00847   XXorRegion(rgn, r->rgn, rgn);
00848 #endif
00849 #ifdef wx_mac
00850   if (!rgn) return;
00851   XorRgn(rgn, r->rgn, rgn);
00852 #endif
00853 
00854   if (ReallyEmpty()) {
00855     Cleanup();
00856     return;
00857   }
00858 }
00859   
00860 void wxRegion::BoundingBox(double *x, double *y, double *w, double *h)
00861 {
00862   if (Empty()) {
00863     *x = *y = *w = *h = 0;
00864     return;
00865   } else {
00866     double v;
00867 #ifdef wx_msw
00868     RECT r;
00869     HRGN rgn;
00870 
00871     if (real_rgn)
00872       rgn = real_rgn;
00873     else
00874       rgn = lazy_rgn->GetRgn();
00875 
00876     if (rgn)
00877       GetRgnBox(rgn, &r);
00878     else {
00879       r.left = r.top = r.right = r.bottom = 0;
00880     }
00881 
00882     if (!real_rgn)
00883       lazy_rgn->DoneRgn(rgn);
00884   
00885     *x = r.left;
00886     *y = r.top;
00887     *w = r.right - r.left;
00888     *h = r.bottom - r.top;
00889 #endif
00890 #ifdef wx_x
00891     XRectangle r;
00892     
00893     XClipBox(rgn, &r);
00894     
00895     *x = r.x;
00896     *y = r.y;
00897     *w = r.width;
00898     *h = r.height;
00899 #endif
00900 #ifdef wx_mac
00901     {
00902       Rect r;
00903       GetRegionBounds(rgn,&r);
00904       *x = r.left;
00905       *y = r.top;
00906       *w = r.right - *x;
00907       *h = r.bottom - *y;
00908     }
00909 #endif
00910 
00911     if (is_ps) {
00912       /* Bitmap-based region is stored upside-down */
00913       *y = -(*y);
00914     }
00915     
00916     v = dc->UnscrolledDeviceToLogicalX((int)*x);
00917     *x = v;
00918     v = dc->UnscrolledDeviceToLogicalY((int)*y);
00919     *y = v;
00920     v = dc->DeviceToLogicalXRel((int)*w);
00921     *w = v;
00922     v = dc->DeviceToLogicalYRel((int)*h);
00923     *h = v;
00924   }
00925 }
00926 
00927 Bool wxRegion::Empty()
00928 {
00929 #ifdef wx_msw
00930   RECT r;
00931   HRGN rgn;
00932   Bool is_empty;
00933 
00934   if (!lazy_rgn) return TRUE;
00935 
00936   if (real_rgn)
00937     rgn = real_rgn;
00938   else
00939     rgn = lazy_rgn->GetRgn();
00940 
00941   if (!rgn)
00942     is_empty = 1;
00943   else
00944     is_empty = (GetRgnBox(rgn, &r) == NULLREGION);
00945 
00946   if (!real_rgn)
00947     lazy_rgn->DoneRgn(rgn);
00948 
00949   return is_empty;
00950 #endif
00951 #ifdef wx_x
00952   if (!rgn) return TRUE;
00953   return XEmptyRegion(rgn);
00954 #endif
00955 #ifdef wx_mac
00956   if (!rgn) return TRUE;
00957   return EmptyRgn(rgn);
00958 #endif
00959 }
00960 
00961 Bool wxRegion::ReallyEmpty()
00962 {
00963   return Empty() && !prgn;
00964 }
00965 
00966 Bool wxRegion::IsInRegion(double x, double y)
00967 {
00968   int ix, iy;
00969 
00970   if (Empty()) return FALSE;
00971 
00972   x = dc->FLogicalToUnscrolledDeviceX(x);
00973   y = dc->FLogicalToUnscrolledDeviceY(y);
00974   
00975 
00976   ix = (int)floor(x);
00977   iy = (int)floor(y);
00978 
00979 #ifdef wx_xt
00980   return XPointInRegion(rgn, ix, iy);
00981 #endif
00982 #ifdef wx_msw
00983   {
00984     HRGN rgn;
00985     Bool in_rgn;
00986 
00987     if (real_rgn)
00988       rgn = real_rgn;
00989     else
00990       rgn = lazy_rgn->GetRgn();
00991     
00992     if (rgn)
00993       in_rgn = PtInRegion(rgn, ix, iy);
00994     else
00995       in_rgn = 0;
00996 
00997     if (!real_rgn)
00998       lazy_rgn->DoneRgn(rgn);
00999 
01000     return in_rgn;
01001   }
01002 #endif
01003 #ifdef wx_mac
01004   {
01005     Point p;
01006     p.h = ix;
01007     p.v = iy;
01008     return PtInRgn(p, rgn);
01009   }
01010 #endif
01011 }
01012 
01013 void wxRegion::Install(long target, Bool align)
01014 {
01015   if (prgn) {
01016     Bool oe;
01017 
01018 #ifdef WX_USE_CAIRO
01019     cairo_new_path(CAIRO_DEV);
01020 #endif
01021 #ifdef wx_mac
01022     CGContextRef cg = (CGContextRef)target;
01023     PathTarget *t;
01024     CGMutablePathRef path;
01025     
01026     path = CGPathCreateMutable();
01027   
01028     t = (PathTarget *)malloc(sizeof(PathTarget));
01029     t->path = path;
01030     t->cg = cg;
01031     
01032     target = (long)t;
01033 #endif
01034 #ifdef wx_msw
01035     Graphics *g = (Graphics *)target;
01036     GraphicsPath *gp;
01037     PathTarget *t;
01038 
01039     gp = wxGPathNew(FillModeAlternate);
01040 
01041     t = (PathTarget *)malloc(sizeof(PathTarget));
01042     t->path = gp;
01043     t->g = g;
01044     t->did_one = 0;
01045 
01046     target = (long)t;
01047 #endif
01048 
01049     oe = prgn->Install(target, 0, align);
01050 
01051 #ifdef WX_USE_CAIRO
01052     if (oe)
01053       cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_EVEN_ODD);
01054     cairo_clip(CAIRO_DEV);
01055     if (oe)
01056       cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_WINDING);
01057     cairo_new_path(CAIRO_DEV);
01058 #endif
01059 #ifdef wx_mac
01060     CGContextBeginPath(cg);
01061     CGContextAddPath(cg, t->path);
01062     if (oe)
01063       CGContextEOClip(cg);
01064     else
01065       CGContextClip(cg);
01066     CGPathRelease(t->path);
01067     free(t);
01068 #endif
01069 #ifdef wx_msw
01070     wxGSetClip(g, t->path, t->did_one ? CombineModeIntersect : CombineModeReplace);
01071     wxGPathRelease(t->path);
01072     free(t);
01073 #endif
01074   } else {
01075     /* Empty region: */
01076 #ifdef WX_USE_CAIRO
01077     cairo_new_path(CAIRO_DEV);
01078     /* Empty path confuses some versions of Cairo, so
01079        clip to two non-overlapping regions */
01080     cairo_move_to(CAIRO_DEV, 0, 0);
01081     cairo_line_to(CAIRO_DEV, 1, 0);
01082     cairo_line_to(CAIRO_DEV, 1, 1);
01083     cairo_clip(CAIRO_DEV);
01084     cairo_new_path(CAIRO_DEV);
01085     cairo_move_to(CAIRO_DEV, 2, 2);
01086     cairo_line_to(CAIRO_DEV, 3, 2);
01087     cairo_line_to(CAIRO_DEV, 3, 3);
01088     cairo_clip(CAIRO_DEV);
01089 #endif
01090 #ifdef wx_mac
01091     {
01092       CGContextRef cg = (CGContextRef)target;
01093       CGRect r;
01094       r.origin.x = 0;
01095       r.origin.y = 0;
01096       r.size.width = 0;
01097       r.size.height = 0;
01098       CGContextClipToRect(cg, r);
01099     }
01100 #endif
01101 #ifdef wx_msw
01102     {
01103       GraphicsPath *gp;
01104       Graphics *g = (Graphics *)target;
01105       gp = wxGPathNew(FillModeAlternate);
01106       wxGSetClip(g, gp, CombineModeReplace);
01107       wxGPathRelease(gp);
01108     }
01109 #endif
01110   }
01111 }
01112 
01113 void wxRegion::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01114 {
01115   Bool oe;
01116 
01117   if (!prgn) return; /* shouldn't happen */
01118 
01119   s->Out("newpath\n");
01120 
01121   oe = prgn->InstallPS(dc, s);
01122 
01123   if (oe)
01124     s->Out("eoclip\n");
01125   else
01126     s->Out("clip\n");
01127 }
01128 
01129 /***************************************************************************************/
01130 
01131 #ifdef wx_mac
01132 static CGAffineTransform current_xform;
01133 #endif
01134 #ifdef wx_msw
01135 static GraphicsPath *current_path;
01136 #endif
01137 
01138 wxPathRgn::wxPathRgn(wxDC *dc)
01139 : wxObject(FALSE)
01140 {
01141   if (dc) {
01142     double x, y, xs, ys;
01143     dc->GetDeviceOrigin(&x, &y);
01144     dc->GetUserScale(&xs, &ys);
01145     ox = x;
01146     oy = y;
01147     sx = xs;
01148     sy = ys;
01149   } else {
01150     ox = oy = 0.0;
01151     sx = sy = 1.0;
01152   }
01153   is_rect = 0;
01154 }
01155 
01156 wxPathRgn::~wxPathRgn()
01157 { 
01158   /* If anything important is added here, change constructor chaining
01159      to wxObject from FALSE to TRUE. Beware that wxPaths can share
01160      wxPathRgns. */
01161 }
01162 
01163 double wxPathRgn::XFormX(double _x, Bool align)
01164 {
01165   if (align)
01166     return floor((_x * sx) + ox) + 0.5;
01167   else
01168     return _x;
01169 }
01170 
01171 double wxPathRgn::XFormY(double _y, Bool align)
01172 {
01173   if (align)
01174     return floor((_y * sy) + oy) + 0.5;
01175   else
01176     return _y;
01177 }
01178 
01179 double wxPathRgn::XFormXB(double _x, Bool align)
01180 {
01181   if (align)
01182     return floor((_x * sx) + ox);
01183   else
01184     return _x;
01185 }
01186 
01187 double wxPathRgn::XFormYB(double _y, Bool align)
01188 {
01189   if (align)
01190     return floor((_y * sy) + oy);
01191   else
01192     return _y;
01193 }
01194 
01195 double wxPathRgn::XFormW(double _w, double _x, Bool align)
01196 {
01197   if (align)
01198     return floor(((_x + _w) * sx) + ox) - floor((_x * sx) + ox);
01199   else
01200     return _w;
01201 }
01202 
01203 double wxPathRgn::XFormH(double _h, double _y, Bool align)
01204 {
01205   if (align)
01206     return floor(((_y + _h) * sy) + oy) - floor((_y * sy) + oy);
01207   else
01208     return _h;
01209 }
01210 
01211 void wxPathRgn::PrepareScale(long target, Bool oe, Bool align, void *_m)
01212 {
01213 #ifdef wx_xt
01214 # ifdef WX_USE_CAIRO
01215   if (!align) {
01216     cairo_matrix_p *m = (cairo_matrix_p *)_m;
01217     cairo_set_matrix_create(*m);
01218     cairo_current_matrix(CAIRO_DEV, *m);
01219     cairo_default_matrix(CAIRO_DEV);
01220     cairo_translate(CAIRO_DEV, ox, oy);
01221     cairo_scale(CAIRO_DEV, sx, sy);
01222   }
01223 # endif
01224 #endif
01225 #ifdef wx_mac
01226   if (align) {
01227     current_xform = CGAffineTransformMakeTranslation(0, 0);
01228   } else {
01229     current_xform = CGAffineTransformMakeTranslation(ox, oy);
01230     current_xform = CGAffineTransformScale(current_xform, sx, sy);
01231   }
01232 #endif
01233 #ifdef wx_msw
01234   current_path = wxGPathNew(oe ?  FillModeAlternate : FillModeWinding);
01235 #endif
01236 }
01237 
01238 void wxPathRgn::RestoreScale(long target, Bool align, void *_m)
01239 {
01240 #ifdef WX_USE_CAIRO
01241   if (!align) {
01242     cairo_matrix_p *m = (cairo_matrix_p *)_m;
01243     cairo__set_matrix(CAIRO_DEV, *m);
01244     cairo_matrix_destroy(*m);
01245   }
01246 #endif
01247 #ifdef wx_mac
01248 #endif
01249 #ifdef wx_msw
01250   if (!align) {
01251     Matrix *m;
01252     m = wxGMatrixNew();
01253     wxGMatrixTranslate(m, ox, oy);
01254     wxGMatrixScale(m, sx, sy);
01255     wxGPathTransform(current_path, m);
01256     wxGMatrixRelease(m);
01257   }
01258   wxGPathAddPath(GP, current_path, TRUE);
01259   wxGPathRelease(current_path);
01260 #endif
01261 }
01262 
01263 
01264 wxRectanglePathRgn::wxRectanglePathRgn(wxDC *dc_for_scale, double _x, double _y, double _width, double _height)
01265 : wxPathRgn(dc_for_scale)
01266 {
01267   x = _x;
01268   y = _y;
01269   width = _width;
01270   height = _height;
01271   is_rect = 1;
01272 }
01273 
01274 Bool wxRectanglePathRgn::Install(long target, Bool reverse, Bool align)
01275 {
01276   double xx, yy, ww, hh;
01277   cairo_matrix_p m;
01278 
01279   PrepareScale(target, TRUE, align, &m);
01280 
01281   xx = XFormXB(x, align);
01282   yy = XFormYB(y, align);
01283   ww = XFormW(width, x, align);
01284   hh = XFormH(height, y, align);
01285 
01286 #ifdef WX_USE_CAIRO
01287   cairo_move_to(CAIRO_DEV, xx, yy);
01288   if (reverse) {
01289     cairo_rel_line_to(CAIRO_DEV, 0, hh);
01290     cairo_rel_line_to(CAIRO_DEV, ww, 0);
01291     cairo_rel_line_to(CAIRO_DEV, 0, -hh);
01292   } else {
01293     cairo_rel_line_to(CAIRO_DEV, ww, 0);
01294     cairo_rel_line_to(CAIRO_DEV, 0, hh);
01295     cairo_rel_line_to(CAIRO_DEV, -ww, 0);
01296   }
01297   cairo_close_path(CAIRO_DEV);
01298 #endif
01299 #ifdef wx_mac
01300   CGPathMoveToPoint(CGPATH, CGXFORM, xx, yy);
01301   if (reverse) {
01302     CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + hh);
01303     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + hh);
01304     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy);
01305   } else {
01306     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy);
01307     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + hh);
01308     CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + hh);
01309   }
01310   CGPathCloseSubpath(CGPATH);
01311 #endif
01312 #ifdef wx_msw
01313   if (reverse) {
01314     wxGPathAddLine(CURRENT_GP, xx, yy, xx, yy + hh);
01315     wxGPathAddLine(CURRENT_GP, xx, yy + hh, xx + ww, yy + hh);
01316     wxGPathAddLine(CURRENT_GP, xx + ww, yy + hh, xx + ww, yy);
01317   } else {
01318     wxGPathAddLine(CURRENT_GP, xx, yy, xx + ww, yy);
01319     wxGPathAddLine(CURRENT_GP, xx + ww, yy, xx + ww, yy + hh);
01320     wxGPathAddLine(CURRENT_GP, xx + ww, yy + hh, xx, yy + hh);
01321   }
01322   wxGPathCloseFigure(CURRENT_GP);
01323 #endif
01324 
01325   RestoreScale(target, align, &m);
01326   
01327   return FALSE;
01328 }
01329 
01330 Bool wxRectanglePathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01331 {
01332   double xx, yy, ww, hh;
01333 
01334   xx = dc->FsLogicalToDeviceX(x, ox, sx);
01335   yy = dc->FsLogicalToDeviceY(y, oy, sy);
01336   ww = dc->FsLogicalToDeviceXRel(width, ox, sx);
01337   hh = dc->FsLogicalToDeviceYRel(height, oy, sy);
01338 
01339   s->Out(xx); s->Out(" "); s->Out(yy); s->Out(" moveto\n");
01340   s->Out(xx + ww); s->Out(" "); s->Out(yy); s->Out(" lineto\n");
01341   s->Out(xx + ww); s->Out(" "); s->Out(yy - hh); s->Out(" lineto\n");
01342   s->Out(xx); s->Out(" "); s->Out(yy - hh); s->Out(" lineto\n");
01343   s->Out("closepath\n");
01344 
01345   return FALSE;
01346 }
01347 
01348 wxRoundedRectanglePathRgn::wxRoundedRectanglePathRgn(wxDC *dc_for_scale, 
01349                                                double _x, double _y, double _width, double _height, double _radius)
01350 : wxPathRgn(dc_for_scale)
01351 {
01352   x = _x;
01353   y = _y;
01354   width = _width;
01355   height = _height;
01356   radius = _radius;
01357 
01358   if (radius < 0) {
01359     radius = -radius;
01360     if (width > height)
01361       radius = radius * height;
01362     else
01363       radius = radius * width;
01364   }
01365 }
01366 
01367 Bool wxRoundedRectanglePathRgn::Install(long target, Bool reverse, Bool align)
01368 {
01369   double xx, yy, ww, hh, rr, rr2;
01370   cairo_matrix_p m;
01371   
01372   PrepareScale(target, TRUE, align, &m);
01373 
01374   xx = XFormXB(x, align);
01375   yy = XFormYB(y, align);
01376   ww = XFormW(width, x, align);
01377   hh = XFormH(height, y, align);
01378   
01379   rr = XFormW(radius, 0, align);
01380   rr2 = XFormH(radius, 0, align);
01381   if (rr2 < rr)
01382     rr = rr2;
01383 
01384 #ifdef WX_USE_CAIRO
01385   {
01386     if (reverse) {
01387       cairo_move_to(CAIRO_DEV, xx, yy + rr);
01388       cairo_line_to(CAIRO_DEV, xx, yy + hh - rr);
01389       cairo_arc_negative(CAIRO_DEV, xx + rr, yy + hh - rr, rr, wxPI, 0.5 * wxPI);
01390       cairo_line_to(CAIRO_DEV, xx + ww - rr, yy + hh);
01391       cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + hh - rr, rr, 0.5 * wxPI, 0);
01392       cairo_line_to(CAIRO_DEV, xx + ww, yy + rr);
01393       cairo_arc_negative(CAIRO_DEV, xx + ww - rr, yy + rr, rr, 2 * wxPI, 1.5 * wxPI);
01394       cairo_line_to(CAIRO_DEV, xx + rr, yy);
01395       cairo_arc_negative(CAIRO_DEV, xx + rr, yy + rr, rr, 1.5 * wxPI, wxPI);
01396       cairo_line_to(CAIRO_DEV, xx, yy + rr);
01397     } else {
01398       cairo_move_to(CAIRO_DEV, xx, yy + rr);
01399       cairo_arc(CAIRO_DEV, xx + rr, yy + rr, rr, wxPI, 1.5 * wxPI);
01400       cairo_line_to(CAIRO_DEV, xx + ww - rr, yy);
01401       cairo_arc(CAIRO_DEV, xx + ww - rr, yy + rr, rr, 1.5 * wxPI, 2 * wxPI);
01402       cairo_line_to(CAIRO_DEV, xx + ww, yy + hh - rr);
01403       cairo_arc(CAIRO_DEV, xx + ww - rr, yy + hh - rr, rr, 0, 0.5 * wxPI);
01404       cairo_line_to(CAIRO_DEV, xx + rr, yy + hh);
01405       cairo_arc(CAIRO_DEV, xx + rr, yy + hh - rr, rr, 0.5 * wxPI, wxPI);
01406       cairo_line_to(CAIRO_DEV, xx, yy + rr);
01407     }
01408     cairo_close_path(CAIRO_DEV);
01409   }
01410 #endif
01411 #ifdef wx_mac
01412   if (reverse) {
01413     CGPathMoveToPoint(CGPATH, CGXFORM, xx + rr, yy);
01414     CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + rr, rr, 1.5 * wxPI, 1.0 * wxPI, TRUE);
01415     CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + hh - rr);
01416     CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + hh - rr, rr, 1.0 * wxPI, 0.5 * wxPI, TRUE);
01417     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww - rr, yy + hh);
01418     CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + hh - rr, rr, 0.5 * wxPI, 0, TRUE);
01419     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + rr);
01420     CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + rr, rr, 2 * wxPI, 1.5 * wxPI, TRUE);
01421   } else {
01422     CGPathMoveToPoint(CGPATH, CGXFORM, xx + rr, yy);
01423     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww - rr, yy);
01424     CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + rr, rr, 1.5 * wxPI, 2 * wxPI, FALSE);
01425     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + ww, yy + hh - rr);
01426     CGPathAddArc(CGPATH, CGXFORM, xx + ww - rr, yy + hh - rr, rr, 0, 0.5 * wxPI, FALSE);
01427     CGPathAddLineToPoint(CGPATH, CGXFORM, xx + rr, yy + hh);
01428     CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + hh - rr, rr, 0.5 * wxPI, 1.0 * wxPI, FALSE);
01429     CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy + rr);
01430     CGPathAddArc(CGPATH, CGXFORM, xx + rr, yy + rr, rr, 1.0 * wxPI, 1.5 * wxPI, FALSE);
01431   }
01432   CGPathCloseSubpath(CGPATH);
01433 #endif
01434 #ifdef wx_msw
01435   if (reverse) {
01436     wxGPathAddArc(CURRENT_GP, xx, yy, rr * 2, rr * 2, 270, -90);
01437     wxGPathAddLine(CURRENT_GP, xx, yy + rr, xx, yy + hh - rr);
01438     wxGPathAddArc(CURRENT_GP, xx, yy + hh - 2 * rr, 2 * rr, 2 * rr, 180, -90);
01439     wxGPathAddLine(CURRENT_GP, xx + rr, yy + hh, xx + ww - rr, yy + hh);
01440     wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy + hh - 2 * rr, 2 * rr, 2 * rr, 90, -90);
01441     wxGPathAddLine(CURRENT_GP, xx + ww, yy + hh - rr, xx + ww, yy + rr);
01442     wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy, rr * 2, rr * 2, 360, -90);
01443   } else {
01444     wxGPathAddArc(CURRENT_GP, xx, yy, rr * 2, rr * 2, 180, 90);
01445     wxGPathAddLine(CURRENT_GP, xx + rr, yy, xx + ww - rr, yy);
01446     wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy, rr * 2, rr * 2, 270, 90);
01447     wxGPathAddLine(CURRENT_GP, xx + ww, yy + rr, xx + ww, yy + hh - rr);
01448     wxGPathAddArc(CURRENT_GP, xx + ww - 2 * rr, yy + hh - 2 * rr, 2 * rr, 2 * rr, 0, 90);
01449     wxGPathAddLine(CURRENT_GP, xx + ww - rr, yy + hh, xx + rr, yy + hh);
01450     wxGPathAddArc(CURRENT_GP, xx, yy + hh - 2 * rr, 2 * rr, 2 * rr, 90, 90);
01451   }
01452   wxGPathCloseFigure(CURRENT_GP);
01453 #endif
01454 
01455   RestoreScale(target, align, &m);
01456 
01457   return FALSE;
01458 }
01459 
01460 Bool wxRoundedRectanglePathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01461 {
01462   double xx, yy, ww, hh, rr;
01463 
01464   xx = dc->FsLogicalToDeviceX(x, ox, sx);
01465   yy = dc->FsLogicalToDeviceY(y, oy, sy);
01466   ww = dc->FsLogicalToDeviceXRel(width, ox, sx);
01467   hh = dc->FsLogicalToDeviceYRel(height, oy, sy);
01468   if (sx > sy)
01469     rr = dc->FsLogicalToDeviceYRel(radius, oy, sy);
01470   else
01471     rr = dc->FsLogicalToDeviceXRel(radius, ox, sx);
01472 
01473   hh = -hh;
01474 
01475   s->Out(xx + rr); s->Out(" "); 
01476   s->Out(yy); s->Out(" moveto\n");
01477   
01478   s->Out(xx + rr); s->Out(" ");
01479   s->Out(yy - rr); s->Out(" "); 
01480   s->Out(rr); s->Out(" 90 180 arc\n");
01481   
01482   s->Out(xx + rr); s->Out(" ");
01483   s->Out(yy + hh + rr); s->Out(" "); 
01484   s->Out(rr); s->Out(" 180 270 arc\n");
01485   
01486   s->Out(xx + ww - rr); s->Out(" ");
01487   s->Out(yy + hh + rr); s->Out(" "); 
01488   s->Out(rr); s->Out(" 270 0 arc\n");
01489   
01490   s->Out(xx + ww - rr); s->Out(" ");
01491   s->Out(yy - rr); s->Out(" "); 
01492   s->Out(rr); s->Out(" 0 90 arc\n");
01493 
01494   s->Out("closepath\n");
01495 
01496   return FALSE;
01497 }
01498 
01499 wxPolygonPathRgn::wxPolygonPathRgn(wxDC *dc_for_scale,
01500                                int _n, wxPoint _points[], double _xoffset, double _yoffset, int _fillStyle)
01501 : wxPathRgn(dc_for_scale)
01502 {
01503   n = _n;
01504   points = _points;
01505   xoffset = _xoffset;
01506   yoffset = _yoffset;
01507   fillStyle = _fillStyle;
01508 }
01509 
01510 Bool wxPolygonPathRgn::Install(long target, Bool reverse, Bool align)
01511 {
01512 #if defined(WX_USE_CAIRO) || defined(wx_msw) || defined(wx_mac)
01513   double xx, yy;
01514 #endif
01515   cairo_matrix_p m;
01516 
01517   PrepareScale(target, fillStyle == wxODDEVEN_RULE, align, &m);
01518 
01519 #ifdef WX_USE_CAIRO
01520   if (reverse) {
01521     int i;
01522     xx = XFormX(points[n-1].x + xoffset, align);
01523     yy = XFormY(points[n-1].y + yoffset, align);
01524     cairo_move_to(CAIRO_DEV, xx, yy);
01525     for (i = n-1; i--; ) {
01526       xx = XFormX(points[i].x + xoffset, align);
01527       yy = XFormY(points[i].y + yoffset, align);
01528       cairo_line_to(CAIRO_DEV, xx, yy);
01529     }
01530   } else {
01531     int i;
01532     xx = XFormX(points[0].x + xoffset, align);
01533     yy = XFormY(points[0].y + yoffset, align);
01534     cairo_move_to(CAIRO_DEV, xx, yy);
01535     for (i = 1; i < n; i++) {
01536       xx = XFormX(points[i].x + xoffset, align);
01537       yy = XFormY(points[i].y + yoffset, align);
01538       cairo_line_to(CAIRO_DEV, xx, yy);
01539     }
01540   }
01541   cairo_close_path(CAIRO_DEV);
01542 #endif
01543 #ifdef wx_mac
01544   if (reverse) {
01545     int i;
01546     xx = XFormX(points[n-1].x + xoffset, align);
01547     yy = XFormY(points[n-1].y + yoffset, align);
01548     CGPathMoveToPoint(CGPATH, CGXFORM, xx, yy);
01549     for (i = n-1; i--; ) {
01550       xx = XFormX(points[i].x + xoffset, align);
01551       yy = XFormY(points[i].y + yoffset, align);
01552       CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy);
01553     }
01554   } else {
01555     int i;
01556     xx = XFormX(points[0].x + xoffset, align);
01557     yy = XFormY(points[0].y + yoffset, align);
01558     CGPathMoveToPoint(CGPATH, CGXFORM, xx, yy);
01559     for (i = 1; i < n; i++) {
01560       xx = XFormX(points[i].x + xoffset, align);
01561       yy = XFormY(points[i].y + yoffset, align);
01562       CGPathAddLineToPoint(CGPATH, CGXFORM, xx, yy);
01563     }
01564   }
01565   CGPathCloseSubpath(CGPATH);
01566 #endif
01567 #ifdef wx_msw
01568   if (reverse) {
01569     int i;
01570     double xx2, yy2;
01571     for (i = n - 1; i--; ) {
01572       xx = XFormX(points[i+1].x + xoffset, align);
01573       yy = XFormY(points[i+1].y + yoffset, align);
01574       xx2 = XFormX(points[i].x + xoffset, align);
01575       yy2 = XFormY(points[i].y + yoffset, align);
01576       wxGPathAddLine(CURRENT_GP, xx, yy, xx2, yy2);
01577     }
01578   } else {
01579     int i;
01580        double xx2, yy2;
01581     for (i = 0; i < n - 1; i++) {
01582       xx = XFormX(points[i].x + xoffset, align);
01583       yy = XFormY(points[i].y + yoffset, align);
01584       xx2 = XFormX(points[i+1].x + xoffset, align);
01585       yy2 = XFormY(points[i+1].y + yoffset, align);
01586       wxGPathAddLine(CURRENT_GP, xx, yy, xx2, yy2);
01587     }
01588   }
01589   wxGPathCloseFigure(CURRENT_GP);
01590 #endif
01591 
01592   RestoreScale(target, align, &m);
01593 
01594   return (fillStyle == wxODDEVEN_RULE);
01595 }
01596 
01597 Bool wxPolygonPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01598 {
01599   double xx, yy;
01600   int i;
01601 
01602   xx = dc->FsLogicalToDeviceX(points[0].x + xoffset, ox, sx);
01603   yy = dc->FsLogicalToDeviceY(points[0].y + yoffset, oy, sy);
01604   s->Out(xx); s->Out(" "); 
01605   s->Out(yy); s->Out(" moveto\n");
01606 
01607   for (i = 1; i < n; i++) {
01608     xx = dc->FsLogicalToDeviceX(points[i].x + xoffset, ox, sx);
01609     yy = dc->FsLogicalToDeviceY(points[i].y + yoffset, oy, sy);
01610     s->Out(xx); s->Out(" "); 
01611     s->Out(yy); s->Out(" lineto\n");
01612   }
01613   s->Out("closepath\n");
01614 
01615   return (fillStyle == wxODDEVEN_RULE);
01616 }
01617 
01618 
01619 wxPathPathRgn::wxPathPathRgn(wxDC *dc_for_scale,
01620                           wxPath *_p, double _xoffset, double _yoffset, int _fillStyle)
01621 : wxPathRgn(dc_for_scale)
01622 {
01623   p = new WXGC_PTRS wxPath();
01624   p->AddPath(_p);
01625   p->Translate(_xoffset, _yoffset);
01626   fillStyle = _fillStyle;
01627 }
01628 
01629 Bool wxPathPathRgn::Install(long target, Bool reverse, Bool align)
01630 {
01631   wxPath *q;
01632   cairo_matrix_p m;
01633 
01634   PrepareScale(target, fillStyle == wxODDEVEN_RULE, align, &m);
01635 
01636   if (reverse) {
01637     q = new WXGC_PTRS wxPath();
01638     q->AddPath(p);
01639     q->Reverse();
01640   } else
01641     q = p;
01642 
01643   if (align) {
01644 #ifdef WX_USE_CAIRO
01645     q->Install(target, 0, 0, ox, oy, sx, sy, TRUE, 0.5, 0.5);
01646 #endif
01647 #ifdef wx_mac
01648     q->Install((long)CGPATH, 0, 0, ox, oy, sx, sy, TRUE, 0.5, 0.5);
01649 #endif
01650 #ifdef wx_msw
01651     q->Install((long)CURRENT_GP, 0, 0, ox, oy, sx, sy, TRUE, 0, 0);
01652 #endif
01653   } else {
01654 #ifdef WX_USE_CAIRO
01655     q->Install(target, 0, 0, 0, 0, 1, 1, FALSE, 0, 0);
01656 #endif
01657 #ifdef wx_mac
01658     q->Install((long)CGPATH, 0, 0, 0, 0, 1, 1, FALSE, 0, 0);
01659 #endif
01660 #ifdef wx_msw
01661     q->Install((long)CURRENT_GP, 0, 0, 0, 0, 1, 1, FALSE, 0, 0);
01662 #endif
01663   }
01664 
01665   RestoreScale(target, align, &m);
01666 
01667   return (fillStyle == wxODDEVEN_RULE);
01668 }
01669 
01670 Bool wxPathPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01671 {
01672   p->InstallPS(dc, s, 0, 0);
01673   return (fillStyle == wxODDEVEN_RULE);
01674 }
01675 
01676 wxArcPathRgn::wxArcPathRgn(wxDC *dc_for_scale,
01677                         double _x, double _y, double _w, double _h, double _start, double _end)
01678 : wxPathRgn(dc_for_scale)
01679 {
01680   x = _x;
01681   y = _y;
01682   w = _w;
01683   h = _h;
01684   start = _start;
01685   end = _end;
01686 }
01687 
01688 Bool wxArcPathRgn::Install(long target, Bool reverse, Bool align)
01689 {
01690   double xx, yy, ww, hh;
01691   cairo_matrix_p m;
01692 
01693   PrepareScale(target, TRUE, align, &m);
01694 
01695   xx = XFormXB(x, align);
01696   yy = XFormYB(y, align);
01697   ww = XFormW(w, x, align);
01698   hh = XFormH(h, y, align);  
01699 
01700 #ifdef WX_USE_CAIRO
01701   {
01702     cairo_translate(CAIRO_DEV, xx, yy);
01703     cairo_scale(CAIRO_DEV, ww, hh);
01704     if ((start != 0.0) || (end != (2 * wxPI)))
01705       cairo_move_to(CAIRO_DEV, 0.5, 0.5);
01706     if (!reverse)
01707       cairo_arc(CAIRO_DEV, 0.5, 0.5, 0.5, -end, -start);
01708     else
01709       cairo_arc_negative(CAIRO_DEV, 0.5, 0.5, 0.5, -start, -end);
01710     cairo_close_path(CAIRO_DEV);
01711   }
01712 #endif
01713 #ifdef wx_mac
01714   {
01715     CGAffineTransform xform;
01716     xform = CGAffineTransformTranslate(*CGXFORM, xx, yy);
01717     xform = CGAffineTransformScale(xform, ww, hh);
01718     if ((start != 0.0) || (end != (2 * wxPI)))
01719       CGPathMoveToPoint(CGPATH, &xform, 0.5, 0.5);
01720     if (!reverse)
01721       CGPathAddArc(CGPATH, &xform, 0.5, 0.5, 0.5, (2 * wxPI) - end, (2 * wxPI) - start, FALSE);
01722     else
01723       CGPathAddArc(CGPATH, &xform, 0.5, 0.5, 0.5, (2 * wxPI) - start, (2 * wxPI) - end, TRUE);
01724     CGPathCloseSubpath(CGPATH);
01725   }
01726 #endif
01727 #ifdef wx_msw
01728   {
01729     double init, span;
01730     if ((start == 0.0) && (end == 2 * wxPI)) {
01731       if (reverse) {
01732        wxGPathAddArc(CURRENT_GP, xx, yy, ww, hh, 360.0, -360.0);
01733       } else {
01734        wxGPathAddArc(CURRENT_GP, xx, yy, ww, hh, 0.0, 360.0);
01735       }
01736     } else {
01737       init = (2 * wxPI - start) * 180 / wxPI;
01738       init = fmod(init, 360.0);
01739       if (init < 0.0)
01740        init += 360.0;
01741       
01742       span = (start - end) * 180 / wxPI;
01743       span = fmod(span, 360.0);
01744       if (span > 0)
01745        span -= 360.0;
01746       if (reverse) {
01747        wxGPathAddPie(CURRENT_GP, xx, yy, ww, hh, init + span, -span);
01748       } else {
01749        wxGPathAddPie(CURRENT_GP, xx, yy, ww, hh, init, span);
01750       }
01751     }
01752     wxGPathCloseFigure(CURRENT_GP);
01753   }
01754 #endif
01755 
01756   RestoreScale(target, align, &m);
01757 
01758   return FALSE;
01759 }
01760 
01761 Bool wxArcPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01762 {
01763   double xx, yy, ww, hh;
01764 
01765   xx = dc->FsLogicalToDeviceX(x, ox, sx);
01766   yy = dc->FsLogicalToDeviceY(y, oy, sy);
01767   ww = dc->FsLogicalToDeviceXRel(w, ox, sx);
01768   hh = dc->FsLogicalToDeviceYRel(h, oy, sy);
01769 
01770   s->Out("matrix currentmatrix ");
01771   s->Out(xx + ww/2); s->Out(" "); s->Out(yy - hh/2); s->Out(" translate ");
01772   s->Out(ww); s->Out(" "); s->Out(hh); s->Out(" scale\n");
01773   if ((start != 0) || (end != 2 * wxPI)) {
01774     s->Out("0 0 moveto\n");
01775   }
01776   s->Out("0 0 0.5 "); 
01777   s->Out(start * 180 / wxPI); s->Out(" "); 
01778   s->Out(end * 180 / wxPI); s->Out(" arc setmatrix closepath\n");
01779   
01780   return FALSE;
01781 }
01782 
01783 
01784 wxUnionPathRgn::wxUnionPathRgn(wxPathRgn *_f, wxPathRgn *_s)
01785 : wxPathRgn(NULL)
01786 {
01787   if (!_f || !_s)
01788     abort();
01789   a = _f;
01790   b = _s;
01791 }
01792 
01793 Bool wxUnionPathRgn::Install(long target, Bool reverse, Bool align)
01794 {
01795   Bool aoe, boe;
01796 
01797   aoe = a->Install(target, reverse, align);
01798   boe = b->Install(target, reverse, align);
01799 
01800   return aoe || boe;
01801 }
01802 
01803 Bool wxUnionPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01804 {
01805   Bool aoe, boe;
01806 
01807   aoe = a->InstallPS(dc, s);
01808   boe = b->InstallPS(dc, s);
01809 
01810   return aoe || boe;
01811 }
01812 
01813 wxIntersectPathRgn::wxIntersectPathRgn(wxPathRgn *_f, wxPathRgn *_s)
01814 : wxPathRgn(NULL)
01815 {
01816   if (!_f || !_s)
01817     abort();
01818   a = _f;
01819   b = _s;
01820 }
01821 
01822 Bool wxIntersectPathRgn::Install(long target, Bool reverse, Bool align)
01823 {
01824   Bool aoe;
01825 
01826   aoe = a->Install(target, reverse, align);
01827 
01828 #ifdef WX_USE_CAIRO
01829   if (aoe)
01830     cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_EVEN_ODD);
01831   cairo_clip(CAIRO_DEV);
01832   if (aoe)
01833     cairo_set_fill_rule(CAIRO_DEV, CAIRO_FILL_RULE_WINDING);
01834   cairo_new_path(CAIRO_DEV);
01835 #endif
01836 #if defined(wx_mac)
01837   CGContextBeginPath(CGCG);
01838   CGContextAddPath(CGCG, CGPATH);
01839   if (aoe)
01840     CGContextEOClip(CGCG);
01841   else
01842     CGContextClip(CGCG);
01843   CGPathRelease(CGPATH);
01844   {
01845     CGMutablePathRef p;
01846     p = CGPathCreateMutable();
01847     CGPATH = p;
01848   }
01849 #endif
01850 #if defined(wx_msw)
01851   wxGSetClip(GP_G, GP, GP_DID_ONE ? CombineModeIntersect : CombineModeReplace);
01852   GP_DID_ONE = 1;
01853   wxGPathRelease(GP);
01854   {
01855     GraphicsPath *p;
01856     p = wxGPathNew(FillModeAlternate);
01857     GP = p;
01858   }
01859 #endif
01860 
01861   return b->Install(target, reverse, align);
01862 }
01863 
01864 Bool wxIntersectPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01865 {
01866   Bool aoe;
01867 
01868   aoe = a->InstallPS(dc, s);
01869   if (aoe)
01870     s->Out("eoclip\n");
01871   else
01872     s->Out("clip\n");
01873   
01874   return b->InstallPS(dc, s);
01875 }
01876   
01877 
01878 wxDiffPathRgn::wxDiffPathRgn(wxPathRgn *_f, wxPathRgn *_s)
01879 : wxPathRgn(NULL)
01880 {
01881   if (!_f || !_s)
01882     abort();
01883   a = _f;
01884   b = _s;
01885 }
01886 
01887 Bool wxDiffPathRgn::Install(long target, Bool reverse, Bool align)
01888 {
01889   Bool aoe, boe;
01890 
01891   aoe = a->Install(target, reverse, align);
01892   boe = b->Install(target, !reverse, align);
01893 
01894   return aoe || boe;
01895 }
01896 
01897 Bool wxDiffPathRgn::InstallPS(wxPostScriptDC *dc, wxPSStream *s)
01898 {
01899   Bool aoe, boe;
01900 
01901   aoe = a->InstallPS(dc, s);
01902   s->Out("reversepath\n");
01903   boe = b->InstallPS(dc, s);
01904   s->Out("reversepath\n");
01905 
01906   return aoe || boe;
01907 }
01908 
01909 /********************************************************/
01910 /*                        Paths                         */
01911 /********************************************************/
01912 
01913 #define CMD_CLOSE        1.0
01914 #define CMD_MOVE         2.0
01915 #define CMD_LINE         3.0
01916 #define CMD_CURVE        4.0
01917 
01918 #define ROTATE_XY(x, y) { xtmp1 = x; ytmp1 = y;             \
01919                           xtmp2 = (xx * xtmp1) + (xy * ytmp1); \
01920                           ytmp2 = (yy * ytmp1) + (yx * xtmp1); \
01921                           x = xtmp2; y = ytmp2; }
01922 
01923 wxPath::wxPath()
01924 {
01925   Reset();
01926 }
01927 
01928 wxPath::~wxPath()
01929 {
01930   Reset();
01931 }
01932 
01933 void wxPath::Reset()
01934 {
01935   ClearCache();
01936   cmd_size = 0;
01937   alloc_cmd_size = 0;
01938   cmds = NULL;
01939   last_cmd = -1;
01940 }
01941 
01942 void wxPath::ClearCache()
01943 {
01944   poly_pts = NULL;
01945 }
01946 
01947 void wxPath::MakeRoom(int n)
01948 {
01949   ClearCache();
01950   if (cmd_size + n > alloc_cmd_size) {
01951     double *a;
01952     int s;
01953     s = 2 * (alloc_cmd_size + n);
01954     a = new WXGC_ATOMIC double[s];
01955     memcpy(a, cmds, sizeof(double) * cmd_size);
01956     cmds = a;
01957     alloc_cmd_size = s;
01958   }
01959 }
01960 
01961 Bool wxPath::IsOpen()
01962 {
01963   return ((last_cmd > -1) && (cmds[last_cmd] != CMD_CLOSE));
01964 }
01965 
01966 void wxPath::Close()
01967 {
01968   if ((last_cmd > -1) && (cmds[last_cmd] != CMD_CLOSE)) {
01969     MakeRoom(1);
01970     last_cmd = cmd_size;
01971     cmds[cmd_size++] = CMD_CLOSE;
01972   }
01973 }
01974 
01975 void wxPath::MoveTo(double x, double y)
01976 {
01977   Close();
01978 
01979   MakeRoom(3);
01980   last_cmd = cmd_size;
01981   cmds[cmd_size++] = CMD_MOVE;
01982   cmds[cmd_size++] = x;
01983   cmds[cmd_size++] = y;
01984 }
01985 
01986 void wxPath::LineTo(double x, double y)
01987 {
01988   MakeRoom(3);
01989   last_cmd = cmd_size;
01990   cmds[cmd_size++] = CMD_LINE;
01991   cmds[cmd_size++] = x;
01992   cmds[cmd_size++] = y;
01993 }
01994 
01995 void wxPath::Arc(double x, double y, double w, double h, double start, double end, Bool ccw)
01996 {
01997   double delta, angle, rotate;
01998   double x0, y0, x1, y1, x2, y2, x3, y3;
01999   double xx, xy, yy, yx, xtmp1, ytmp1, xtmp2, ytmp2;
02000   int did_one = 0, start_cmd = cmd_size, start_open;
02001 
02002   start_open = IsOpen();
02003 
02004   /* The arc below is backwards from the MrEd API.... */
02005   {
02006     double s;
02007     s = start;
02008     start = end;
02009     end = s;
02010   }
02011 
02012   if (ccw) {
02013     double s;
02014     s = start;
02015     start = end;
02016     end = s;
02017   }
02018 
02019   delta = end - start;
02020   if (delta > 2 * wxPI)
02021     delta = 2 * wxPI;
02022   else if (delta < 0) {
02023     delta = fmod(delta, 2 * wxPI);
02024     delta += 2 * wxPI;
02025   }
02026 
02027   /* At this point, delta is between 0 and 2pi */
02028   
02029   if (delta == 2 * wxPI)
02030     start = 0;
02031 
02032   /* Change top-left to center: */
02033   x += w/2;
02034   y += h/2;
02035 
02036   /* Make up to 4 curves to represent the arc. */
02037   do {
02038     if (delta > (wxPI / 2))
02039       angle = (wxPI / 2);
02040     else
02041       angle = delta;
02042 
02043     /* First generate points for an arc
02044        of `angle' length from -angle/2 to
02045        +angle/2. */
02046 
02047     x0  = cos(angle / 2);
02048     y0  = sin(angle / 2);
02049     x1 = (4 - x0) / 3;
02050     y1 = ((1 - x0) * (3 - x0)) / (3 * y0);
02051     x2 = x1;
02052     y2 = -y1;
02053     x3 = x0;
02054     y3 = -y0;
02055     
02056     /* Rotate to start: */
02057     rotate = start + (angle / 2);
02058     xx = cos(rotate);
02059     xy = sin(rotate);
02060     yy = xx;
02061     yx = -xy;
02062     ROTATE_XY(x0, y0);
02063     ROTATE_XY(x1, y1);
02064     ROTATE_XY(x2, y2);
02065     ROTATE_XY(x3, y3);
02066 
02067     /* Scale and move to match ellipse: */
02068     x0 = (x0 * w/2) + x;
02069     x1 = (x1 * w/2) + x;
02070     x2 = (x2 * w/2) + x;
02071     x3 = (x3 * w/2) + x;
02072 
02073     y0 = (y0 * h/2) + y;
02074     y1 = (y1 * h/2) + y;
02075     y2 = (y2 * h/2) + y;
02076     y3 = (y3 * h/2) + y;
02077 
02078     if (!did_one) {
02079       if (IsOpen()) {
02080        LineTo(x0, y0);
02081       } else {
02082        MoveTo(x0, y0);
02083       }
02084     }
02085 
02086     if (angle)
02087       CurveTo(x1, y1, x2, y2, x3, y3);
02088     else
02089       LineTo(x3, y3);
02090     
02091     start += angle;
02092     delta -= angle;
02093     did_one = 1;
02094   } while (delta > 0);
02095 
02096   if (!ccw) {
02097     Reverse(start_cmd, start_open);
02098   }
02099 }
02100 
02101 void wxPath::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
02102 {
02103   MakeRoom(7);
02104   last_cmd = cmd_size;
02105   cmds[cmd_size++] = CMD_CURVE;
02106   cmds[cmd_size++] = x1;
02107   cmds[cmd_size++] = y1;
02108   cmds[cmd_size++] = x2;
02109   cmds[cmd_size++] = y2;
02110   cmds[cmd_size++] = x3;
02111   cmds[cmd_size++] = y3;
02112 }
02113 
02114 void wxPath::Rectangle(double x, double y, double width, double height)
02115 {
02116   MoveTo(x, y);
02117   LineTo(x + width, y);
02118   LineTo(x + width, y + height);
02119   LineTo(x, y + height);
02120   Close();
02121 }
02122 
02123 void wxPath::RoundedRectangle(double x, double y, double width, double height, double radius)
02124 {
02125   // A negative radius value is interpreted to mean
02126   // 'the proportion of the smallest X or Y dimension'
02127   if (radius < 0.0) {
02128     double smallest = 0.0;
02129     if (width < height)
02130       smallest = width;
02131     else
02132       smallest = height;
02133     radius = (double)(- radius * smallest);
02134   }
02135     
02136   Close();
02137   Arc(x, y, radius * 2, radius * 2, wxPI, 0.5 * wxPI, FALSE);
02138   LineTo(x + width - radius, y);
02139   Arc(x + width - 2 * radius, y, radius * 2, radius * 2, 0.5 * wxPI, 0 * wxPI, FALSE);
02140   LineTo(x + width, y + height - radius);
02141   Arc(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius, 0 * wxPI, 1.5 * wxPI, FALSE);
02142   LineTo(x + radius, y + height);
02143   Arc(x, y + height - 2 * radius, 2 * radius, 2 * radius, 1.5 * wxPI, 1.0 * wxPI, FALSE);
02144   Close();
02145 }
02146 
02147 void wxPath::Ellipse(double x, double y, double width, double height)
02148 {
02149   Close();
02150   Arc(x, y, width, height, 0, 2 * wxPI, TRUE);
02151   Close();
02152 }
02153 
02154 void wxPath::Lines(int n, wxPoint points[], double xoffset, double yoffset)
02155 {
02156   int i;
02157   for (i = 0; i < n; i++) {
02158     LineTo(points[i].x + xoffset, points[i].y + yoffset);
02159   }
02160 }
02161 
02162 void wxPath::Translate(double x, double y)
02163 {
02164   int i = 0;
02165   while (i < cmd_size) {
02166     if (cmds[i] == CMD_CLOSE) {
02167       i += 1;
02168     } else if ((cmds[i] == CMD_MOVE)
02169               || (cmds[i] == CMD_LINE)) {
02170       cmds[i+1] += x;
02171       cmds[i+2] += y;
02172       i += 3;
02173     } else if (cmds[i] == CMD_CURVE) {
02174       cmds[i+1] += x;
02175       cmds[i+2] += y;
02176       cmds[i+3] += x;
02177       cmds[i+4] += y;
02178       cmds[i+5] += x;
02179       cmds[i+6] += y;
02180       i += 7;
02181     }
02182   }
02183 }
02184 
02185 void wxPath::Scale(double x, double y)
02186 {
02187   int i = 0;
02188   while (i < cmd_size) {
02189     if (cmds[i] == CMD_CLOSE) {
02190       i += 1;
02191     } else if ((cmds[i] == CMD_MOVE)
02192               || (cmds[i] == CMD_LINE)) {
02193       cmds[i+1] *= x;
02194       cmds[i+2] *= y;
02195       i += 3;
02196     } else if (cmds[i] == CMD_CURVE) {
02197       cmds[i+1] *= x;
02198       cmds[i+2] *= y;
02199       cmds[i+3] *= x;
02200       cmds[i+4] *= y;
02201       cmds[i+5] *= x;
02202       cmds[i+6] *= y;
02203       i += 7;
02204     }
02205   }
02206 }
02207 
02208 void wxPath::Rotate(double a)
02209 {
02210   double xx, xy, yy, yx, xtmp1, ytmp1, xtmp2, ytmp2;
02211   int i = 0;
02212 
02213   xx = cos(a);
02214   xy = sin(a);
02215   yy = xx;
02216   yx = -xy;
02217 
02218   while (i < cmd_size) {
02219     if (cmds[i] == CMD_CLOSE) {
02220       i += 1;
02221     } else if ((cmds[i] == CMD_MOVE)
02222               || (cmds[i] == CMD_LINE)) {
02223       ROTATE_XY(cmds[i+1], cmds[i+2]);
02224       i += 3;
02225     } else if (cmds[i] == CMD_CURVE) {
02226       ROTATE_XY(cmds[i+1], cmds[i+2]);
02227       ROTATE_XY(cmds[i+3], cmds[i+4]);
02228       ROTATE_XY(cmds[i+5], cmds[i+6]);
02229       i += 7;
02230     }
02231   }
02232 }
02233 
02234 void wxPath::Reverse(int start_cmd, Bool start_with_line)
02235 {
02236   int e, i, j, pos, n, *cs, controls;
02237   double *a;
02238 
02239   while (start_cmd < cmd_size) {
02240     /* Find next starting point: */
02241     if (cmds[start_cmd] == CMD_CLOSE) {
02242       start_cmd += 1;
02243     }
02244 
02245     i = start_cmd;
02246     n = 0;
02247     while (i < cmd_size) {
02248       if (cmds[i] == CMD_CLOSE) {
02249        break;
02250       } else {
02251        n++;
02252        if (cmds[i] == CMD_MOVE) {
02253          i += 3;
02254        } else if (cmds[i] == CMD_LINE) {
02255          i += 3;
02256        } else if (cmds[i] == CMD_CURVE) {
02257          i += 7;
02258        }
02259       }
02260     }
02261     e = i;
02262 
02263     /* Reverse sub-path in [start_cmd, e) */
02264 
02265     a = new WXGC_ATOMIC double[e - start_cmd];
02266     cs = new WXGC_ATOMIC int[n];
02267 
02268     /* Traverse again to find command starts: */
02269     n = 0;
02270     i = start_cmd;
02271     while (i < e) {
02272       cs[n++] = i;
02273       if (cmds[i] == CMD_MOVE) {
02274        i += 3;
02275       } else if (cmds[i] == CMD_LINE) {
02276        i += 3;
02277       } else if (cmds[i] == CMD_CURVE) {
02278        i += 7;
02279       }
02280     }
02281 
02282     /* Reverse */
02283     controls = -1;
02284     pos = 0;
02285     for (j = n; j--; ) {
02286       i = cs[j];
02287       if (!start_with_line && (j == n - 1)) {
02288        a[pos++] = CMD_MOVE;
02289       } else if (controls >= 0) {
02290        a[pos++] = CMD_CURVE;
02291        a[pos++] = cmds[controls+3];
02292        a[pos++] = cmds[controls+4];
02293        a[pos++] = cmds[controls+1];
02294        a[pos++] = cmds[controls+2];
02295       } else {
02296        a[pos++] = CMD_LINE;
02297       }
02298 
02299       if ((cmds[i] == CMD_MOVE)
02300          || (cmds[i] == CMD_LINE)) {
02301        a[pos++] = cmds[i+1];
02302        a[pos++] = cmds[i+2];
02303        controls = -1;
02304       } else if (cmds[i] == CMD_CURVE) {
02305        a[pos++] = cmds[i+5];
02306        a[pos++] = cmds[i+6];
02307        controls = i;
02308       }
02309     }
02310 
02311     memcpy(cmds + start_cmd, a, (e - start_cmd) * sizeof(double));
02312 
02313     start_cmd = e;
02314   }
02315 }
02316 
02317 void wxPath::AddPath(wxPath *p)
02318 {
02319   int i, closed_n;
02320 
02321   if (!IsOpen()) {
02322     /* Simple case: this path is closed, so just append p */
02323     MakeRoom(p->cmd_size);
02324     last_cmd = cmd_size + p->last_cmd;
02325     for (i = 0; i < p->cmd_size; i++) {
02326       cmds[cmd_size++] = p->cmds[i];
02327     }
02328   } else {
02329     /* Put closed paths in p on the front of this path,
02330        and add unclosed paths to this path's unclosed
02331        path. */
02332     if (p->IsOpen()) {
02333       for (i = 0; i < p->cmd_size; i++) {
02334        if (p->cmds[i] == CMD_CLOSE)
02335          break;
02336        else if (cmds[i] == CMD_CURVE)
02337          i += 7;
02338        else
02339          i += 3;
02340       }
02341       
02342       if (i < p->cmd_size) {
02343        closed_n = i + 1;
02344       } else {
02345        closed_n = 0;
02346       }
02347     } else {
02348       /* No open path in p */
02349       closed_n = p->cmd_size;
02350     }
02351     
02352     MakeRoom(p->cmd_size);
02353     memmove(cmds + closed_n, cmds, cmd_size * sizeof(double));
02354     memcpy(cmds, p->cmds, closed_n * sizeof(double));
02355     if (closed_n  < p->cmd_size) {
02356       /* There was an open path in p... */
02357       memcpy(cmds + cmd_size + closed_n, p->cmds + closed_n, (p->cmd_size - closed_n) * sizeof(double));
02358 
02359       /* p's open path must start with CMD_MOVE; change it to CMD_LINE */
02360       cmds[closed_n + cmd_size] = CMD_LINE;
02361     
02362       last_cmd = cmd_size + p->last_cmd;
02363     } else {
02364       /* No open path in p, so just adjust last_cmd */
02365       last_cmd += closed_n;
02366     }
02367     cmd_size += p->cmd_size;
02368   }
02369 }
02370 
02371 void wxPath::Install(long target, double dx, double dy, 
02372                    double ox, double oy, double sx, double sy,
02373                    Bool align, double pox, double poy)
02374 {
02375   int i = 0;
02376   double lx = 0.0, ly = 0.0, lxx = 0.0, lyy = 0.0;
02377 
02378 #ifdef WX_USE_CAIRO
02379   cairo_new_path(CAIRO_DEV);
02380 #endif
02381 
02382   while (i < cmd_size) {
02383     if (cmds[i] == CMD_CLOSE) {
02384 #ifdef WX_USE_CAIRO
02385       cairo_close_path(CAIRO_DEV);
02386 #endif
02387 #ifdef wx_mac
02388       CGPathCloseSubpath(PATHPATH);;
02389 #endif
02390 #ifdef wx_msw
02391       wxGPathCloseFigure(PATH_GP);
02392 #endif
02393       i += 1;
02394     } else if (cmds[i] == CMD_MOVE) {
02395       double xx, yy;
02396       xx = (cmds[i+1]+dx) * sx + ox;
02397       yy = (cmds[i+2]+dy) * sy + oy;
02398       if (align) {
02399        xx = floor(xx) + pox;
02400        yy = floor(yy) + poy;
02401       }
02402 
02403 #ifdef WX_USE_CAIRO
02404       cairo_move_to(CAIRO_DEV, xx, yy);
02405 #endif
02406 #ifdef wx_mac
02407       CGPathMoveToPoint(PATHPATH, NULL, xx, yy);
02408 #endif
02409 
02410       lx = cmds[i+1];
02411       ly = cmds[i+2];
02412       lxx = xx;
02413       lyy = yy;
02414 
02415       i += 3;
02416     } else if (cmds[i] == CMD_LINE) {
02417       if ((cmds[i+1] != lx) || (cmds[i+2] != ly)) {
02418        double xx, yy;
02419        xx = (cmds[i+1]+dx) * sx + ox;
02420        yy = (cmds[i+2]+dy) * sy + oy;
02421        if (align) {
02422          xx = floor(xx) + pox;
02423          yy = floor(yy) + poy;
02424        }
02425 
02426 #ifdef WX_USE_CAIRO
02427        cairo_line_to(CAIRO_DEV, xx, yy);
02428 #endif
02429 #ifdef wx_mac
02430        CGPathAddLineToPoint(PATHPATH, NULL, xx, yy);
02431 #endif
02432 #ifdef wx_msw
02433        wxGPathAddLine(PATH_GP, lxx, lyy, xx, yy);
02434 #endif
02435 
02436        lx = cmds[i+1];
02437        ly = cmds[i+2];
02438        lxx = xx;
02439        lyy = yy;
02440       }
02441       i += 3;
02442     } else if (cmds[i] == CMD_CURVE) {
02443       if ((cmds[i+5] != lx) || (cmds[i+6] != ly)) {
02444        double xx, yy, xx1, yy1, xx2, yy2;
02445        xx = (cmds[i+5]+dx) * sx + ox;
02446        yy = (cmds[i+6]+dy) * sy + oy;
02447        if (align) {
02448          xx = floor(xx) + pox;
02449          yy = floor(yy) + poy;
02450        }
02451 
02452        xx1 = (cmds[i+1]+dx) * sx + ox;
02453        yy1 = (cmds[i+2]+dy) * sy + oy;
02454        xx2 = (cmds[i+3]+dx) * sx + ox;
02455        yy2 = (cmds[i+4]+dy) * sy + oy;
02456 
02457 #ifdef WX_USE_CAIRO
02458        cairo_curve_to(CAIRO_DEV, xx1, yy1, xx2, yy2, xx, yy);
02459 #endif
02460 #ifdef wx_mac
02461        CGPathAddCurveToPoint(PATHPATH, NULL, xx1, yy1, xx2, yy2, xx, yy);
02462 #endif
02463 #ifdef wx_msw
02464        wxGPathAddBezier(PATH_GP, lxx, lyy, xx1, yy1, xx2, yy2, xx, yy);
02465 #endif
02466        lx = cmds[i+5];
02467        ly = cmds[i+6];
02468        lxx = xx;
02469        lyy = yy;
02470       }
02471       i += 7;
02472     }
02473   }
02474 }
02475 
02476 void wxPath::InstallPS(wxPostScriptDC *dc, wxPSStream *s, double dx, double dy)
02477 {
02478   int i = 0;
02479 
02480   while (i < cmd_size) {
02481     if (cmds[i] == CMD_CLOSE) {
02482       s->Out("closepath\n");
02483       i += 1;
02484     } else if ((cmds[i] == CMD_MOVE) 
02485               || (cmds[i] == CMD_LINE)) {
02486       double x, y;
02487       x = dc->FLogicalToDeviceX(cmds[i+1]+ dx);
02488       y = dc->FLogicalToDeviceY(cmds[i+2]+ dy);
02489       s->Out(x); s->Out(" "); s->Out(y);
02490       if (cmds[i] == CMD_LINE)
02491        s->Out(" lineto\n");
02492       else
02493        s->Out(" moveto\n");
02494       i += 3;
02495     } else if (cmds[i] == CMD_CURVE) {
02496       double x1, y1, x2, y2, x3, y3;
02497       x1 = dc->FLogicalToDeviceX(cmds[i+1] + dx);
02498       y1 = dc->FLogicalToDeviceY(cmds[i+2] + dy);
02499       x2 = dc->FLogicalToDeviceX(cmds[i+3] + dx);
02500       y2 = dc->FLogicalToDeviceY(cmds[i+4] + dy);
02501       x3 = dc->FLogicalToDeviceX(cmds[i+5] + dx);
02502       y3 = dc->FLogicalToDeviceY(cmds[i+6] + dy);
02503       s->Out(x1); s->Out(" "); s->Out(y1); s->Out(" "); 
02504       s->Out(x2); s->Out(" "); s->Out(y2); s->Out(" "); 
02505       s->Out(x3); s->Out(" "); s->Out(y3); s->Out(" "); 
02506       s->Out("curveto\n");
02507       i += 7;
02508     }
02509   }
02510 }
02511 
02512 static double my_round(double d)
02513 {
02514   double i, frac;
02515 
02516   if (d < 0) {
02517     frac = modf(d, &i);
02518     if (frac < -0.5)
02519       return i - 1;
02520     else
02521       return i;
02522   } else {
02523     frac = modf(d, &i);
02524     if (frac < 0.5)
02525       return i;
02526     else
02527       return i + 1;
02528   }
02529 }
02530 
02531 int wxPath::ToPolygons(int **_lens, double ***_ptss, double sx, double sy)
02532 {
02533   int i, cnt, *lens, len, alloc_len, need_len;
02534   double lx, ly, **ptss, *pts, *naya;
02535 
02536   cnt = 0;
02537   for (i = 0; i < cmd_size; ) {
02538     if (cmds[i] == CMD_CLOSE) {
02539       cnt++;
02540       i += 1;
02541     } else if (cmds[i] == CMD_MOVE) {
02542       i += 3;
02543     } else if (cmds[i] == CMD_LINE) {
02544       i += 3;
02545     } else if (cmds[i] == CMD_CURVE) {
02546       i += 7;
02547     }
02548   }
02549 
02550   if (IsOpen())
02551     cnt++;
02552 
02553   ptss = new WXGC_PTRS double*[cnt];
02554   lens = new WXGC_ATOMIC int[cnt];
02555   cnt = 0;
02556 
02557   pts = NULL;
02558   len = 0;
02559   alloc_len = 0;
02560   lx = ly = 0;
02561 
02562   for (i = 0; i < cmd_size; ) {
02563     if (cmds[i] == CMD_CLOSE) {
02564       ptss[cnt] = pts;
02565       lens[cnt] = len;
02566       cnt++;
02567 
02568       len = 0;
02569       alloc_len = 0;
02570       pts = NULL;
02571       lx = ly = 0;
02572 
02573       i += 1;
02574     } else {
02575       if ((cmds[i] == CMD_MOVE)
02576          || (cmds[i] == CMD_LINE)) {
02577        need_len = 1;
02578       } else if (cmds[i] == CMD_CURVE) {
02579        double dx, dy;
02580        dx = sx * (lx - cmds[i + 5]);
02581        dy = sy * (ly - cmds[i + 6]);
02582        if (dx < 0) dx = -dx;
02583        if (dy < 0) dy = -dy;
02584        if (dx > dy)
02585          need_len = (int)ceil(dx);
02586        else
02587          need_len = (int)ceil(dy);
02588        need_len += 1;
02589       } else {
02590        need_len = 0;
02591       }
02592 
02593       if (len + (2 * need_len) > alloc_len) {
02594        int l;
02595        l = (len + (2 * need_len)) * 2;
02596        naya = new WXGC_ATOMIC double[l];
02597        memcpy(naya, pts, len * sizeof(double));
02598        pts = naya;
02599        alloc_len = l;
02600       }
02601 
02602       if ((cmds[i] == CMD_MOVE)
02603          || (cmds[i] == CMD_LINE)) {
02604        lx = cmds[i+1];
02605        ly = cmds[i+2];
02606        pts[len++] = lx;
02607        pts[len++] = ly;
02608        i += 3;
02609       } else if (cmds[i] == CMD_CURVE) {
02610        int d;
02611        double x0 = lx, x1 = cmds[i+1], x2 = cmds[i+3], x3 = cmds[i+5];
02612        double y0 = ly, y1 = cmds[i+2], y2 = cmds[i+4], y3 = cmds[i+6];
02613        double ax = (((x3 - (x2 * 3)) + (x1 * 3)) - x0);
02614        double ay = (((y3 - (y2 * 3)) + (y1 * 3)) - y0);
02615        double bx = (((x2 * 3) - (x1 * 6)) + (x0 * 3));
02616        double by = (((y2 * 3) - (y1 * 6)) + (y0 * 3));
02617        double cx = ((x1 * 3) - (x0 * 3));
02618        double cy = ((y1 * 3) -  (y0 * 3));
02619        double dx = x0, dy = y0, tt, x, y;
02620 
02621        for (d = 0; d < need_len; d++) {
02622          tt = ((double)d / (double)(need_len - 1));
02623          x = ((((((tt * ax) + bx) * tt) + cx) * tt) + dx);
02624          y = ((((((tt * ay) + by) * tt) + cy) * tt) + dy);
02625          if ((d > 0) && (d < need_len-1)) {
02626            /* We've generating points to map to pixels
02627               after scaling, so round intermediate points.
02628               End point have to be floored, for consistency
02629               with everything else, so leave them alone. */
02630            x = my_round(x * sx) / sx;
02631            y = my_round(y * sy) / sy;
02632          }
02633          pts[len++] = x;
02634          pts[len++] = y;
02635        }
02636 
02637        lx = x3;
02638        ly = y3;
02639 
02640        i += 7;
02641       }
02642     }
02643   }
02644 
02645   if (IsOpen()) {
02646     ptss[cnt] = pts;
02647     lens[cnt] = len;
02648     cnt++;
02649   }
02650 
02651   *_lens = lens;
02652   *_ptss = ptss;
02653 
02654   return cnt;
02655 }
02656 
02657 void wxPath::BoundingBox(double *_x1, double *_y1, double *_x2, double *_y2)
02658 {
02659   double x1, x2, y1, y2;
02660   int i;
02661 
02662   if (cmd_size) {
02663     /* First command must be move-to: */
02664     x1 = cmds[1];
02665     y1 = cmds[2];
02666     x2 = x1;
02667     y2 = y1;
02668     for (i = 3; i < cmd_size; ) {
02669       if (cmds[i] == CMD_CLOSE) {
02670        i += 1;
02671       } else if ((cmds[i] == CMD_MOVE)
02672                || (cmds[i] == CMD_LINE)) {
02673        if (cmds[i+1] < x1)
02674          x1 = cmds[i+1];
02675        if (cmds[i+1] > x2)
02676          x2 = cmds[i+1];
02677        if (cmds[i+2] < y1)
02678          y1 = cmds[i+2];
02679        if (cmds[i+2] > y2)
02680          y2 = cmds[i+2];
02681        i += 3;
02682       } else if (cmds[i] == CMD_CURVE) {
02683        int j;
02684        for (j = 0; j < 6; j += 2) {
02685          if (cmds[i+j+1] < x1)
02686            x1 = cmds[i+j+1];
02687          if (cmds[i+j+1] > x2)
02688            x2 = cmds[i+j+1];
02689          if (cmds[i+j+2] < y1)
02690            y1 = cmds[i+j+2];
02691          if (cmds[i+j+2] > y2)
02692            y2 = cmds[i+j+2];
02693        }
02694        i += 7;
02695       }
02696     }
02697   } else {
02698     x1 = y1 = x2 = y2 = 0.0;
02699   }
02700 
02701   *_x1 = x1;
02702   *_x2 = x2;
02703   *_y1 = y1;
02704   *_y2 = y2;
02705 }