1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  21     #pragma implementation "dc.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  32     #include "wx/window.h" 
  35     #include "wx/dialog.h" 
  37     #include "wx/bitmap.h" 
  38     #include "wx/dcmemory.h" 
  43 #include "wx/dcprint.h" 
  48 #if wxUSE_COMMON_DIALOGS 
  56 #include "wx/msw/private.h" 
  58 #if !USE_SHARED_LIBRARY 
  59     IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
) 
  62 // --------------------------------------------------------------------------- 
  64 // --------------------------------------------------------------------------- 
  66 static const int VIEWPORT_EXTENT 
= 1000; 
  68 static const int MM_POINTS 
= 9; 
  69 static const int MM_METRIC 
= 10; 
  71 // --------------------------------------------------------------------------- 
  73 // --------------------------------------------------------------------------- 
  77 #define XLOG2DEV(x) (x) 
  78 #define YLOG2DEV(y) (y) 
  81 #define XLOG2DEVREL(x) (x) 
  82 #define YLOG2DEVREL(y) (y) 
  86 #define XDEV2LOG(x) (x) 
  88 #define YDEV2LOG(y) (y) 
  91 #define XDEV2LOGREL(x) (x) 
  92 #define YDEV2LOGREL(y) (y) 
  95  * Have the same macros as for XView but not for every operation: 
  96  * just for calculating window/viewport extent (a better way of scaling). 
 101 #define MS_XLOG2DEV(x) LogicalToDevice(x) 
 103 #define MS_YLOG2DEV(y) LogicalToDevice(y) 
 106 #define MS_XLOG2DEVREL(x) LogicalToDeviceXRel(x) 
 107 #define MS_YLOG2DEVREL(y) LogicalToDeviceYRel(y) 
 111 #define MS_XDEV2LOG(x) DeviceToLogicalX(x) 
 113 #define MS_YDEV2LOG(y) DeviceToLogicalY(y) 
 116 #define MS_XDEV2LOGREL(x) DeviceToLogicalXRel(x) 
 117 #define MS_YDEV2LOGREL(y) DeviceToLogicalYRel(y) 
 119 #define YSCALE(y) (yorigin - (y)) 
 121 #define     wx_round(a)    (int)((a)+.5) 
 123 // =========================================================================== 
 125 // =========================================================================== 
 127 // --------------------------------------------------------------------------- 
 129 // --------------------------------------------------------------------------- 
 131 // Default constructor 
 145     m_windowExtX 
= VIEWPORT_EXTENT
; 
 146     m_windowExtY 
= VIEWPORT_EXTENT
; 
 155         SelectOldObjects(m_hDC
); 
 157             if ( m_canvas 
== NULL 
) 
 158                 ::DeleteDC(GetHdc()); 
 160                 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc()); 
 166 // This will select current objects out of the DC, 
 167 // which is what you have to do before deleting the 
 169 void wxDC::SelectOldObjects(WXHDC dc
) 
 175             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 176             if (m_selectedBitmap
.Ok()) 
 178                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 184             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 189             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 194             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 199             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
); 
 204     m_brush 
= wxNullBrush
; 
 206     m_palette 
= wxNullPalette
; 
 208     m_backgroundBrush 
= wxNullBrush
; 
 209     m_selectedBitmap 
= wxNullBitmap
; 
 212 // --------------------------------------------------------------------------- 
 214 // --------------------------------------------------------------------------- 
 216 void wxDC::DoSetClippingRegion(long cx
, long cy
, long cw
, long ch
) 
 221     m_clipX2 
= (int)(cx 
+ cw
); 
 222     m_clipY2 
= (int)(cy 
+ ch
); 
 224     DoClipping((WXHDC
) m_hDC
); 
 227 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 229     wxCHECK_RET( region
.GetHRGN(), _T("invalid clipping region") ); 
 231     wxRect box 
= region
.GetBox(); 
 236     m_clipX2 
= box
.x 
+ box
.width
; 
 237     m_clipY2 
= box
.y 
+ box
.height
; 
 240     SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN()); 
 242     ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
); 
 246 void wxDC::DoClipping(WXHDC dc
) 
 248     if (m_clipping 
&& dc
) 
 250         IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
), 
 251                                     XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
)); 
 255 void wxDC::DestroyClippingRegion() 
 257     if (m_clipping 
&& m_hDC
) 
 259         // TODO: this should restore the previous clipping region, 
 260         // so that OnPaint processing works correctly, and the update clipping region 
 261         // doesn't get destroyed after the first DestroyClippingRegion. 
 262         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 263         SelectClipRgn(GetHdc(), rgn
); 
 269 // --------------------------------------------------------------------------- 
 270 // query capabilities 
 271 // --------------------------------------------------------------------------- 
 273 bool wxDC::CanDrawBitmap() const 
 278 bool wxDC::CanGetTextExtent() const 
 280     // What sort of display is it? 
 281     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 283     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 286 int wxDC::GetDepth() const 
 288     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 291 // --------------------------------------------------------------------------- 
 293 // --------------------------------------------------------------------------- 
 299         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 300     else if (m_selectedBitmap
.Ok()) 
 302         rect
.left 
= 0; rect
.top 
= 0; 
 303         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 304         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 306     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 308     DWORD colour 
= GetBkColor(GetHdc()); 
 309     HBRUSH brush 
= CreateSolidBrush(colour
); 
 310     FillRect(GetHdc(), &rect
, brush
); 
 313     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 314     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 315     ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
); 
 316     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 317     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 320 void wxDC::DoFloodFill(long x
, long y
, const wxColour
& col
, int style
) 
 322     (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 324                        style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 327     CalcBoundingBox(x
, y
); 
 330 bool wxDC::DoGetPixel(long x
, long y
, wxColour 
*col
) const 
 332     // added by steve 29.12.94 (copied from DrawPoint) 
 333     // returns TRUE for pixels in the color of the current pen 
 334     // and FALSE for all other pixels colors 
 335     // if col is non-NULL return the color of the pixel 
 337     // get the color of the pixel 
 338     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 339     // get the color of the pen 
 340     COLORREF pencolor 
= 0x00ffffff; 
 343         pencolor 
= m_pen
.GetColour().GetPixel(); 
 346     // return the color of the pixel 
 348         col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
)); 
 350     // check, if color of the pixels is the same as the color 
 351     // of the current pen 
 352     return(pixelcolor
==pencolor
); 
 355 void wxDC::DoCrossHair(long x
, long y
) 
 357     long x1 
= x
-VIEWPORT_EXTENT
; 
 358     long y1 
= y
-VIEWPORT_EXTENT
; 
 359     long x2 
= x
+VIEWPORT_EXTENT
; 
 360     long y2 
= y
+VIEWPORT_EXTENT
; 
 362     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
); 
 363     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 365     (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
); 
 366     (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 368     CalcBoundingBox(x1
, y1
); 
 369     CalcBoundingBox(x2
, y2
); 
 372 void wxDC::DoDrawLine(long x1
, long y1
, long x2
, long y2
) 
 374     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
); 
 375     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 377     /* MATTHEW: [6] New normalization */ 
 378 #if WX_STANDARD_GRAPHICS 
 379     (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
)); 
 382     CalcBoundingBox(x1
, y1
); 
 383     CalcBoundingBox(x2
, y2
); 
 386 void wxDC::DoDrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
) 
 390     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
) ;; 
 391     if (x1
==x2 
&& x2
==y2
) 
 393         DrawEllipse(xc
,yc
,(long)(radius
*2.0),(long)(radius
*2.0)); 
 397     long xx1 
= XLOG2DEV(x1
); 
 398     long yy1 
= YLOG2DEV(y1
); 
 399     long xx2 
= XLOG2DEV(x2
); 
 400     long yy2 
= YLOG2DEV(y2
); 
 401     long xxc 
= XLOG2DEV(xc
); 
 402     long yyc 
= YLOG2DEV(yc
); 
 403     long ray 
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 405     (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
); 
 406     long xxx1 
= (long) (xxc
-ray
); 
 407     long yyy1 
= (long) (yyc
-ray
); 
 408     long xxx2 
= (long) (xxc
+ray
); 
 409     long yyy2 
= (long) (yyc
+ray
); 
 410     if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
) 
 412         // Have to add 1 to bottom-right corner of rectangle 
 413         // to make semi-circles look right (crooked line otherwise). 
 414         // Unfortunately this is not a reliable method, depends 
 415         // on the size of shape. 
 416         // TODO: figure out why this happens! 
 417         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, 
 421         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, 
 424     CalcBoundingBox((xc
-radius
), (yc
-radius
)); 
 425     CalcBoundingBox((xc
+radius
), (yc
+radius
)); 
 428 void wxDC::DoDrawPoint(long x
, long y
) 
 430     COLORREF color 
= 0x00ffffff; 
 433         color 
= m_pen
.GetColour().GetPixel(); 
 436     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 438     CalcBoundingBox(x
, y
); 
 441 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
) 
 443     // Do things less efficiently if we have offsets 
 444     if (xoffset 
!= 0 || yoffset 
!= 0) 
 446         POINT 
*cpoints 
= new POINT
[n
]; 
 448         for (i 
= 0; i 
< n
; i
++) 
 450             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 451             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 453             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 455         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 456         (void)Polygon(GetHdc(), cpoints
, n
); 
 457         SetPolyFillMode(GetHdc(),prev
); 
 463         for (i 
= 0; i 
< n
; i
++) 
 464             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 466         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 467         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 468         SetPolyFillMode(GetHdc(),prev
); 
 472 void wxDC::DoDrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
) 
 474     // Do things less efficiently if we have offsets 
 475     if (xoffset 
!= 0 || yoffset 
!= 0) 
 477         POINT 
*cpoints 
= new POINT
[n
]; 
 479         for (i 
= 0; i 
< n
; i
++) 
 481             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 482             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 484             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 486         (void)Polyline(GetHdc(), cpoints
, n
); 
 492         for (i 
= 0; i 
< n
; i
++) 
 493             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 495         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 499 void wxDC::DoDrawRectangle(long x
, long y
, long width
, long height
) 
 502     long y2 
= y 
+ height
; 
 504     /* MATTHEW: [6] new normalization */ 
 505 #if WX_STANDARD_GRAPHICS 
 506     bool do_brush
, do_pen
; 
 508     do_brush 
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
; 
 509     do_pen 
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
; 
 512         HPEN orig_pen 
= NULL
; 
 514         if (do_pen 
|| !m_pen
.Ok()) 
 515             orig_pen 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 517         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 518             XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1); 
 520         if (do_pen 
|| !m_pen
.Ok()) 
 521             ::SelectObject(GetHdc() , orig_pen
); 
 524         HBRUSH orig_brush 
= NULL
; 
 526         if (do_brush 
|| !m_brush
.Ok()) 
 527             orig_brush 
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
)); 
 529         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 530             XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 532         if (do_brush 
|| !m_brush
.Ok()) 
 533             ::SelectObject(GetHdc(), orig_brush
); 
 536     (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 539     CalcBoundingBox(x
, y
); 
 540     CalcBoundingBox(x2
, y2
); 
 543 void wxDC::DoDrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
) 
 545     // Now, a negative radius value is interpreted to mean 
 546     // 'the proportion of the smallest X or Y dimension' 
 550         double smallest 
= 0.0; 
 555         radius 
= (- radius 
* smallest
); 
 559     long y2 
= (y
+height
); 
 561     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 562         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 564     CalcBoundingBox(x
, y
); 
 565     CalcBoundingBox(x2
, y2
); 
 568 void wxDC::DoDrawEllipse(long x
, long y
, long width
, long height
) 
 571     long y2 
= (y
+height
); 
 573     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 575     CalcBoundingBox(x
, y
); 
 576     CalcBoundingBox(x2
, y2
); 
 579 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
 580 void wxDC::DoDrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
) 
 585     const double deg2rad 
= 3.14159265359 / 180.0; 
 586     int rx1 
= XLOG2DEV(x
+w
/2); 
 587     int ry1 
= YLOG2DEV(y
+h
/2); 
 590     rx1 
+= (int)(100.0 * abs(w
) * cos(sa 
* deg2rad
)); 
 591     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa 
* deg2rad
)); 
 592     rx2 
+= (int)(100.0 * abs(w
) * cos(ea 
* deg2rad
)); 
 593     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea 
* deg2rad
)); 
 595     // draw pie with NULL_PEN first and then outline otherwise a line is 
 596     // drawn from the start and end points to the centre 
 597     HPEN orig_pen 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 600         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
 605         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
 606             rx1
, ry1
-1, rx2
, ry2
-1); 
 608     ::SelectObject(GetHdc(), orig_pen
); 
 609     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
 612     CalcBoundingBox(x
, y
); 
 613     CalcBoundingBox(x2
, y2
); 
 616 void wxDC::DoDrawIcon(const wxIcon
& icon
, long x
, long y
) 
 618 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__) 
 619     ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(), 
 620         icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
); 
 622     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON()); 
 625     CalcBoundingBox(x
, y
); 
 626     CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight()); 
 629 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, long x
, long y
, bool useMask 
) 
 634     // If we're not drawing transparently, and not drawing to a printer, 
 635     // optimize this function to use Windows functions. 
 636     if (!useMask 
&& !IsKindOf(CLASSINFO(wxPrinterDC
))) 
 639         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
 640         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
 641         ::SelectObject( memdc
, hbitmap 
); 
 642         ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
); 
 647         // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level 
 649         memDC
.SelectObject(bmp
); 
 651         /* Not sure if we need this. The mask should leave the 
 652         * masked areas as per the original background of this DC. 
 655         // There might be transparent areas, so make these 
 656         // the same colour as this DC 
 657         memDC.SetBackground(* GetBackground()); 
 661         Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
); 
 663         memDC
.SelectObject(wxNullBitmap
); 
 667 void wxDC::DoDrawText(const wxString
& text
, long x
, long y
) 
 669     if (m_textForegroundColour
.Ok()) 
 670         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
 672     DWORD old_background 
= 0; 
 673     if (m_textBackgroundColour
.Ok()) 
 675         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
 678     if (m_backgroundMode 
== wxTRANSPARENT
) 
 679         SetBkMode(GetHdc(), TRANSPARENT
); 
 681         SetBkMode(GetHdc(), OPAQUE
); 
 683     (void)TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
)); 
 685     if (m_textBackgroundColour
.Ok()) 
 686         (void)SetBkColor(GetHdc(), old_background
); 
 688     CalcBoundingBox(x
, y
); 
 691     GetTextExtent(text
, &w
, &h
); 
 692     CalcBoundingBox((x 
+ w
), (y 
+ h
)); 
 695 // --------------------------------------------------------------------------- 
 697 // --------------------------------------------------------------------------- 
 699 void wxDC::SetPalette(const wxPalette
& palette
) 
 701     // Set the old object temporarily, in case the assignment deletes an object 
 702     // that's not yet selected out. 
 705         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
); 
 713         // Setting a NULL colourmap is a way of restoring 
 714         // the original colourmap 
 717             ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
); 
 724     if (m_palette
.Ok() && m_palette
.GetHPALETTE()) 
 726         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
); 
 728             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
 730         ::RealizePalette(GetHdc()); 
 734 void wxDC::SetFont(const wxFont
& the_font
) 
 736     // Set the old object temporarily, in case the assignment deletes an object 
 737     // that's not yet selected out. 
 740         ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
 749             ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
 753     if (m_font
.Ok() && m_font
.GetResourceHandle()) 
 755         HFONT f 
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle()); 
 756         if (f 
== (HFONT
) NULL
) 
 758             wxLogDebug("::SelectObject failed in wxDC::SetFont."); 
 761             m_oldFont 
= (WXHFONT
) f
; 
 765 void wxDC::SetPen(const wxPen
& pen
) 
 767     // Set the old object temporarily, in case the assignment deletes an object 
 768     // that's not yet selected out. 
 771         ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
 780             ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
 786         if (m_pen
.GetResourceHandle()) 
 788             HPEN p 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle()); 
 790                 m_oldPen 
= (WXHPEN
) p
; 
 795 void wxDC::SetBrush(const wxBrush
& brush
) 
 797     // Set the old object temporarily, in case the assignment deletes an object 
 798     // that's not yet selected out. 
 801         ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
 810             ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
 816         if (m_brush
.GetResourceHandle()) 
 819             b 
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle()); 
 821                 m_oldBrush 
= (WXHBRUSH
) b
; 
 826 void wxDC::SetBackground(const wxBrush
& brush
) 
 828     m_backgroundBrush 
= brush
; 
 830     if (!m_backgroundBrush
.Ok()) 
 835         bool customColours 
= TRUE
; 
 836         // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to 
 837         // change background colours from the control-panel specified colours. 
 838         if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
)) 
 839             customColours 
= FALSE
; 
 843             if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
) 
 845                 m_canvas
->SetTransparent(TRUE
); 
 849                 // New behaviour, 10/2/99: setting the background brush of a DC 
 850                 // doesn't affect the window background colour. However, 
 851                 // I'm leaving in the transparency setting because it's needed by 
 852                 // various controls (e.g. wxStaticText) to determine whether to draw 
 853                 // transparently or not. TODO: maybe this should be a new function 
 854                 // wxWindow::SetTransparency(). Should that apply to the child itself, or the 
 856                 //        m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour()); 
 857                 m_canvas
->SetTransparent(FALSE
); 
 861     COLORREF new_color 
= m_backgroundBrush
.GetColour().GetPixel(); 
 863         (void)SetBkColor(GetHdc(), new_color
); 
 867 void wxDC::SetBackgroundMode(int mode
) 
 869     m_backgroundMode 
= mode
; 
 871     if (m_backgroundMode 
== wxTRANSPARENT
) 
 872         ::SetBkMode(GetHdc(), TRANSPARENT
); 
 874         ::SetBkMode(GetHdc(), OPAQUE
); 
 877 void wxDC::SetLogicalFunction(int function
) 
 879     m_logicalFunction 
= function
; 
 881     SetRop((WXHDC
) m_hDC
); 
 884 void wxDC::SetRop(WXHDC dc
) 
 886     if (!dc 
|| m_logicalFunction 
< 0) 
 890     // These may be wrong 
 891     switch (m_logicalFunction
) 
 893         //    case wxXOR: c_rop = R2_XORPEN; break; 
 894     case wxXOR
: c_rop 
= R2_NOTXORPEN
; break; 
 895     case wxINVERT
: c_rop 
= R2_NOT
; break; 
 896     case wxOR_REVERSE
: c_rop 
= R2_MERGEPENNOT
; break; 
 897     case wxAND_REVERSE
: c_rop 
= R2_MASKPENNOT
; break; 
 898     case wxCLEAR
: c_rop 
= R2_WHITE
; break; 
 899     case wxSET
: c_rop 
= R2_BLACK
; break; 
 900     case wxSRC_INVERT
: c_rop 
= R2_NOTCOPYPEN
; break; 
 901     case wxOR_INVERT
: c_rop 
= R2_MERGENOTPEN
; break; 
 902     case wxAND
: c_rop 
= R2_MASKPEN
; break; 
 903     case wxOR
: c_rop 
= R2_MERGEPEN
; break; 
 904     case wxAND_INVERT
: c_rop 
= R2_MASKNOTPEN
; break; 
 909         c_rop 
= R2_COPYPEN
; break; 
 911     SetROP2((HDC
) dc
, c_rop
); 
 914 bool wxDC::StartDoc(const wxString
& message
) 
 916     // We might be previewing, so return TRUE to let it continue. 
 924 void wxDC::StartPage() 
 932 // --------------------------------------------------------------------------- 
 934 // --------------------------------------------------------------------------- 
 936 long wxDC::GetCharHeight() const 
 938     TEXTMETRIC lpTextMetric
; 
 940     GetTextMetrics(GetHdc(), &lpTextMetric
); 
 942     return YDEV2LOGREL(lpTextMetric
.tmHeight
); 
 945 long wxDC::GetCharWidth() const 
 947     TEXTMETRIC lpTextMetric
; 
 949     GetTextMetrics(GetHdc(), &lpTextMetric
); 
 951     return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
); 
 954 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
, 
 955                          long *descent
, long *externalLeading
, 
 956                          wxFont 
*theFont
) const 
 958     wxFont 
*fontToUse 
= (wxFont
*) theFont
; 
 960         fontToUse 
= (wxFont
*) &m_font
; 
 965     GetTextExtentPoint(GetHdc(), (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
); 
 966     GetTextMetrics(GetHdc(), &tm
); 
 968     if (x
) *x 
= XDEV2LOGREL(sizeRect
.cx
); 
 969     if (y
) *y 
= YDEV2LOGREL(sizeRect
.cy
); 
 970     if (descent
) *descent 
= tm
.tmDescent
; 
 971     if (externalLeading
) *externalLeading 
= tm
.tmExternalLeading
; 
 974 void wxDC::SetMapMode(int mode
) 
 976     m_mappingMode 
= mode
; 
 979     int pixel_height 
= 0; 
 983     pixel_width 
= GetDeviceCaps(GetHdc(), HORZRES
); 
 984     pixel_height 
= GetDeviceCaps(GetHdc(), VERTRES
); 
 985     mm_width 
= GetDeviceCaps(GetHdc(), HORZSIZE
); 
 986     mm_height 
= GetDeviceCaps(GetHdc(), VERTSIZE
); 
 988     if ((pixel_width 
== 0) || (pixel_height 
== 0) || (mm_width 
== 0) || (mm_height 
== 0)) 
 993     double mm2pixelsX 
= pixel_width
/mm_width
; 
 994     double mm2pixelsY 
= pixel_height
/mm_height
; 
1000             m_logicalScaleX 
= (twips2mm 
* mm2pixelsX
); 
1001             m_logicalScaleY 
= (twips2mm 
* mm2pixelsY
); 
1006             m_logicalScaleX 
= (pt2mm 
* mm2pixelsX
); 
1007             m_logicalScaleY 
= (pt2mm 
* mm2pixelsY
); 
1012             m_logicalScaleX 
= mm2pixelsX
; 
1013             m_logicalScaleY 
= mm2pixelsY
; 
1018             m_logicalScaleX 
= (mm2pixelsX
/10.0); 
1019             m_logicalScaleY 
= (mm2pixelsY
/10.0); 
1025             m_logicalScaleX 
= 1.0; 
1026             m_logicalScaleY 
= 1.0; 
1031     if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
) 
1032         ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1034     SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1035     m_windowExtX 
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
); 
1036     m_windowExtY 
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
); 
1037     ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
); 
1038     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1039     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1042 void wxDC::SetUserScale(double x
, double y
) 
1047     SetMapMode(m_mappingMode
); 
1050 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
) 
1052     m_signX 
= xLeftRight 
? 1 : -1; 
1053     m_signY 
= yBottomUp 
? -1 : 1; 
1055     SetMapMode(m_mappingMode
); 
1058 void wxDC::SetSystemScale(double x
, double y
) 
1063     SetMapMode(m_mappingMode
); 
1066 void wxDC::SetLogicalOrigin(long x
, long y
) 
1068     m_logicalOriginX 
= x
; 
1069     m_logicalOriginY 
= y
; 
1071     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1074 void wxDC::SetDeviceOrigin(long x
, long y
) 
1076     m_deviceOriginX 
= x
; 
1077     m_deviceOriginY 
= y
; 
1079     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1082 // --------------------------------------------------------------------------- 
1083 // coordinates transformations 
1084 // --------------------------------------------------------------------------- 
1086 long wxDCBase::DeviceToLogicalX(long x
) const 
1088     return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
); 
1091 long wxDCBase::DeviceToLogicalXRel(long x
) const 
1093     return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
)); 
1096 long wxDCBase::DeviceToLogicalY(long y
) const 
1098     return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
); 
1101 long wxDCBase::DeviceToLogicalYRel(long y
) const 
1103     return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
)); 
1106 long wxDCBase::LogicalToDeviceX(long x
) const 
1108     return (long) ((x 
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX 
+ m_deviceOriginX
); 
1111 long wxDCBase::LogicalToDeviceXRel(long x
) const 
1113     return (long) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
); 
1116 long wxDCBase::LogicalToDeviceY(long y
) const 
1118     return (long) ((y 
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY 
+ m_deviceOriginY
); 
1121 long wxDCBase::LogicalToDeviceYRel(long y
) const 
1123     return (long) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
); 
1126 // --------------------------------------------------------------------------- 
1128 // --------------------------------------------------------------------------- 
1129 bool wxDC::DoBlit(long xdest
, long ydest
, long width
, long height
, 
1130                   wxDC 
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
) 
1132     long xdest1 
= xdest
; 
1133     long ydest1 
= ydest
; 
1137     // Chris Breeze 18/5/98: use text foreground/background colours 
1138     // when blitting from 1-bit bitmaps 
1139     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1140     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1141     if (m_textForegroundColour
.Ok()) 
1143         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1145     if (m_textBackgroundColour
.Ok()) 
1147         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1150     DWORD dwRop 
= rop 
== wxCOPY 
? SRCCOPY 
: 
1151     rop 
== wxCLEAR 
? WHITENESS 
: 
1152     rop 
== wxSET 
? BLACKNESS 
: 
1153     rop 
== wxINVERT 
? DSTINVERT 
: 
1154     rop 
== wxAND 
? MERGECOPY 
: 
1155     rop 
== wxOR 
? MERGEPAINT 
: 
1156     rop 
== wxSRC_INVERT 
? NOTSRCCOPY 
: 
1157     rop 
== wxXOR 
? SRCINVERT 
: 
1158     rop 
== wxOR_REVERSE 
? MERGEPAINT 
: 
1159     rop 
== wxAND_REVERSE 
? SRCERASE 
: 
1160     rop 
== wxSRC_OR 
? SRCPAINT 
: 
1161     rop 
== wxSRC_AND 
? SRCAND 
: 
1164     bool success 
= TRUE
; 
1165     if (useMask 
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask()) 
1169         // Not implemented under Win95 (or maybe a specific device?) 
1170         if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, 
1171             (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(), 
1181             HDC dc_mask 
= CreateCompatibleDC((HDC
) source
->m_hDC
); 
1182             ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap()); 
1183             success 
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, 
1184                 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0); 
1185             success 
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, 
1186                 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0); 
1187             ::SelectObject(dc_mask
, 0); 
1188             ::DeleteDC(dc_mask
); 
1190             // New code from Chris Breeze, 15/7/98 
1191             // Blit bitmap with mask 
1193             if (IsKindOf(CLASSINFO(wxPrinterDC
))) 
1195                 // If we are printing source colours are screen colours 
1196                 // not printer colours and so we need copy the bitmap 
1199                 HDC dc_mask 
= ::CreateCompatibleDC((HDC
) source
->m_hDC
); 
1200                 HDC dc_src 
= (HDC
) source
->m_hDC
; 
1202                 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap()); 
1203                 for (int x 
= 0; x 
< width
; x
++) 
1205                     for (int y 
= 0; y 
< height
; y
++) 
1207                         COLORREF cref 
= ::GetPixel(dc_mask
, x
, y
); 
1210                             HBRUSH brush 
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
)); 
1211                             rect
.left 
= xdest1 
+ x
; rect
.right 
= rect
.left 
+ 1; 
1212                             rect
.top 
= ydest1 
+ y
;  rect
.bottom 
= rect
.top 
+ 1; 
1213                             ::FillRect(GetHdc(), &rect
, brush
); 
1214                             ::DeleteObject(brush
); 
1218                 ::SelectObject(dc_mask
, 0); 
1219                 ::DeleteDC(dc_mask
); 
1223                 // create a temp buffer bitmap and DCs to access it and the mask 
1224                 HDC dc_mask 
= ::CreateCompatibleDC((HDC
) source
->m_hDC
); 
1225                 HDC dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
1226                 HBITMAP buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
1227                 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap()); 
1228                 ::SelectObject(dc_buffer
, buffer_bmap
); 
1230                 // copy dest to buffer 
1231                 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1232                     GetHdc(), xdest1
, ydest1
, SRCCOPY
); 
1234                 // copy src to buffer using selected raster op 
1235                 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1236                     (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
); 
1238                 // set masked area in buffer to BLACK (pixel value 0) 
1239                 COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
1240                 COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
1241                 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1242                     dc_mask
, xsrc1
, ysrc1
, SRCAND
); 
1244                 // set unmasked area in dest to BLACK 
1245                 ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
1246                 ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
1247                 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, 
1248                     dc_mask
, xsrc1
, ysrc1
, SRCAND
); 
1249                 ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
1250                 ::SetTextColor(GetHdc(), prevCol
); 
1252                 // OR buffer to dest 
1253                 success 
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, 
1254                     dc_buffer
, 0, 0, SRCPAINT
) != 0); 
1256                 // tidy up temporary DCs and bitmap 
1257                 ::SelectObject(dc_mask
, 0); 
1258                 ::DeleteDC(dc_mask
); 
1259                 ::SelectObject(dc_buffer
, 0); 
1260                 ::DeleteDC(dc_buffer
); 
1261                 ::DeleteObject(buffer_bmap
); 
1267         if (IsKindOf(CLASSINFO(wxPrinterDC
))) 
1269             // If we are printing, source colours are screen colours 
1270             // not printer colours and so we need copy the bitmap 
1272             HDC dc_src 
= (HDC
) source
->m_hDC
; 
1274             for (int x 
= 0; x 
< width
; x
++) 
1276                 for (int y 
= 0; y 
< height
; y
++) 
1278                     HBRUSH brush 
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
)); 
1279                     rect
.left 
= xdest1 
+ x
;   rect
.right 
= rect
.left 
+ 1; 
1280                     rect
.top 
= ydest1 
+ y
;    rect
.bottom 
= rect
.top 
+ 1; 
1281                     ::FillRect(GetHdc(), &rect
, brush
); 
1282                     ::DeleteObject(brush
); 
1288             success 
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
, 
1289                 xsrc1
, ysrc1
, dwRop
) != 0); 
1292     ::SetTextColor(GetHdc(), old_textground
); 
1293     ::SetBkColor(GetHdc(), old_background
); 
1298 void wxDC::DoGetSize(int *w
, int *h
) const 
1300     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
1301     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
1304 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
1306     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
); 
1307     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1310 wxSize 
wxDC::GetPPI() const 
1312     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
1313     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
1315     return wxSize(x
, y
); 
1318 // For use by wxWindows only, unless custom units are required. 
1319 void wxDC::SetLogicalScale(double x
, double y
) 
1321     m_logicalScaleX 
= x
; 
1322     m_logicalScaleY 
= y
; 
1325 #if WXWIN_COMPATIBILITY 
1326 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
, 
1327                          float *descent
, float *externalLeading
, 
1328                          wxFont 
*theFont
, bool use16bit
) const 
1330     long x1
, y1
, descent1
, externalLeading1
; 
1331     GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
); 
1334         *descent 
= descent1
; 
1335     if (externalLeading
) 
1336         *externalLeading 
= externalLeading1
; 
1340 // --------------------------------------------------------------------------- 
1341 // spline drawing code 
1342 // --------------------------------------------------------------------------- 
1346 class wxSpline
: public wxObject
 
1352     wxSpline(wxList 
*list
); 
1353     void DeletePoints(); 
1355     // Doesn't delete points 
1359 void wx_draw_open_spline(wxDC 
*dc
, wxSpline 
*spline
); 
1361 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
1362                          double a3
, double b3
, double a4
, double b4
); 
1363 void wx_clear_stack(); 
1364 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
1365                   double *y3
, double *x4
, double *y4
); 
1366 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
1367                     double x4
, double y4
); 
1368 static bool wx_spline_add_point(double x
, double y
); 
1369 static void wx_spline_draw_point_array(wxDC 
*dc
); 
1370 wxSpline 
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
); 
1372 void wxDC::DoDrawSpline(wxList 
*list
) 
1374     wxSpline 
spline(list
); 
1376     wx_draw_open_spline(this, &spline
); 
1379 wxList wx_spline_point_list
; 
1381 void wx_draw_open_spline(wxDC 
*dc
, wxSpline 
*spline
) 
1384     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
1385     double           x1
, y1
, x2
, y2
; 
1387     wxNode 
*node 
= spline
->points
->First(); 
1388     p 
= (wxPoint 
*)node
->Data(); 
1393     node 
= node
->Next(); 
1394     p 
= (wxPoint 
*)node
->Data(); 
1398     cx1 
= (double)((x1 
+ x2
) / 2); 
1399     cy1 
= (double)((y1 
+ y2
) / 2); 
1400     cx2 
= (double)((cx1 
+ x2
) / 2); 
1401     cy2 
= (double)((cy1 
+ y2
) / 2); 
1403     wx_spline_add_point(x1
, y1
); 
1405     while ((node 
= node
->Next()) != NULL
) 
1407         p 
= (wxPoint 
*)node
->Data(); 
1412         cx4 
= (double)(x1 
+ x2
) / 2; 
1413         cy4 
= (double)(y1 
+ y2
) / 2; 
1414         cx3 
= (double)(x1 
+ cx4
) / 2; 
1415         cy3 
= (double)(y1 
+ cy4
) / 2; 
1417         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
1421         cx2 
= (double)(cx1 
+ x2
) / 2; 
1422         cy2 
= (double)(cy1 
+ y2
) / 2; 
1425     wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
)); 
1426     wx_spline_add_point(x2
, y2
); 
1428     wx_spline_draw_point_array(dc
); 
1432 /********************* CURVES FOR SPLINES ***************************** 
1434   The following spline drawing routine is from 
1436     "An Algorithm for High-Speed Curve Generation" 
1437     by George Merrill Chaikin, 
1438     Computer Graphics and Image Processing, 3, Academic Press, 
1443         "On Chaikin's Algorithm" by R. F. Riesenfeld, 
1444         Computer Graphics and Image Processing, 4, Academic Press, 
1447 ***********************************************************************/ 
1449 #define     half(z1, z2)    ((z1+z2)/2.0) 
1452 /* iterative version */ 
1454 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
1457     register double  xmid
, ymid
; 
1458     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1461     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
1463     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
1464         xmid 
= (double)half(x2
, x3
); 
1465         ymid 
= (double)half(y2
, y3
); 
1466         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
1467             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
1468             wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
)); 
1469             wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
)); 
1471             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
1472                 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
1473             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
1474                 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
1480 /* utilities used by spline drawing routines */ 
1483 typedef struct wx_spline_stack_struct 
{ 
1484     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1488 #define         SPLINE_STACK_DEPTH             20 
1489 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
1490 static Stack   
*wx_stack_top
; 
1491 static int      wx_stack_count
; 
1493 void wx_clear_stack() 
1495     wx_stack_top 
= wx_spline_stack
; 
1499 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
1501     wx_stack_top
->x1 
= x1
; 
1502     wx_stack_top
->y1 
= y1
; 
1503     wx_stack_top
->x2 
= x2
; 
1504     wx_stack_top
->y2 
= y2
; 
1505     wx_stack_top
->x3 
= x3
; 
1506     wx_stack_top
->y3 
= y3
; 
1507     wx_stack_top
->x4 
= x4
; 
1508     wx_stack_top
->y4 
= y4
; 
1513 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
1514                   double *x3
, double *y3
, double *x4
, double *y4
) 
1516     if (wx_stack_count 
== 0) 
1520     *x1 
= wx_stack_top
->x1
; 
1521     *y1 
= wx_stack_top
->y1
; 
1522     *x2 
= wx_stack_top
->x2
; 
1523     *y2 
= wx_stack_top
->y2
; 
1524     *x3 
= wx_stack_top
->x3
; 
1525     *y3 
= wx_stack_top
->y3
; 
1526     *x4 
= wx_stack_top
->x4
; 
1527     *y4 
= wx_stack_top
->y4
; 
1531 static bool wx_spline_add_point(double x
, double y
) 
1533     wxPoint 
*point 
= new wxPoint
; 
1536     wx_spline_point_list
.Append((wxObject
*)point
); 
1540 static void wx_spline_draw_point_array(wxDC 
*dc
) 
1542     dc
->DrawLines(&wx_spline_point_list
, 0, 0); 
1543     wxNode 
*node 
= wx_spline_point_list
.First(); 
1546         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
1549         node 
= wx_spline_point_list
.First(); 
1553 wxSpline::wxSpline(wxList 
*list
) 
1558 wxSpline::~wxSpline() 
1562 void wxSpline::DeletePoints() 
1564     for(wxNode 
*node 
= points
->First(); node
; node 
= points
->First()) 
1566         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
1574 #endif // wxUSE_SPLINES