1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze 
   7 // Licence:           wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "dcclient.h" 
  14 #include "wx/dcclient.h" 
  15 #include "wx/dcmemory.h" 
  22 //----------------------------------------------------------------------------- 
  24 //----------------------------------------------------------------------------- 
  34 static GdkPixmap  
*hatches
[num_hatches
]; 
  35 static GdkPixmap 
**hatch_bitmap 
= (GdkPixmap 
**) NULL
; 
  37 //----------------------------------------------------------------------------- 
  39 //----------------------------------------------------------------------------- 
  41 #define RAD2DEG 57.2957795131 
  43 //----------------------------------------------------------------------------- 
  44 // temporary implementation of the missing GDK function 
  45 //----------------------------------------------------------------------------- 
  47 #include "gdk/gdkprivate.h" 
  49 void gdk_draw_bitmap     (GdkDrawable  
*drawable
, 
  59     GdkWindowPrivate 
*drawable_private
; 
  60     GdkWindowPrivate 
*src_private
; 
  61     GdkGCPrivate 
*gc_private
; 
  63     g_return_if_fail (drawable 
!= NULL
); 
  64     g_return_if_fail (src 
!= NULL
); 
  65     g_return_if_fail (gc 
!= NULL
); 
  67     drawable_private 
= (GdkWindowPrivate
*) drawable
; 
  68     src_private 
= (GdkWindowPrivate
*) src
; 
  69     if (drawable_private
->destroyed 
|| src_private
->destroyed
) 
  72     gc_private 
= (GdkGCPrivate
*) gc
; 
  74     if (width 
== -1) width 
= src_private
->width
; 
  75     if (height 
== -1) height 
= src_private
->height
; 
  77     XCopyPlane( drawable_private
->xdisplay
, 
  79                 drawable_private
->xwindow
, 
  87 //----------------------------------------------------------------------------- 
  89 //----------------------------------------------------------------------------- 
  91 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
) 
  93 wxWindowDC::wxWindowDC() 
  95     m_penGC 
= (GdkGC 
*) NULL
; 
  96     m_brushGC 
= (GdkGC 
*) NULL
; 
  97     m_textGC 
= (GdkGC 
*) NULL
; 
  98     m_bgGC 
= (GdkGC 
*) NULL
; 
  99     m_cmap 
= (GdkColormap 
*) NULL
; 
 101     m_owner 
= (wxWindow 
*)NULL
; 
 104 wxWindowDC::wxWindowDC( wxWindow 
*window 
) 
 106     m_penGC 
= (GdkGC 
*) NULL
; 
 107     m_brushGC 
= (GdkGC 
*) NULL
; 
 108     m_textGC 
= (GdkGC 
*) NULL
; 
 109     m_bgGC 
= (GdkGC 
*) NULL
; 
 110     m_cmap 
= (GdkColormap 
*) NULL
; 
 111     m_owner 
= (wxWindow 
*)NULL
; 
 114     wxASSERT_MSG( window
, "DC needs a window" ); 
 116     GtkWidget 
*widget 
= window
->m_wxwindow
; 
 118     wxASSERT_MSG( widget
, "DC needs a widget" ); 
 120     m_window 
= widget
->window
; 
 125          /* don't report problems */ 
 131     if (window
->m_wxwindow
) 
 132         m_cmap 
= gtk_widget_get_colormap( window
->m_wxwindow 
); 
 134         m_cmap 
= gtk_widget_get_colormap( window
->m_widget 
); 
 138     /* this must be done after SetUpDC, bacause SetUpDC calls the 
 139        repective SetBrush, SetPen, SetBackground etc functions 
 140        to set up the DC. SetBackground call m_owner->SetBackground 
 141        and this might not be desired as the standard dc background 
 142        is white whereas a window might assume gray to be the 
 143        standard (as e.g. wxStatusBar) */ 
 148 wxWindowDC::~wxWindowDC() 
 153 void wxWindowDC::DoFloodFill( long WXUNUSED(x
), long WXUNUSED(y
),  
 154                            const wxColour 
&WXUNUSED(col
), int WXUNUSED(style
) ) 
 156     wxFAIL_MSG( _T("wxWindowDC::DoFloodFill not implemented") ); 
 159 bool wxWindowDC::DoGetPixel( long WXUNUSED(x1
), long WXUNUSED(y1
), wxColour 
*WXUNUSED(col
) ) const 
 161     wxFAIL_MSG( _T("wxWindowDC::DoGetPixel not implemented") ); 
 165 void wxWindowDC::DoDrawLine( long x1
, long y1
, long x2
, long y2 
) 
 167     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 169     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 172             gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) ); 
 174         CalcBoundingBox(x1
, y1
); 
 175         CalcBoundingBox(x2
, y2
); 
 179 void wxWindowDC::DoCrossHair( long x
, long y 
) 
 181     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 183     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 188         long xx 
= XLOG2DEV(x
); 
 189         long yy 
= YLOG2DEV(y
); 
 192             gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy 
); 
 193             gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) ); 
 198 void wxWindowDC::DoDrawArc( long x1
, long y1
, long x2
, long y2
, 
 201     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 203     long xx1 
= XLOG2DEV(x1
);  
 204     long yy1 
= YLOG2DEV(y1
); 
 205     long xx2 
= XLOG2DEV(x2
);  
 206     long yy2 
= YLOG2DEV(y2
); 
 207     long xxc 
= XLOG2DEV(xc
);  
 208     long yyc 
= YLOG2DEV(yc
); 
 209     double dx 
= xx1 
- xxc
;  
 210     double dy 
= yy1 
- yyc
; 
 211     double radius 
= sqrt(dx
*dx
+dy
*dy
); 
 212     long   r      
= (long)radius
; 
 213     double radius1
, radius2
; 
 215     if (xx1 
== xx2 
&& yy1 
== yy2
)  
 223         radius1 
= radius2 
= 0.0; 
 227         radius1 
= (xx1 
- xxc 
== 0) ? 
 228             (yy1 
- yyc 
< 0) ? 90.0 : -90.0 : 
 229             -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
; 
 230         radius2 
= (xx2 
- xxc 
== 0) ? 
 231             (yy2 
- yyc 
< 0) ? 90.0 : -90.0 : 
 232             -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
; 
 234     long alpha1 
= long(radius1 
* 64.0); 
 235     long alpha2 
= long((radius2 
- radius1
) * 64.0); 
 236     while (alpha2 
<= 0) alpha2 
+= 360*64; 
 237     while (alpha1 
> 360*64) alpha1 
-= 360*64; 
 241         if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 242             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2 
); 
 244         if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 245             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2 
); 
 248     CalcBoundingBox (x1
, y1
); 
 249     CalcBoundingBox (x2
, y2
); 
 252 void wxWindowDC::DoDrawEllipticArc( long x
, long y
, long width
, long height
, double sa
, double ea 
) 
 254     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 256     long xx 
= XLOG2DEV(x
);     
 257     long yy 
= YLOG2DEV(y
); 
 258     long ww 
= m_signX 
* XLOG2DEVREL(width
);  
 259     long hh 
= m_signY 
* YLOG2DEVREL(height
); 
 261     // CMB: handle -ve width and/or height 
 262     if (ww 
< 0) { ww 
= -ww
; xx 
= xx 
- ww
; } 
 263     if (hh 
< 0) { hh 
= -hh
; yy 
= yy 
- hh
; } 
 267         long start 
= long(sa 
* 64.0); 
 268         long end 
= long(ea 
* 64.0); 
 270         if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 271             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end 
); 
 273         if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 274             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end 
); 
 277     CalcBoundingBox (x
, y
); 
 278     CalcBoundingBox (x 
+ width
, y 
+ height
); 
 281 void wxWindowDC::DoDrawPoint( long x
, long y 
) 
 283     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 285     if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
) 
 286         gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) ); 
 288     CalcBoundingBox (x
, y
); 
 291 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], long xoffset
, long yoffset 
) 
 293     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 295     if (m_pen
.GetStyle() == wxTRANSPARENT
) return; 
 298     CalcBoundingBox( points
[0].x 
+ xoffset
, points
[0].y 
+ yoffset 
); 
 300     for (int i 
= 0; i 
< n
-1; i
++) 
 302         long x1 
= XLOG2DEV(points
[i
].x 
+ xoffset
); 
 303         long x2 
= XLOG2DEV(points
[i
+1].x 
+ xoffset
); 
 304         long y1 
= YLOG2DEV(points
[i
].y 
+ yoffset
);     // oh, what a waste 
 305         long y2 
= YLOG2DEV(points
[i
+1].y 
+ yoffset
); 
 307             gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2 
); 
 309         CalcBoundingBox( points
[i
+1].x 
+ xoffset
, points
[i
+1].y 
+ yoffset 
); 
 313 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], long xoffset
, long yoffset
, int WXUNUSED(fillStyle
) ) 
 315     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 319     GdkPoint 
*gdkpoints 
= new GdkPoint
[n
+1]; 
 321     for (i 
= 0 ; i 
< n 
; i
++) 
 323         gdkpoints
[i
].x 
= XLOG2DEV(points
[i
].x 
+ xoffset
); 
 324         gdkpoints
[i
].y 
= YLOG2DEV(points
[i
].y 
+ yoffset
); 
 326         CalcBoundingBox( points
[i
].x 
+ xoffset
, points
[i
].y 
+ yoffset 
); 
 329     if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 330         gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
); 
 334     if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
) 
 336         for (i 
= 0 ; i 
< n 
; i
++) 
 338             gdk_draw_line( m_window
, m_penGC
,  
 341                            gdkpoints
[(i
+1)%n
].x
, 
 342                            gdkpoints
[(i
+1)%n
].y
); 
 349 void wxWindowDC::DoDrawRectangle( long x
, long y
, long width
, long height 
) 
 351     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 353     long xx 
= XLOG2DEV(x
); 
 354     long yy 
= YLOG2DEV(y
); 
 355     long ww 
= m_signX 
* XLOG2DEVREL(width
); 
 356     long hh 
= m_signY 
* YLOG2DEVREL(height
); 
 358     // CMB: draw nothing if transformed w or h is 0 
 359     if (ww 
== 0 || hh 
== 0) return; 
 361     // CMB: handle -ve width and/or height 
 362     if (ww 
< 0) { ww 
= -ww
; xx 
= xx 
- ww
; } 
 363     if (hh 
< 0) { hh 
= -hh
; yy 
= yy 
- hh
; } 
 367         if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 368             gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh 
); 
 370         if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 371             gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 ); 
 374     CalcBoundingBox( x
, y 
); 
 375     CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 378 void wxWindowDC::DoDrawRoundedRectangle( long x
, long y
, long width
, long height
, double radius 
) 
 380     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 382     if (radius 
< 0.0) radius 
= - radius 
* ((width 
< height
) ? width 
: height
); 
 384     long xx 
= XLOG2DEV(x
);     
 385     long yy 
= YLOG2DEV(y
); 
 386     long ww 
= m_signX 
* XLOG2DEVREL(width
);  
 387     long hh 
= m_signY 
* YLOG2DEVREL(height
); 
 388     long rr 
= XLOG2DEVREL((long)radius
); 
 390     // CMB: handle -ve width and/or height 
 391     if (ww 
< 0) { ww 
= -ww
; xx 
= xx 
- ww
; } 
 392     if (hh 
< 0) { hh 
= -hh
; yy 
= yy 
- hh
; } 
 394     // CMB: if radius is zero use DrawRectangle() instead to avoid 
 395     // X drawing errors with small radii 
 398         DrawRectangle( x
, y
, width
, height 
); 
 402     // CMB: draw nothing if transformed w or h is 0 
 403     if (ww 
== 0 || hh 
== 0) return; 
 405     // CMB: adjust size if outline is drawn otherwise the result is 
 406     // 1 pixel too wide and high 
 407     if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 415         // CMB: ensure dd is not larger than rectangle otherwise we 
 416         // get an hour glass shape 
 418         if (dd 
> ww
) dd 
= ww
; 
 419         if (dd 
> hh
) dd 
= hh
; 
 422         if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 424             gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh 
); 
 425             gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 ); 
 426             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 ); 
 427             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 ); 
 428             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 ); 
 429             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 ); 
 432         if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 434             gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy 
); 
 435             gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh 
); 
 436             gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr 
); 
 437             gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr 
); 
 438             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 ); 
 439             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 ); 
 440             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 ); 
 441             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 ); 
 445     // this ignores the radius 
 446     CalcBoundingBox( x
, y 
); 
 447     CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 450 void wxWindowDC::DoDrawEllipse( long x
, long y
, long width
, long height 
) 
 452     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 454     long xx 
= XLOG2DEV(x
);     
 455     long yy 
= YLOG2DEV(y
); 
 456     long ww 
= m_signX 
* XLOG2DEVREL(width
);  
 457     long hh 
= m_signY 
* YLOG2DEVREL(height
); 
 459     // CMB: handle -ve width and/or height 
 460     if (ww 
< 0) { ww 
= -ww
; xx 
= xx 
- ww
; } 
 461     if (hh 
< 0) { hh 
= -hh
; yy 
= yy 
- hh
; } 
 465         if (m_brush
.GetStyle() != wxTRANSPARENT
) 
 466             gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 ); 
 468         if (m_pen
.GetStyle() != wxTRANSPARENT
) 
 469             gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 ); 
 472     CalcBoundingBox( x 
- width
, y 
- height 
); 
 473     CalcBoundingBox( x 
+ width
, y 
+ height 
); 
 476 void wxWindowDC::DoDrawIcon( const wxIcon 
&icon
, long x
, long y 
) 
 478     // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why 
 479     DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE 
); 
 482 void wxWindowDC::DoDrawBitmap( const wxBitmap 
&bitmap
, 
 486     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 488     wxCHECK_RET( bitmap
.Ok(), _T("invalid bitmap") ); 
 490     /* scale/translate size and position */ 
 492     int xx 
= XLOG2DEV(x
); 
 493     int yy 
= YLOG2DEV(y
); 
 495     int w 
= bitmap
.GetWidth(); 
 496     int h 
= bitmap
.GetHeight(); 
 498     CalcBoundingBox( x
, y 
); 
 499     CalcBoundingBox( x 
+ w
, y 
+ h 
); 
 501     if (!m_window
) return; 
 503     int ww 
= XLOG2DEVREL(w
); 
 504     int hh 
= YLOG2DEVREL(h
); 
 506     /* scale bitmap if required */ 
 510     if ((w 
!= ww
) || (h 
!= hh
)) 
 512         wxImage 
image( bitmap 
); 
 513         image 
= image
.Scale( ww
, hh 
); 
 515         use_bitmap 
= image
.ConvertToBitmap(); 
 522     /* apply mask if any */ 
 524     GdkBitmap 
*mask 
= (GdkBitmap 
*) NULL
; 
 525     if (use_bitmap
.GetMask()) mask 
= use_bitmap
.GetMask()->GetBitmap(); 
 529         gdk_gc_set_clip_mask( m_penGC
, mask 
); 
 530         gdk_gc_set_clip_origin( m_penGC
, xx
, yy 
); 
 533     /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */ 
 535     GdkPixmap 
*pm 
= use_bitmap
.GetPixmap(); 
 538         gdk_draw_pixmap( m_window
, m_penGC
, pm
, 0, 0, xx
, yy
, -1, -1 ); 
 542         GdkBitmap 
*bm 
= use_bitmap
.GetBitmap(); 
 545             gdk_draw_bitmap( m_window
, m_penGC
, bm
, 0, 0, xx
, yy
, -1, -1 ); 
 549     /* remove mask again if any */ 
 553         gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap 
*) NULL 
); 
 554         gdk_gc_set_clip_origin( m_penGC
, 0, 0 ); 
 558 bool wxWindowDC::DoBlit( long xdest
, long ydest
, long width
, long height
, 
 559                          wxDC 
*source
, long xsrc
, long ysrc
, 
 560                          int logical_func
, bool useMask 
) 
 562    /* this is the nth try to get this utterly useless function to 
 563       work. it now completely ignores the scaling or translation 
 564       of the source dc, but scales correctly on the target dc and 
 565       knows about possible mask information in a memory dc. */ 
 567     wxCHECK_MSG( Ok(), FALSE
, _T("invalid window dc") ); 
 569     wxCHECK_MSG( source
, FALSE
, _T("invalid source dc") ); 
 571     if (!m_window
) return FALSE
; 
 573     wxClientDC 
*srcDC 
= (wxClientDC
*)source
; 
 574     wxMemoryDC 
*memDC 
= (wxMemoryDC
*)source
; 
 576     bool use_bitmap_method 
= FALSE
; 
 578     if (srcDC
->m_isMemDC
) 
 580         if (!memDC
->m_selected
.Ok()) return FALSE
; 
 582         /* we use the "XCopyArea" way to copy a memory dc into 
 583            y different window if the memory dc BOTH 
 584            a) doesn't have any mask or its mask isn't used 
 588         if (useMask 
&& (memDC
->m_selected
.GetMask())) 
 590            /* we HAVE TO use the direct way for memory dcs 
 591               that have mask since the XCopyArea doesn't know 
 593             use_bitmap_method 
= TRUE
; 
 595         else if (memDC
->m_selected
.GetDepth() == 1) 
 597            /* we HAVE TO use the direct way for memory dcs 
 598               that are bitmaps because XCopyArea doesn't cope 
 599               with different bit depths */ 
 600             use_bitmap_method 
= TRUE
; 
 602         else if ((xsrc 
== 0) && (ysrc 
== 0) && 
 603                  (width 
== memDC
->m_selected
.GetWidth()) && 
 604                  (height 
== memDC
->m_selected
.GetHeight())) 
 606            /* we SHOULD use the direct way if all of the bitmap  
 607               in the memory dc is copied in which case XCopyArea  
 608               wouldn't be able able to boost performace by reducing  
 609               the area to be scaled */ 
 610             use_bitmap_method 
= TRUE
; 
 614             use_bitmap_method 
= FALSE
; 
 618     CalcBoundingBox( xdest
, ydest 
); 
 619     CalcBoundingBox( xdest 
+ width
, ydest 
+ height 
); 
 621     int old_logical_func 
= m_logicalFunction
; 
 622     SetLogicalFunction( logical_func 
); 
 624     if (use_bitmap_method
) 
 626         /* scale/translate bitmap size */ 
 628         long bm_width 
= memDC
->m_selected
.GetWidth(); 
 629         long bm_height 
= memDC
->m_selected
.GetHeight(); 
 631         long bm_ww 
= XLOG2DEVREL( bm_width 
); 
 632         long bm_hh 
= YLOG2DEVREL( bm_height 
); 
 634         /* scale bitmap if required */ 
 638         if ((bm_width 
!= bm_ww
) || (bm_height 
!= bm_hh
)) 
 640             wxImage 
image( memDC
->m_selected 
); 
 641             image 
= image
.Scale( bm_ww
, bm_hh 
); 
 643             use_bitmap 
= image
.ConvertToBitmap(); 
 647             use_bitmap 
= memDC
->m_selected
; 
 650         /* scale/translate size and position */ 
 652         long xx 
= XLOG2DEV(xdest
); 
 653         long yy 
= YLOG2DEV(ydest
); 
 655         long ww 
= XLOG2DEVREL(width
); 
 656         long hh 
= YLOG2DEVREL(height
); 
 658         /* apply mask if any */ 
 660         GdkBitmap 
*mask 
= (GdkBitmap 
*) NULL
; 
 661         if (use_bitmap
.GetMask()) mask 
= use_bitmap
.GetMask()->GetBitmap(); 
 665             gdk_gc_set_clip_mask( m_penGC
, mask 
); 
 666             gdk_gc_set_clip_origin( m_penGC
, xx
, yy 
); 
 669         /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */ 
 671         GdkPixmap 
*pm 
= use_bitmap
.GetPixmap(); 
 674             gdk_draw_pixmap( m_window
, m_penGC
, pm
, xsrc
, ysrc
, xx
, yy
, ww
, hh 
); 
 678             GdkBitmap 
*bm 
= use_bitmap
.GetBitmap(); 
 681                 /* we use the textGC here because blitting a bitmap is done 
 682                    using the current text colour */ 
 683                 gdk_draw_bitmap( m_window
, m_textGC
, bm
, xsrc
, ysrc
, xx
, yy
, ww
, hh 
); 
 687         /* remove mask again if any */ 
 691             gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap 
*) NULL 
); 
 692             gdk_gc_set_clip_origin( m_penGC
, 0, 0 ); 
 695     else /* use_bitmap_method */ 
 697         /* scale/translate size and position */ 
 699         long xx 
= XLOG2DEV(xdest
); 
 700         long yy 
= YLOG2DEV(ydest
); 
 702         long ww 
= XLOG2DEVREL(width
); 
 703         long hh 
= YLOG2DEVREL(height
); 
 705         if ((width 
!= ww
) || (height 
!= hh
)) 
 707             /* draw source window into a bitmap as we cannot scale 
 708                a window in contrast to a bitmap. this would actually 
 709                work with memory dcs as well, but we'd lose the mask 
 710                information and waste one step in this process since 
 711                a memory already has a bitmap. all this is slightly 
 712                inefficient as we could take an XImage directly from 
 713                an X window, but we'd then also have to care that 
 714                the window is not outside the screen (in which case 
 715                we'd get a BadMatch or what not). 
 716                Is a double XGetImage and combined XGetPixel and 
 717                XPutPixel really faster? I'm not sure. look at wxXt 
 718                for a different implementation of the same problem. */ 
 720             wxBitmap 
bitmap( width
, height 
); 
 721             gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,  
 723                                   xsrc
, ysrc
, width
, height 
); 
 727             wxImage 
image( bitmap 
); 
 728             image 
= image
.Scale( ww
, hh 
); 
 730             /* convert to bitmap */ 
 732             bitmap 
= image
.ConvertToBitmap(); 
 734             /* draw scaled bitmap */ 
 736             gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 ); 
 741             /* no scaling and not a memory dc with a mask either */ 
 743             gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
, 
 745                                   xsrc
, ysrc
, width
, height 
); 
 749     SetLogicalFunction( old_logical_func 
); 
 753 void wxWindowDC::DoDrawText( const wxString 
&text
, long x
, long y 
) 
 755     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 757     if (!m_window
) return; 
 759     GdkFont 
*font 
= m_font
.GetInternalFont( m_scaleY 
); 
 764     /* CMB 21/5/98: draw text background if mode is wxSOLID */ 
 765     if (m_backgroundMode 
== wxSOLID
) 
 767         long width 
= gdk_string_width( font
, text
.mbc_str() ); 
 768         long height 
= font
->ascent 
+ font
->descent
; 
 769         gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() ); 
 770         gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height 
); 
 771         gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() ); 
 773     gdk_draw_string( m_window
, font
, m_textGC
, x
, y 
+ font
->ascent
, text
.mbc_str() ); 
 775     /* CMB 17/7/98: simple underline: ignores scaling and underlying 
 776        X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS 
 777        properties (see wxXt implementation) */ 
 778     if (m_font
.GetUnderlined()) 
 780         long width 
= gdk_string_width( font
, text
.mbc_str() ); 
 781         long ul_y 
= y 
+ font
->ascent
; 
 782         if (font
->descent 
> 0) ul_y
++; 
 783         gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x 
+ width
, ul_y
); 
 787     GetTextExtent (text
, &w
, &h
); 
 788     CalcBoundingBox (x 
+ w
, y 
+ h
); 
 789     CalcBoundingBox (x
, y
); 
 792 void wxWindowDC::GetTextExtent( const wxString 
&string
, long *width
, long *height
, 
 793                                 long *descent
, long *externalLeading
, 
 794                                 wxFont 
*theFont 
) const 
 796     wxFont fontToUse 
= m_font
; 
 797     if (theFont
) fontToUse 
= *theFont
; 
 799     GdkFont 
*font 
= fontToUse
.GetInternalFont( m_scaleY 
); 
 800     if (width
) (*width
) = long(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
); 
 801     if (height
) (*height
) = long((font
->ascent 
+ font
->descent
) / m_scaleY
); 
 802     if (descent
) (*descent
) = long(font
->descent 
/ m_scaleY
); 
 803     if (externalLeading
) (*externalLeading
) = 0;  // ?? 
 806 long wxWindowDC::GetCharWidth() const 
 808     GdkFont 
*font 
= m_font
.GetInternalFont( m_scaleY 
); 
 809     return long(gdk_string_width( font
, "H" ) / m_scaleX
); 
 812 long wxWindowDC::GetCharHeight() const 
 814     GdkFont 
*font 
= m_font
.GetInternalFont( m_scaleY 
); 
 815     return long((font
->ascent 
+ font
->descent
) / m_scaleY
); 
 818 void wxWindowDC::Clear() 
 820     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 822     if (!m_window
) return; 
 824     /* - we either are a memory dc or have a window as the 
 825        owner. anything else shouldn't happen. 
 826        - we don't use gdk_window_clear() as we don't set 
 827        the window's background colour anymore. it is too 
 828        much pain to keep the DC's and the window's back- 
 829        ground colour in synch. */ 
 834         m_owner
->GetSize( &width
, &height 
); 
 835         gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height 
); 
 842         GetSize( &width
, &height 
); 
 843         gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height 
); 
 848 void wxWindowDC::SetFont( const wxFont 
&font 
) 
 853 void wxWindowDC::SetPen( const wxPen 
&pen 
) 
 855     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 857     if (m_pen 
== pen
) return; 
 861     if (!m_pen
.Ok()) return; 
 863     if (!m_window
) return; 
 865     gint width 
= m_pen
.GetWidth(); 
 866     // CMB: if width is non-zero scale it with the dc 
 873         // X doesn't allow different width in x and y and so we take 
 875         double w 
= 0.5 + (abs(XLOG2DEVREL(width
)) + abs(YLOG2DEVREL(width
))) / 2.0; 
 879     GdkLineStyle lineStyle 
= GDK_LINE_SOLID
; 
 880     switch (m_pen
.GetStyle()) 
 882         case wxSOLID
:      { lineStyle 
= GDK_LINE_SOLID
;       break; } 
 883         case wxDOT
:        { lineStyle 
= GDK_LINE_ON_OFF_DASH
; break; } 
 884         case wxLONG_DASH
:  { lineStyle 
= GDK_LINE_ON_OFF_DASH
; break; } 
 885         case wxSHORT_DASH
: { lineStyle 
= GDK_LINE_ON_OFF_DASH
; break; } 
 886         case wxDOT_DASH
:   { lineStyle 
= GDK_LINE_DOUBLE_DASH
; break; } 
 889     GdkCapStyle capStyle 
= GDK_CAP_ROUND
; 
 890     switch (m_pen
.GetCap()) 
 892         case wxCAP_ROUND
:      { capStyle 
= (width 
<= 1) ? GDK_CAP_NOT_LAST 
: GDK_CAP_ROUND
; break; } 
 893         case wxCAP_PROJECTING
: { capStyle 
= GDK_CAP_PROJECTING
; break; } 
 894         case wxCAP_BUTT
:       { capStyle 
= GDK_CAP_BUTT
;       break; } 
 897     GdkJoinStyle joinStyle 
= GDK_JOIN_ROUND
; 
 898     switch (m_pen
.GetJoin()) 
 900         case wxJOIN_BEVEL
: { joinStyle 
= GDK_JOIN_BEVEL
; break; } 
 901         case wxJOIN_ROUND
: { joinStyle 
= GDK_JOIN_ROUND
; break; } 
 902         case wxJOIN_MITER
: { joinStyle 
= GDK_JOIN_MITER
; break; } 
 905     gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle 
); 
 907     m_pen
.GetColour().CalcPixel( m_cmap 
); 
 908     gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() ); 
 911 void wxWindowDC::SetBrush( const wxBrush 
&brush 
) 
 913     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 915     if (m_brush 
== brush
) return; 
 919     if (!m_brush
.Ok()) return; 
 921     if (!m_window
) return; 
 923     m_brush
.GetColour().CalcPixel( m_cmap 
); 
 924     gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() ); 
 926     GdkFill fillStyle 
= GDK_SOLID
; 
 927     switch (m_brush
.GetStyle()) 
 933          fillStyle 
= GDK_STIPPLED
; 
 936     gdk_gc_set_fill( m_brushGC
, fillStyle 
); 
 938     if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok())) 
 940         if (m_brush
.GetStipple()->GetPixmap()) 
 941             gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetPixmap() ); 
 943             gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() ); 
 946     if (IS_HATCH(m_brush
.GetStyle())) 
 948         int num 
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
; 
 949         gdk_gc_set_stipple( m_brushGC
, hatches
[num
] ); 
 953 void wxWindowDC::SetBackground( const wxBrush 
&brush 
) 
 955    /* CMB 21/7/98: Added SetBackground. Sets background brush 
 956     * for Clear() and bg colour for shapes filled with cross-hatch brush */ 
 958     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
 960     if (m_backgroundBrush 
== brush
) return; 
 962     m_backgroundBrush 
= brush
; 
 964     if (!m_backgroundBrush
.Ok()) return; 
 966     if (!m_window
) return; 
 968     m_backgroundBrush
.GetColour().CalcPixel( m_cmap 
); 
 969     gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() ); 
 970     gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() ); 
 971     gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() ); 
 972     gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() ); 
 974     GdkFill fillStyle 
= GDK_SOLID
; 
 975     switch (m_backgroundBrush
.GetStyle()) 
 981             fillStyle 
= GDK_STIPPLED
; 
 984     gdk_gc_set_fill( m_bgGC
, fillStyle 
); 
 986     if (m_backgroundBrush
.GetStyle() == wxSTIPPLE
) 
 988         gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() ); 
 991     if (IS_HATCH(m_backgroundBrush
.GetStyle())) 
 993         int num 
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
; 
 994         gdk_gc_set_stipple( m_bgGC
, hatches
[num
] ); 
 998 void wxWindowDC::SetLogicalFunction( int function 
) 
1000     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1002     if (m_logicalFunction 
== function
) return; 
1004     GdkFunction mode 
= GDK_COPY
; 
1007         case wxXOR
:          mode 
= GDK_XOR
;           break; 
1008         case wxINVERT
:       mode 
= GDK_INVERT
;        break; 
1009 #if (GTK_MINOR_VERSION > 0) 
1010         case wxOR_REVERSE
:   mode 
= GDK_OR_REVERSE
;    break; 
1011         case wxAND_REVERSE
:  mode 
= GDK_AND_REVERSE
;   break; 
1012         case wxCLEAR
:        mode 
= GDK_CLEAR
;         break; 
1013         case wxSET
:          mode 
= GDK_SET
;           break; 
1014         case wxOR_INVERT
:    mode 
= GDK_OR_INVERT
;     break; 
1016         case wxAND
:          mode 
= GDK_AND
;           break; 
1018         case wxOR
:           mode 
= GDK_OR
;            break; 
1019         case wxEQUIV
:        mode 
= GDK_EQUIV
;         break; 
1020         case wxNAND
:         mode 
= GDK_NAND
;          break; 
1021         case wxAND_INVERT
:   mode 
= GDK_AND_INVERT
;    break; 
1022         case wxCOPY
:         mode 
= GDK_COPY
;          break; 
1023         case wxNO_OP
:        mode 
= GDK_NOOP
;          break; 
1024         case wxSRC_INVERT
:   mode 
= GDK_COPY_INVERT
;   break; 
1028            wxFAIL_MSG( "unsupported logical function" ); 
1033     m_logicalFunction 
= function
; 
1035     if (!m_window
) return; 
1037     gdk_gc_set_function( m_penGC
, mode 
); 
1038     gdk_gc_set_function( m_brushGC
, mode 
); 
1039     gdk_gc_set_function( m_textGC
, mode 
); 
1042 void wxWindowDC::SetTextForeground( const wxColour 
&col 
) 
1044     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1046     if (m_textForegroundColour 
== col
) return; 
1048     m_textForegroundColour 
= col
; 
1049     if (!m_textForegroundColour
.Ok()) return; 
1051     if (!m_window
) return; 
1053     m_textForegroundColour
.CalcPixel( m_cmap 
); 
1054     gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() ); 
1057 void wxWindowDC::SetTextBackground( const wxColour 
&col 
) 
1059     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1061     if (m_textBackgroundColour 
== col
) return; 
1063     m_textBackgroundColour 
= col
; 
1064     if (!m_textBackgroundColour
.Ok()) return; 
1066     if (!m_window
) return; 
1068     m_textBackgroundColour
.CalcPixel( m_cmap 
); 
1069     gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() ); 
1072 void wxWindowDC::SetBackgroundMode( int mode 
) 
1074     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1076     m_backgroundMode 
= mode
; 
1078     if (!m_window
) return; 
1080     // CMB 21/7/98: fill style of cross-hatch brushes is affected by 
1081     // transparent/solid background mode 
1083     if (m_brush
.GetStyle() != wxSOLID 
&& m_brush
.GetStyle() != wxTRANSPARENT
) 
1085         gdk_gc_set_fill( m_brushGC
, 
1086           (m_backgroundMode 
== wxTRANSPARENT
) ? GDK_STIPPLED 
: GDK_OPAQUE_STIPPLED
); 
1090 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) ) 
1092     wxFAIL_MSG( _T("wxWindowDC::SetPalette not implemented") ); 
1095 void wxWindowDC::DoSetClippingRegion( long x
, long y
, long width
, long height 
) 
1097     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1099     wxDC::DoSetClippingRegion( x
, y
, width
, height 
); 
1101     if (!m_window
) return; 
1104     rect
.x 
= XLOG2DEV(x
); 
1105     rect
.y 
= YLOG2DEV(y
); 
1106     rect
.width 
= XLOG2DEVREL(width
); 
1107     rect
.height 
= YLOG2DEVREL(height
); 
1108     gdk_gc_set_clip_rectangle( m_penGC
, &rect 
); 
1109     gdk_gc_set_clip_rectangle( m_brushGC
, &rect 
); 
1110     gdk_gc_set_clip_rectangle( m_textGC
, &rect 
); 
1111     gdk_gc_set_clip_rectangle( m_bgGC
, &rect 
); 
1114 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion 
®ion  
) 
1116     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1120         DestroyClippingRegion(); 
1124     if (!m_window
) return; 
1126     gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() ); 
1127     gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() ); 
1128     gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() ); 
1129     gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() ); 
1132 void wxWindowDC::DestroyClippingRegion() 
1134     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1136     wxDC::DestroyClippingRegion(); 
1138     if (!m_window
) return; 
1140     gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle 
*) NULL 
); 
1141     gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle 
*) NULL 
); 
1142     gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle 
*) NULL 
); 
1143     gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle 
*) NULL 
); 
1146 void wxWindowDC::SetUpDC() 
1150     m_logicalFunction 
= wxCOPY
; 
1151     m_penGC 
= gdk_gc_new( m_window 
); 
1152     m_brushGC 
= gdk_gc_new( m_window 
); 
1153     m_textGC 
= gdk_gc_new( m_window 
); 
1154     m_bgGC 
= gdk_gc_new( m_window 
); 
1156     wxColour 
tmp_col( m_textForegroundColour 
); 
1157     m_textForegroundColour 
= wxNullColour
; 
1158     SetTextForeground( tmp_col 
); 
1159     tmp_col 
= m_textBackgroundColour
; 
1160     m_textBackgroundColour 
= wxNullColour
; 
1161     SetTextBackground( tmp_col 
); 
1163     wxPen 
tmp_pen( m_pen 
); 
1167     wxFont 
tmp_font( m_font 
); 
1168     m_font 
= wxNullFont
; 
1169     SetFont( tmp_font 
); 
1171     wxBrush 
tmp_brush( m_brush 
); 
1172     m_brush 
= wxNullBrush
; 
1173     SetBrush( tmp_brush 
); 
1175     tmp_brush 
= m_backgroundBrush
; 
1176     m_backgroundBrush 
= wxNullBrush
; 
1177     SetBackground( tmp_brush 
); 
1181         hatch_bitmap    
= hatches
; 
1182         hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow 
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height 
); 
1183         hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow 
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height 
); 
1184         hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow 
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height 
); 
1185         hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow 
*) NULL
, cross_bits
, cross_width
, cross_height 
); 
1186         hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow 
*) NULL
, horiz_bits
, horiz_width
, horiz_height 
); 
1187         hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow 
*) NULL
, verti_bits
, verti_width
, verti_height 
); 
1191 void wxWindowDC::Destroy() 
1193     if (m_penGC
) gdk_gc_unref( m_penGC 
); 
1194     m_penGC 
= (GdkGC
*) NULL
; 
1195     if (m_brushGC
) gdk_gc_unref( m_brushGC 
); 
1196     m_brushGC 
= (GdkGC
*) NULL
; 
1197     if (m_textGC
) gdk_gc_unref( m_textGC 
); 
1198     m_textGC 
= (GdkGC
*) NULL
; 
1199     if (m_bgGC
) gdk_gc_unref( m_bgGC 
); 
1200     m_bgGC 
= (GdkGC
*) NULL
; 
1203 void wxWindowDC::ComputeScaleAndOrigin() 
1205     /* CMB: copy scale to see if it changes */ 
1206     double origScaleX 
= m_scaleX
; 
1207     double origScaleY 
= m_scaleY
; 
1209     wxDC::ComputeScaleAndOrigin(); 
1211     /* CMB: if scale has changed call SetPen to recalulate the line width */ 
1212     if ((m_scaleX 
!= origScaleX 
|| m_scaleY 
!= origScaleY
) && 
1215       /* this is a bit artificial, but we need to force wxDC to think 
1216          the pen has changed */ 
1223 // Resolution in pixels per logical inch 
1224 wxSize 
wxWindowDC::GetPPI() const 
1226     return wxSize(100, 100); 
1229 int wxWindowDC::GetDepth() const 
1231     wxFAIL_MSG(_T("not implemented")); 
1237 // ----------------------------------- spline code ---------------------------------------- 
1239 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
1240                          double a3
, double b3
, double a4
, double b4
); 
1241 void wx_clear_stack(); 
1242 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
1243         double *y3
, double *x4
, double *y4
); 
1244 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
1245           double x4
, double y4
); 
1246 static bool wx_spline_add_point(double x
, double y
); 
1247 static void wx_spline_draw_point_array(wxDC 
*dc
); 
1249 wxList wx_spline_point_list
; 
1251 #define                half(z1, z2)        ((z1+z2)/2.0) 
1254 /* iterative version */ 
1256 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
1259     register double  xmid
, ymid
; 
1260     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1263     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
1265     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
1266         xmid 
= (double)half(x2
, x3
); 
1267         ymid 
= (double)half(y2
, y3
); 
1268         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
1269             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
1270             wx_spline_add_point( x1
, y1 
); 
1271             wx_spline_add_point( xmid
, ymid 
); 
1273             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
1274                  (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
1275             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
1276                  (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
1281 /* utilities used by spline drawing routines */ 
1283 typedef struct wx_spline_stack_struct 
{ 
1284     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1287 #define         SPLINE_STACK_DEPTH             20 
1288 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
1289 static Stack   
*wx_stack_top
; 
1290 static int      wx_stack_count
; 
1292 void wx_clear_stack() 
1294     wx_stack_top 
= wx_spline_stack
; 
1298 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
1300     wx_stack_top
->x1 
= x1
; 
1301     wx_stack_top
->y1 
= y1
; 
1302     wx_stack_top
->x2 
= x2
; 
1303     wx_stack_top
->y2 
= y2
; 
1304     wx_stack_top
->x3 
= x3
; 
1305     wx_stack_top
->y3 
= y3
; 
1306     wx_stack_top
->x4 
= x4
; 
1307     wx_stack_top
->y4 
= y4
; 
1312 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
1313                   double *x3
, double *y3
, double *x4
, double *y4
) 
1315     if (wx_stack_count 
== 0) 
1319     *x1 
= wx_stack_top
->x1
; 
1320     *y1 
= wx_stack_top
->y1
; 
1321     *x2 
= wx_stack_top
->x2
; 
1322     *y2 
= wx_stack_top
->y2
; 
1323     *x3 
= wx_stack_top
->x3
; 
1324     *y3 
= wx_stack_top
->y3
; 
1325     *x4 
= wx_stack_top
->x4
; 
1326     *y4 
= wx_stack_top
->y4
; 
1330 static bool wx_spline_add_point(double x
, double y
) 
1332   wxPoint 
*point 
= new wxPoint 
; 
1335   wx_spline_point_list
.Append((wxObject
*)point
); 
1339 static void wx_spline_draw_point_array(wxDC 
*dc
) 
1341   dc
->DrawLines(&wx_spline_point_list
, 0, 0 ); 
1342   wxNode 
*node 
= wx_spline_point_list
.First(); 
1345     wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
1348     node 
= wx_spline_point_list
.First(); 
1352 void wxWindowDC::DoDrawSpline( wxList 
*points 
) 
1354     wxCHECK_RET( Ok(), _T("invalid window dc") ); 
1357     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
1358     double           x1
, y1
, x2
, y2
; 
1360     wxNode 
*node 
= points
->First(); 
1361     p 
= (wxPoint 
*)node
->Data(); 
1366     node 
= node
->Next(); 
1367     p 
= (wxPoint 
*)node
->Data(); 
1371     cx1 
= (double)((x1 
+ x2
) / 2); 
1372     cy1 
= (double)((y1 
+ y2
) / 2); 
1373     cx2 
= (double)((cx1 
+ x2
) / 2); 
1374     cy2 
= (double)((cy1 
+ y2
) / 2); 
1376     wx_spline_add_point(x1
, y1
); 
1378     while ((node 
= node
->Next()) != NULL
) 
1380         p 
= (wxPoint 
*)node
->Data(); 
1385         cx4 
= (double)(x1 
+ x2
) / 2; 
1386         cy4 
= (double)(y1 
+ y2
) / 2; 
1387         cx3 
= (double)(x1 
+ cx4
) / 2; 
1388         cy3 
= (double)(y1 
+ cy4
) / 2; 
1390         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
1394         cx2 
= (double)(cx1 
+ x2
) / 2; 
1395         cy2 
= (double)(cy1 
+ y2
) / 2; 
1398     wx_spline_add_point( cx1
, cy1 
); 
1399     wx_spline_add_point( x2
, y2 
); 
1401     wx_spline_draw_point_array( this ); 
1404 #endif // wxUSE_SPLINE 
1406 //----------------------------------------------------------------------------- 
1408 //----------------------------------------------------------------------------- 
1410 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
) 
1412 wxPaintDC::wxPaintDC() 
1417 wxPaintDC::wxPaintDC( wxWindow 
*win 
) 
1422 //----------------------------------------------------------------------------- 
1424 //----------------------------------------------------------------------------- 
1426 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
) 
1428 wxClientDC::wxClientDC() 
1433 wxClientDC::wxClientDC( wxWindow 
*win 
)