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 #include "wx/msw/private.h" // needs to be before #include <commdlg.h> 
  50 #if wxUSE_COMMON_DIALOGS 
  51 #if wxUSE_NORLANDER_HEADERS 
  61 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
) 
  63 // --------------------------------------------------------------------------- 
  65 // --------------------------------------------------------------------------- 
  67 static const int VIEWPORT_EXTENT 
= 1000; 
  69 static const int MM_POINTS 
= 9; 
  70 static const int MM_METRIC 
= 10; 
  72 // usually this is defined in math.h 
  74     static const double M_PI 
= 3.14159265358979323846; 
  77 // --------------------------------------------------------------------------- 
  79 // --------------------------------------------------------------------------- 
  81 // convert degrees to radians 
  82 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
  84 // =========================================================================== 
  86 // =========================================================================== 
  88 // --------------------------------------------------------------------------- 
  90 // --------------------------------------------------------------------------- 
  92 // Default constructor 
 106     m_windowExtX 
= VIEWPORT_EXTENT
; 
 107     m_windowExtY 
= VIEWPORT_EXTENT
; 
 116         SelectOldObjects(m_hDC
); 
 118             if ( m_canvas 
== NULL 
) 
 119                 ::DeleteDC(GetHdc()); 
 121                 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc()); 
 127 // This will select current objects out of the DC, 
 128 // which is what you have to do before deleting the 
 130 void wxDC::SelectOldObjects(WXHDC dc
) 
 136             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 137             if (m_selectedBitmap
.Ok()) 
 139                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 145             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 150             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 155             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 160             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
); 
 165     m_brush 
= wxNullBrush
; 
 167     m_palette 
= wxNullPalette
; 
 169     m_backgroundBrush 
= wxNullBrush
; 
 170     m_selectedBitmap 
= wxNullBitmap
; 
 173 // --------------------------------------------------------------------------- 
 175 // --------------------------------------------------------------------------- 
 177 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
) 
 182     m_clipX2 
= (int)(cx 
+ cw
); 
 183     m_clipY2 
= (int)(cy 
+ ch
); 
 185     DoClipping((WXHDC
) m_hDC
); 
 188 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 190     wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") ); 
 192     wxRect box 
= region
.GetBox(); 
 197     m_clipX2 
= box
.x 
+ box
.width
; 
 198     m_clipY2 
= box
.y 
+ box
.height
; 
 201     SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN()); 
 203     ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
); 
 207 void wxDC::DoClipping(WXHDC dc
) 
 209     if (m_clipping 
&& dc
) 
 211         IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
), 
 212                                     XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
)); 
 216 void wxDC::DestroyClippingRegion() 
 218     if (m_clipping 
&& m_hDC
) 
 220         // TODO: this should restore the previous clipping region, 
 221         // so that OnPaint processing works correctly, and the update clipping region 
 222         // doesn't get destroyed after the first DestroyClippingRegion. 
 223         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 224         SelectClipRgn(GetHdc(), rgn
); 
 230 // --------------------------------------------------------------------------- 
 231 // query capabilities 
 232 // --------------------------------------------------------------------------- 
 234 bool wxDC::CanDrawBitmap() const 
 239 bool wxDC::CanGetTextExtent() const 
 241     // What sort of display is it? 
 242     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 244     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 247 int wxDC::GetDepth() const 
 249     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 252 // --------------------------------------------------------------------------- 
 254 // --------------------------------------------------------------------------- 
 261         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 265         // No, I think we should simply ignore this if printing on e.g. 
 267         // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 
 268         if (!m_selectedBitmap
.Ok()) 
 271         rect
.left 
= 0; rect
.top 
= 0; 
 272         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 273         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 276     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 278     DWORD colour 
= GetBkColor(GetHdc()); 
 279     HBRUSH brush 
= CreateSolidBrush(colour
); 
 280     FillRect(GetHdc(), &rect
, brush
); 
 283     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 284     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 285     ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
); 
 286     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 287     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 290 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
) 
 292     if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 294                          style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 297         // quoting from the MSDN docs: 
 299         //      Following are some of the reasons this function might fail: 
 301         //      * The filling could not be completed. 
 302         //      * The specified point has the boundary color specified by the 
 303         //        crColor parameter (if FLOODFILLBORDER was requested). 
 304         //      * The specified point does not have the color specified by 
 305         //        crColor (if FLOODFILLSURFACE was requested) 
 306         //      * The point is outside the clipping region that is, it is not 
 307         //        visible on the device. 
 309         wxLogLastError("ExtFloodFill"); 
 312     CalcBoundingBox(x
, y
); 
 315 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour 
*col
) const 
 317     // get the color of the pixel 
 318     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 320     // get the color of the pen 
 321     COLORREF pencolor 
= 0x00ffffff; 
 324         pencolor 
= m_pen
.GetColour().GetPixel(); 
 327     // return the color of the pixel 
 330         col
->Set(GetRValue(pixelcolor
), 
 331                  GetGValue(pixelcolor
), 
 332                  GetBValue(pixelcolor
)); 
 335     // check, if color of the pixels is the same as the color of the current 
 336     // pen and return TRUE if it is, FALSE otherwise 
 337     return pixelcolor 
== pencolor
; 
 340 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
) 
 342     wxCoord x1 
= x
-VIEWPORT_EXTENT
; 
 343     wxCoord y1 
= y
-VIEWPORT_EXTENT
; 
 344     wxCoord x2 
= x
+VIEWPORT_EXTENT
; 
 345     wxCoord y2 
= y
+VIEWPORT_EXTENT
; 
 347     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
); 
 348     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 350     (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
); 
 351     (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 353     CalcBoundingBox(x1
, y1
); 
 354     CalcBoundingBox(x2
, y2
); 
 357 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 359     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
); 
 360     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 362     /* MATTHEW: [6] New normalization */ 
 363 #if WX_STANDARD_GRAPHICS 
 364     (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
)); 
 367     CalcBoundingBox(x1
, y1
); 
 368     CalcBoundingBox(x2
, y2
); 
 371 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
) 
 375     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
) ;; 
 376     if (x1
==x2 
&& x2
==y2
) 
 378         DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0)); 
 382     wxCoord xx1 
= XLOG2DEV(x1
); 
 383     wxCoord yy1 
= YLOG2DEV(y1
); 
 384     wxCoord xx2 
= XLOG2DEV(x2
); 
 385     wxCoord yy2 
= YLOG2DEV(y2
); 
 386     wxCoord xxc 
= XLOG2DEV(xc
); 
 387     wxCoord yyc 
= YLOG2DEV(yc
); 
 388     wxCoord ray 
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 390     (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
); 
 391     wxCoord xxx1 
= (wxCoord
) (xxc
-ray
); 
 392     wxCoord yyy1 
= (wxCoord
) (yyc
-ray
); 
 393     wxCoord xxx2 
= (wxCoord
) (xxc
+ray
); 
 394     wxCoord yyy2 
= (wxCoord
) (yyc
+ray
); 
 395     if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
) 
 397         // Have to add 1 to bottom-right corner of rectangle 
 398         // to make semi-circles look right (crooked line otherwise). 
 399         // Unfortunately this is not a reliable method, depends 
 400         // on the size of shape. 
 401         // TODO: figure out why this happens! 
 402         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, 
 406         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, 
 409     CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
)); 
 410     CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
)); 
 413 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
) 
 415     COLORREF color 
= 0x00ffffff; 
 418         color 
= m_pen
.GetColour().GetPixel(); 
 421     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 423     CalcBoundingBox(x
, y
); 
 426 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
) 
 428     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
 429     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
 430     if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) 
 433        if (m_textForegroundColour
.Ok()) 
 434        {   //just the oposite from what is expected see help on pattern brush 
 435            // 1 in mask becomes bk color 
 436            ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
 438        if (m_textBackgroundColour
.Ok()) 
 439        {   //just the oposite from what is expected 
 440            // 0 in mask becomes text color 
 441            ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
 444        if (m_backgroundMode 
== wxTRANSPARENT
) 
 445            SetBkMode(GetHdc(), TRANSPARENT
); 
 447            SetBkMode(GetHdc(), OPAQUE
); 
 450     // Do things less efficiently if we have offsets 
 451     if (xoffset 
!= 0 || yoffset 
!= 0) 
 453         POINT 
*cpoints 
= new POINT
[n
]; 
 455         for (i 
= 0; i 
< n
; i
++) 
 457             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 458             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 460             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 462         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 463         (void)Polygon(GetHdc(), cpoints
, n
); 
 464         SetPolyFillMode(GetHdc(),prev
); 
 470         for (i 
= 0; i 
< n
; i
++) 
 471             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 473         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 474         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 475         SetPolyFillMode(GetHdc(),prev
); 
 478     if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) 
 480        ::SetBkMode(GetHdc(), TRANSPARENT
); 
 481        ::SetTextColor(GetHdc(), old_textground
); 
 482        ::SetBkColor(GetHdc(), old_background
); 
 486 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 488     // Do things less efficiently if we have offsets 
 489     if (xoffset 
!= 0 || yoffset 
!= 0) 
 491         POINT 
*cpoints 
= new POINT
[n
]; 
 493         for (i 
= 0; i 
< n
; i
++) 
 495             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 496             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 498             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 500         (void)Polyline(GetHdc(), cpoints
, n
); 
 506         for (i 
= 0; i 
< n
; i
++) 
 507             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 509         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 513 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 515     COLORREF colFgOld 
= 0, 
 518     if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 520         colFgOld 
= ::GetTextColor(GetHdc()); 
 521         colBgOld 
= ::GetBkColor(GetHdc()); 
 523         if ( m_textForegroundColour
.Ok() ) 
 525             // just the oposite from what is expected see help on pattern brush 
 526             // 1 in mask becomes bk color 
 527             ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
 530         if ( m_textBackgroundColour
.Ok() ) 
 532             // 0 in mask becomes text color 
 533             ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel()); 
 536         // VZ: IMHO this does strictly nothing here 
 537         SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
 541     wxCoord x2 
= x 
+ width
; 
 542     wxCoord y2 
= y 
+ height
; 
 544     // Windows draws the filled rectangles without outline (i.e. drawn with a 
 545     // transparent pen) one pixel smaller in both directions and we want them 
 546     // to have the same size regardless of which pen is used - adjust 
 547     if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 553     (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 555     CalcBoundingBox(x
, y
); 
 556     CalcBoundingBox(x2
, y2
); 
 558     if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 560         // restore the colours we changed 
 561         ::SetBkMode(GetHdc(), TRANSPARENT
); 
 562         ::SetTextColor(GetHdc(), colFgOld
); 
 563         ::SetBkColor(GetHdc(), colBgOld
); 
 567 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 569     // Now, a negative radius value is interpreted to mean 
 570     // 'the proportion of the smallest X or Y dimension' 
 574         double smallest 
= 0.0; 
 579         radius 
= (- radius 
* smallest
); 
 582     wxCoord x2 
= (x
+width
); 
 583     wxCoord y2 
= (y
+height
); 
 585     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 586         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 588     CalcBoundingBox(x
, y
); 
 589     CalcBoundingBox(x2
, y2
); 
 592 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 594     wxCoord x2 
= (x
+width
); 
 595     wxCoord y2 
= (y
+height
); 
 597     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 599     CalcBoundingBox(x
, y
); 
 600     CalcBoundingBox(x2
, y2
); 
 603 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
 604 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 609     int rx1 
= XLOG2DEV(x
+w
/2); 
 610     int ry1 
= YLOG2DEV(y
+h
/2); 
 617     rx1 
+= (int)(100.0 * abs(w
) * cos(sa
)); 
 618     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa
)); 
 619     rx2 
+= (int)(100.0 * abs(w
) * cos(ea
)); 
 620     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea
)); 
 622     // draw pie with NULL_PEN first and then outline otherwise a line is 
 623     // drawn from the start and end points to the centre 
 624     HPEN orig_pen 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 627         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
 632         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
 633             rx1
, ry1
-1, rx2
, ry2
-1); 
 635     ::SelectObject(GetHdc(), orig_pen
); 
 636     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
 639     CalcBoundingBox(x
, y
); 
 640     CalcBoundingBox(x2
, y2
); 
 643 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
) 
 645     wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") ); 
 647     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
)); 
 649     CalcBoundingBox(x
, y
); 
 650     CalcBoundingBox(x 
+ icon
.GetWidth(), y 
+ icon
.GetHeight()); 
 653 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, wxCoord x
, wxCoord y
, bool useMask 
) 
 655     wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 
 657     int width 
= bmp
.GetWidth(), 
 658         height 
= bmp
.GetHeight(); 
 663         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
 664         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
 666         wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") ); 
 668         COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
 669         COLORREF old_background 
= ::GetBkColor(GetHdc()); 
 670         if (m_textForegroundColour
.Ok()) 
 672             ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
 674         if (m_textBackgroundColour
.Ok()) 
 676             ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
 679         ::SelectObject( memdc
, hbitmap 
); 
 680         ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
); 
 683         ::SetTextColor(GetHdc(), old_textground
); 
 684         ::SetBkColor(GetHdc(), old_background
); 
 688         // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level 
 690         memDC
.SelectObject(bmp
); 
 692         Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
); 
 694         memDC
.SelectObject(wxNullBitmap
); 
 698 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
) 
 700     DrawAnyText(text
, x
, y
); 
 702     // update the bounding box 
 703     CalcBoundingBox(x
, y
); 
 706     GetTextExtent(text
, &w
, &h
); 
 707     CalcBoundingBox(x 
+ w
, y 
+ h
); 
 710 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
) 
 712     // prepare for drawing the text 
 713     if ( m_textForegroundColour
.Ok() ) 
 714         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
 716     DWORD old_background 
= 0; 
 717     if ( m_textBackgroundColour
.Ok() ) 
 719         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
 722     SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
 725     if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 726                    text
.c_str(), text
.length()) == 0 ) 
 728         wxLogLastError("TextOut"); 
 731     // restore the old parameters (text foreground colour may be left because 
 732     // it never is set to anything else, but background should remain 
 733     // transparent even if we just drew an opaque string) 
 734     if ( m_textBackgroundColour
.Ok() ) 
 735         (void)SetBkColor(GetHdc(), old_background
); 
 737     SetBkMode(GetHdc(), TRANSPARENT
); 
 740 void wxDC::DoDrawRotatedText(const wxString
& text
, 
 741                              wxCoord x
, wxCoord y
, 
 744     // we test that we have some font because otherwise we should still use the 
 745     // "else" part below to avoid that DrawRotatedText(angle = 180) and 
 746     // DrawRotatedText(angle = 0) use different fonts (we can't use the default 
 747     // font for drawing rotated fonts unfortunately) 
 748     if ( (angle 
== 0.0) && m_font
.Ok() ) 
 750         DoDrawText(text
, x
, y
); 
 754         // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so 
 755         //     can't have non zero orientation/escapement 
 756         wxFont font 
= m_font
.Ok() ? m_font 
: *wxNORMAL_FONT
; 
 757         HFONT hfont 
= (HFONT
)font
.GetResourceHandle(); 
 759         if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 ) 
 761             wxLogLastError("GetObject(hfont)"); 
 764         // GDI wants the angle in tenth of degree 
 765         long angle10 
= (long)(angle 
* 10); 
 766         lf
.lfEscapement 
= angle10
; 
 767         lf
. lfOrientation 
= angle10
; 
 769         hfont 
= ::CreateFontIndirect(&lf
); 
 772             wxLogLastError("CreateFont"); 
 776             HFONT hfontOld 
= (HFONT
)::SelectObject(GetHdc(), hfont
); 
 778             DrawAnyText(text
, x
, y
); 
 780             (void)::SelectObject(GetHdc(), hfontOld
); 
 781             (void)::DeleteObject(hfont
); 
 784         // call the bounding box by adding all four vertices of the rectangle 
 785         // containing the text to it (simpler and probably not slower than 
 786         // determining which of them is really topmost/leftmost/...) 
 788         GetTextExtent(text
, &w
, &h
); 
 790         double rad 
= DegToRad(angle
); 
 792         // "upper left" and "upper right" 
 793         CalcBoundingBox(x
, y
); 
 794         CalcBoundingBox(x 
+ w
*cos(rad
), y 
- h
*sin(rad
)); 
 796         // "bottom left" and "bottom right" 
 797         x 
+= (wxCoord
)(h
*sin(rad
)); 
 798         y 
+= (wxCoord
)(h
*cos(rad
)); 
 799         CalcBoundingBox(x
, y
); 
 800         CalcBoundingBox(x 
+ h
*sin(rad
), y 
+ h
*cos(rad
)); 
 804 // --------------------------------------------------------------------------- 
 806 // --------------------------------------------------------------------------- 
 808 void wxDC::SetPalette(const wxPalette
& palette
) 
 810     // Set the old object temporarily, in case the assignment deletes an object 
 811     // that's not yet selected out. 
 814         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
); 
 822         // Setting a NULL colourmap is a way of restoring 
 823         // the original colourmap 
 826             ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
); 
 833     if (m_palette
.Ok() && m_palette
.GetHPALETTE()) 
 835         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
); 
 837             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
 839         ::RealizePalette(GetHdc()); 
 843 void wxDC::SetFont(const wxFont
& the_font
) 
 845     // Set the old object temporarily, in case the assignment deletes an object 
 846     // that's not yet selected out. 
 849         ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
 858             ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
 862     if (m_font
.Ok() && m_font
.GetResourceHandle()) 
 864         HFONT f 
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle()); 
 865         if (f 
== (HFONT
) NULL
) 
 867             wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont.")); 
 870             m_oldFont 
= (WXHFONT
) f
; 
 874 void wxDC::SetPen(const wxPen
& pen
) 
 876     // Set the old object temporarily, in case the assignment deletes an object 
 877     // that's not yet selected out. 
 880         ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
 889             ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
 895         if (m_pen
.GetResourceHandle()) 
 897             HPEN p 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle()); 
 899                 m_oldPen 
= (WXHPEN
) p
; 
 904 void wxDC::SetBrush(const wxBrush
& brush
) 
 906     // Set the old object temporarily, in case the assignment deletes an object 
 907     // that's not yet selected out. 
 910         ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
 919             ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
 925         if (m_brush
.GetResourceHandle()) 
 928             b 
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle()); 
 930                 m_oldBrush 
= (WXHBRUSH
) b
; 
 935 void wxDC::SetBackground(const wxBrush
& brush
) 
 937     m_backgroundBrush 
= brush
; 
 939     if (!m_backgroundBrush
.Ok()) 
 944         bool customColours 
= TRUE
; 
 945         // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to 
 946         // change background colours from the control-panel specified colours. 
 947         if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
)) 
 948             customColours 
= FALSE
; 
 952             if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
) 
 954                 m_canvas
->SetTransparent(TRUE
); 
 958                 // New behaviour, 10/2/99: setting the background brush of a DC 
 959                 // doesn't affect the window background colour. However, 
 960                 // I'm leaving in the transparency setting because it's needed by 
 961                 // various controls (e.g. wxStaticText) to determine whether to draw 
 962                 // transparently or not. TODO: maybe this should be a new function 
 963                 // wxWindow::SetTransparency(). Should that apply to the child itself, or the 
 965                 //        m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour()); 
 966                 m_canvas
->SetTransparent(FALSE
); 
 970     COLORREF new_color 
= m_backgroundBrush
.GetColour().GetPixel(); 
 972         (void)SetBkColor(GetHdc(), new_color
); 
 976 void wxDC::SetBackgroundMode(int mode
) 
 978     m_backgroundMode 
= mode
; 
 980     // SetBackgroundColour now only refers to text background 
 981     // and m_backgroundMode is used there 
 984     if (m_backgroundMode == wxTRANSPARENT) 
 985         ::SetBkMode(GetHdc(), TRANSPARENT); 
 987         ::SetBkMode(GetHdc(), OPAQUE); 
 991 void wxDC::SetLogicalFunction(int function
) 
 993     m_logicalFunction 
= function
; 
 995     SetRop((WXHDC
) m_hDC
); 
 998 void wxDC::SetRop(WXHDC dc
) 
1000     if (!dc 
|| m_logicalFunction 
< 0) 
1005     // These may be wrong 
1006     switch (m_logicalFunction
) 
1008         //    case wxXOR: c_rop = R2_XORPEN; break; 
1009     case wxXOR
: c_rop 
= R2_NOTXORPEN
; break; 
1010     case wxINVERT
: c_rop 
= R2_NOT
; break; 
1011     case wxOR_REVERSE
: c_rop 
= R2_MERGEPENNOT
; break; 
1012     case wxAND_REVERSE
: c_rop 
= R2_MASKPENNOT
; break; 
1013     case wxCLEAR
: c_rop 
= R2_WHITE
; break; 
1014     case wxSET
: c_rop 
= R2_BLACK
; break; 
1015     case wxSRC_INVERT
: c_rop 
= R2_NOTCOPYPEN
; break; 
1016     case wxOR_INVERT
: c_rop 
= R2_MERGENOTPEN
; break; 
1017     case wxAND
: c_rop 
= R2_MASKPEN
; break; 
1018     case wxOR
: c_rop 
= R2_MERGEPEN
; break; 
1019     case wxAND_INVERT
: c_rop 
= R2_MASKNOTPEN
; break; 
1025         // these probably wouldn't be wrong, RR 
1027             case wxXOR
:          c_rop 
= R2_XORPEN
;        break; 
1028             case wxINVERT
:       c_rop 
= R2_NOT
;           break; 
1029             case wxOR_REVERSE
:   c_rop 
= R2_MERGEPENNOT
;   break; 
1030             case wxAND_REVERSE
:  c_rop 
= R2_MASKPENNOT
;    break; 
1031             case wxCLEAR
:        c_rop 
= R2_BLACK
;         break; 
1032             case wxSET
:          c_rop 
= R2_WHITE
;         break; 
1033             case wxOR_INVERT
:    c_rop 
= R2_MERGENOTPEN
;   break; 
1034             case wxAND
:          c_rop 
= R2_MASKPEN
;       break; 
1035             case wxOR
:           c_rop 
= R2_MERGEPEN
;      break; 
1036             case wxEQUIV
:        c_rop 
= R2_NOTXORPEN
;     break; 
1037             case wxNAND
:         c_rop 
= R2_NOTMASKPEN
;    break; 
1038             case wxAND_INVERT
:   c_rop 
= R2_MASKNOTPEN
;    break; 
1039             case wxCOPY
:         c_rop 
= R2_COPYPEN
;       break; 
1040             case wxNO_OP
:        c_rop 
= R2_NOP
;           break; 
1041             case wxSRC_INVERT
:   c_rop 
= R2_NOTCOPYPEN
;    break; 
1043         // what is this one? 
1044         case wxNOR
:          c_rop 
= R2_COPYPEN
;       break; 
1046         // these are actually ternary ROPs 
1047         case wxSRC_AND
:      c_rop 
= R2_MASKPEN
;       break; 
1048         case wxSRC_OR
:       c_rop 
= R2_MERGEPEN
;      break; 
1052         c_rop 
= R2_COPYPEN
; break; 
1054     SetROP2((HDC
) dc
, c_rop
); 
1057 bool wxDC::StartDoc(const wxString
& message
) 
1059     // We might be previewing, so return TRUE to let it continue. 
1067 void wxDC::StartPage() 
1071 void wxDC::EndPage() 
1075 // --------------------------------------------------------------------------- 
1077 // --------------------------------------------------------------------------- 
1079 wxCoord 
wxDC::GetCharHeight() const 
1081     TEXTMETRIC lpTextMetric
; 
1083     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1085     return YDEV2LOGREL(lpTextMetric
.tmHeight
); 
1088 wxCoord 
wxDC::GetCharWidth() const 
1090     TEXTMETRIC lpTextMetric
; 
1092     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1094     return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
); 
1097 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord 
*x
, wxCoord 
*y
, 
1098                            wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1099                            wxFont 
*theFont
) const 
1101     wxFont 
*fontToUse 
= (wxFont
*) theFont
; 
1103         fontToUse 
= (wxFont
*) &m_font
; 
1108     GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
); 
1109     GetTextMetrics(GetHdc(), &tm
); 
1111     if (x
) *x 
= XDEV2LOGREL(sizeRect
.cx
); 
1112     if (y
) *y 
= YDEV2LOGREL(sizeRect
.cy
); 
1113     if (descent
) *descent 
= tm
.tmDescent
; 
1114     if (externalLeading
) *externalLeading 
= tm
.tmExternalLeading
; 
1117 void wxDC::SetMapMode(int mode
) 
1119     m_mappingMode 
= mode
; 
1121     int pixel_width 
= 0; 
1122     int pixel_height 
= 0; 
1126     pixel_width 
= GetDeviceCaps(GetHdc(), HORZRES
); 
1127     pixel_height 
= GetDeviceCaps(GetHdc(), VERTRES
); 
1128     mm_width 
= GetDeviceCaps(GetHdc(), HORZSIZE
); 
1129     mm_height 
= GetDeviceCaps(GetHdc(), VERTSIZE
); 
1131     if ((pixel_width 
== 0) || (pixel_height 
== 0) || (mm_width 
== 0) || (mm_height 
== 0)) 
1136     double mm2pixelsX 
= pixel_width
/mm_width
; 
1137     double mm2pixelsY 
= pixel_height
/mm_height
; 
1143             m_logicalScaleX 
= (twips2mm 
* mm2pixelsX
); 
1144             m_logicalScaleY 
= (twips2mm 
* mm2pixelsY
); 
1149             m_logicalScaleX 
= (pt2mm 
* mm2pixelsX
); 
1150             m_logicalScaleY 
= (pt2mm 
* mm2pixelsY
); 
1155             m_logicalScaleX 
= mm2pixelsX
; 
1156             m_logicalScaleY 
= mm2pixelsY
; 
1161             m_logicalScaleX 
= (mm2pixelsX
/10.0); 
1162             m_logicalScaleY 
= (mm2pixelsY
/10.0); 
1168             m_logicalScaleX 
= 1.0; 
1169             m_logicalScaleY 
= 1.0; 
1174     if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
) 
1175         ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1177     SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1178     m_windowExtX 
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
); 
1179     m_windowExtY 
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
); 
1180     ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
); 
1181     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1182     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1185 void wxDC::SetUserScale(double x
, double y
) 
1190     SetMapMode(m_mappingMode
); 
1193 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
) 
1195     m_signX 
= xLeftRight 
? 1 : -1; 
1196     m_signY 
= yBottomUp 
? -1 : 1; 
1198     SetMapMode(m_mappingMode
); 
1201 void wxDC::SetSystemScale(double x
, double y
) 
1206     SetMapMode(m_mappingMode
); 
1209 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1211     m_logicalOriginX 
= x
; 
1212     m_logicalOriginY 
= y
; 
1214     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1217 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1219     m_deviceOriginX 
= x
; 
1220     m_deviceOriginY 
= y
; 
1222     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1225 // --------------------------------------------------------------------------- 
1226 // coordinates transformations 
1227 // --------------------------------------------------------------------------- 
1229 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1231     return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
); 
1234 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1236     return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
)); 
1239 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
1241     return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
); 
1244 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
1246     return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
)); 
1249 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
1251     return (wxCoord
) ((x 
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX 
+ m_deviceOriginX
); 
1254 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
1256     return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
); 
1259 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
1261     return (wxCoord
) ((y 
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY 
+ m_deviceOriginY
); 
1264 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
1266     return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
); 
1269 // --------------------------------------------------------------------------- 
1271 // --------------------------------------------------------------------------- 
1273 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, 
1274                   wxCoord width
, wxCoord height
, 
1275                   wxDC 
*source
, wxCoord xsrc
, wxCoord ysrc
, 
1276                   int rop
, bool useMask
) 
1278     wxMask 
*mask 
= NULL
; 
1281         const wxBitmap
& bmp 
= source
->m_selectedBitmap
; 
1282         mask 
= bmp
.GetMask(); 
1284         if ( !(bmp
.Ok() && mask 
&& mask
->GetMaskBitmap()) ) 
1286             // don't give assert here because this would break existing 
1287             // programs - just silently ignore useMask parameter 
1292     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1293     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1294     if (m_textForegroundColour
.Ok()) 
1296         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1298     if (m_textBackgroundColour
.Ok()) 
1300         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1303     DWORD dwRop 
= rop 
== wxCOPY 
? SRCCOPY 
: 
1304                   rop 
== wxCLEAR 
? WHITENESS 
: 
1305                   rop 
== wxSET 
? BLACKNESS 
: 
1306                   rop 
== wxINVERT 
? DSTINVERT 
: 
1307                   rop 
== wxAND 
? MERGECOPY 
: 
1308                   rop 
== wxOR 
? MERGEPAINT 
: 
1309                   rop 
== wxSRC_INVERT 
? NOTSRCCOPY 
: 
1310                   rop 
== wxXOR 
? SRCINVERT 
: 
1311                   rop 
== wxOR_REVERSE 
? MERGEPAINT 
: 
1312                   rop 
== wxAND_REVERSE 
? SRCERASE 
: 
1313                   rop 
== wxSRC_OR 
? SRCPAINT 
: 
1314                   rop 
== wxSRC_AND 
? SRCAND 
: 
1322         HBITMAP hbmpMask 
= wxInvertMask((HBITMAP
)mask
->GetMaskBitmap()); 
1324         // we want the part of the image corresponding to the mask to be 
1325         // transparent, i.e. do PATCOPY there and apply dwRop elsewhere 
1326         const wxColour
& colBg 
= m_backgroundBrush
.GetColour(); 
1327         HBRUSH hbrBg 
= (HBRUSH
)::CreateSolidBrush(wxColourToRGB(colBg
)); 
1328         HBRUSH hbrOld 
= (HBRUSH
)::SelectObject(GetHdc(), hbrBg
); 
1330         success 
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
, 
1331                             GetHdcOf(*source
), xsrc
, ysrc
, 
1333                             MAKEROP4(PATCOPY
, dwRop
)) != 0; 
1335         (void)::SelectObject(GetHdc(), hbrOld
); 
1336         ::DeleteObject(hbrOld
); 
1337         ::DeleteObject(hbmpMask
); 
1342             // Blit bitmap with mask 
1344             // create a temp buffer bitmap and DCs to access it and the mask 
1345             HDC dc_mask 
= ::CreateCompatibleDC(GetHdcOf(*source
)); 
1346             HDC dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
1347             HBITMAP buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
1348             ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap()); 
1349             ::SelectObject(dc_buffer
, buffer_bmap
); 
1351             // copy dest to buffer 
1352             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1353                            GetHdc(), xdest
, ydest
, SRCCOPY
) ) 
1355                 wxLogLastError("BitBlt"); 
1358             // copy src to buffer using selected raster op 
1359             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1360                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) ) 
1362                 wxLogLastError("BitBlt"); 
1365             // set masked area in buffer to BLACK (pixel value 0) 
1366             COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
1367             COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
1368             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1369                            dc_mask
, xsrc
, ysrc
, SRCAND
) ) 
1371                 wxLogLastError("BitBlt"); 
1374             // set unmasked area in dest to BLACK 
1375             ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
1376             ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
1377             if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
, 
1378                            dc_mask
, xsrc
, ysrc
, SRCAND
) ) 
1380                 wxLogLastError("BitBlt"); 
1382             ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
1383             ::SetTextColor(GetHdc(), prevCol
); 
1385             // OR buffer to dest 
1386             success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
1387                                (int)width
, (int)height
, 
1388                                dc_buffer
, 0, 0, SRCPAINT
) != 0; 
1391                 wxLogLastError("BitBlt"); 
1394             // tidy up temporary DCs and bitmap 
1395             ::SelectObject(dc_mask
, 0); 
1396             ::DeleteDC(dc_mask
); 
1397             ::SelectObject(dc_buffer
, 0); 
1398             ::DeleteDC(dc_buffer
); 
1399             ::DeleteObject(buffer_bmap
); 
1402     else // no mask, just BitBlt() it 
1404         success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
1405                            (int)width
, (int)height
, 
1406                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0; 
1409             wxLogLastError("BitBlt"); 
1412     ::SetTextColor(GetHdc(), old_textground
); 
1413     ::SetBkColor(GetHdc(), old_background
); 
1418 void wxDC::DoGetSize(int *w
, int *h
) const 
1420     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
1421     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
1424 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
1426     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
); 
1427     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1430 wxSize 
wxDC::GetPPI() const 
1432     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
1433     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
1435     return wxSize(x
, y
); 
1438 // For use by wxWindows only, unless custom units are required. 
1439 void wxDC::SetLogicalScale(double x
, double y
) 
1441     m_logicalScaleX 
= x
; 
1442     m_logicalScaleY 
= y
; 
1445 #if WXWIN_COMPATIBILITY 
1446 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
, 
1447                          float *descent
, float *externalLeading
, 
1448                          wxFont 
*theFont
, bool use16bit
) const 
1450     wxCoord x1
, y1
, descent1
, externalLeading1
; 
1451     GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
); 
1454         *descent 
= descent1
; 
1455     if (externalLeading
) 
1456         *externalLeading 
= externalLeading1
; 
1460 // --------------------------------------------------------------------------- 
1461 // spline drawing code 
1462 // --------------------------------------------------------------------------- 
1466 class wxSpline
: public wxObject
 
1472     wxSpline(wxList 
*list
); 
1473     void DeletePoints(); 
1475     // Doesn't delete points 
1479 void wx_draw_open_spline(wxDC 
*dc
, wxSpline 
*spline
); 
1481 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, 
1482                          double a3
, double b3
, double a4
, double b4
); 
1483 void wx_clear_stack(); 
1484 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
, 
1485                   double *y3
, double *x4
, double *y4
); 
1486 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, 
1487                     double x4
, double y4
); 
1488 static bool wx_spline_add_point(double x
, double y
); 
1489 static void wx_spline_draw_point_array(wxDC 
*dc
); 
1490 wxSpline 
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
); 
1492 void wxDC::DoDrawSpline(wxList 
*list
) 
1494     wxSpline 
spline(list
); 
1496     wx_draw_open_spline(this, &spline
); 
1499 wxList wx_spline_point_list
; 
1501 void wx_draw_open_spline(wxDC 
*dc
, wxSpline 
*spline
) 
1504     double           cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
; 
1505     double           x1
, y1
, x2
, y2
; 
1507     wxNode 
*node 
= spline
->points
->First(); 
1508     p 
= (wxPoint 
*)node
->Data(); 
1513     node 
= node
->Next(); 
1514     p 
= (wxPoint 
*)node
->Data(); 
1518     cx1 
= (double)((x1 
+ x2
) / 2); 
1519     cy1 
= (double)((y1 
+ y2
) / 2); 
1520     cx2 
= (double)((cx1 
+ x2
) / 2); 
1521     cy2 
= (double)((cy1 
+ y2
) / 2); 
1523     wx_spline_add_point(x1
, y1
); 
1525     while ((node 
= node
->Next()) != NULL
) 
1527         p 
= (wxPoint 
*)node
->Data(); 
1532         cx4 
= (double)(x1 
+ x2
) / 2; 
1533         cy4 
= (double)(y1 
+ y2
) / 2; 
1534         cx3 
= (double)(x1 
+ cx4
) / 2; 
1535         cy3 
= (double)(y1 
+ cy4
) / 2; 
1537         wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
); 
1541         cx2 
= (double)(cx1 
+ x2
) / 2; 
1542         cy2 
= (double)(cy1 
+ y2
) / 2; 
1545     wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
)); 
1546     wx_spline_add_point(x2
, y2
); 
1548     wx_spline_draw_point_array(dc
); 
1552 /********************* CURVES FOR SPLINES ***************************** 
1554   The following spline drawing routine is from 
1556     "An Algorithm for High-Speed Curve Generation" 
1557     by George Merrill Chaikin, 
1558     Computer Graphics and Image Processing, 3, Academic Press, 
1563         "On Chaikin's Algorithm" by R. F. Riesenfeld, 
1564         Computer Graphics and Image Processing, 4, Academic Press, 
1567 ***********************************************************************/ 
1569 #define     half(z1, z2)    ((z1+z2)/2.0) 
1572 /* iterative version */ 
1574 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
, 
1577     register double  xmid
, ymid
; 
1578     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1581     wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
); 
1583     while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) { 
1584         xmid 
= (double)half(x2
, x3
); 
1585         ymid 
= (double)half(y2
, y3
); 
1586         if (fabs(x1 
- xmid
) < THRESHOLD 
&& fabs(y1 
- ymid
) < THRESHOLD 
&& 
1587             fabs(xmid 
- x4
) < THRESHOLD 
&& fabs(ymid 
- y4
) < THRESHOLD
) { 
1588             wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
)); 
1589             wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
)); 
1591             wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
), 
1592                 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
); 
1593             wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
), 
1594                 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
); 
1600 /* utilities used by spline drawing routines */ 
1603 typedef struct wx_spline_stack_struct 
{ 
1604     double           x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
; 
1608 #define         SPLINE_STACK_DEPTH             20 
1609 static Stack    wx_spline_stack
[SPLINE_STACK_DEPTH
]; 
1610 static Stack   
*wx_stack_top
; 
1611 static int      wx_stack_count
; 
1613 void wx_clear_stack() 
1615     wx_stack_top 
= wx_spline_stack
; 
1619 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
) 
1621     wx_stack_top
->x1 
= x1
; 
1622     wx_stack_top
->y1 
= y1
; 
1623     wx_stack_top
->x2 
= x2
; 
1624     wx_stack_top
->y2 
= y2
; 
1625     wx_stack_top
->x3 
= x3
; 
1626     wx_stack_top
->y3 
= y3
; 
1627     wx_stack_top
->x4 
= x4
; 
1628     wx_stack_top
->y4 
= y4
; 
1633 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, 
1634                   double *x3
, double *y3
, double *x4
, double *y4
) 
1636     if (wx_stack_count 
== 0) 
1640     *x1 
= wx_stack_top
->x1
; 
1641     *y1 
= wx_stack_top
->y1
; 
1642     *x2 
= wx_stack_top
->x2
; 
1643     *y2 
= wx_stack_top
->y2
; 
1644     *x3 
= wx_stack_top
->x3
; 
1645     *y3 
= wx_stack_top
->y3
; 
1646     *x4 
= wx_stack_top
->x4
; 
1647     *y4 
= wx_stack_top
->y4
; 
1651 static bool wx_spline_add_point(double x
, double y
) 
1653     wxPoint 
*point 
= new wxPoint
; 
1656     wx_spline_point_list
.Append((wxObject
*)point
); 
1660 static void wx_spline_draw_point_array(wxDC 
*dc
) 
1662     dc
->DrawLines(&wx_spline_point_list
, 0, 0); 
1663     wxNode 
*node 
= wx_spline_point_list
.First(); 
1666         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
1669         node 
= wx_spline_point_list
.First(); 
1673 wxSpline::wxSpline(wxList 
*list
) 
1678 wxSpline::~wxSpline() 
1682 void wxSpline::DeletePoints() 
1684     for(wxNode 
*node 
= points
->First(); node
; node 
= points
->First()) 
1686         wxPoint 
*point 
= (wxPoint 
*)node
->Data(); 
1694 #endif // wxUSE_SPLINES