]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/dc.cpp
23c3da77eca43bdec7dd21268312e46e5488bfe3
   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/sysopt.h" 
  44 #include "wx/dcprint.h" 
  45 #include "wx/module.h" 
  50 #include "wx/msw/private.h" // needs to be before #include <commdlg.h> 
  52 #if wxUSE_COMMON_DIALOGS 
  60 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
) 
  62 // --------------------------------------------------------------------------- 
  64 // --------------------------------------------------------------------------- 
  66 static const int VIEWPORT_EXTENT 
= 1000; 
  68 static const int MM_POINTS 
= 9; 
  69 static const int MM_METRIC 
= 10; 
  71 // usually this is defined in math.h 
  73     static const double M_PI 
= 3.14159265358979323846; 
  76 // ROPs which don't have standard names (see "Ternary Raster Operations" in the 
  77 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) 
  78 #define DSTCOPY 0x00AA0029      // a.k.a. NOP operation 
  80 // --------------------------------------------------------------------------- 
  82 // --------------------------------------------------------------------------- 
  84 // convert degrees to radians 
  85 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
  87 // ---------------------------------------------------------------------------- 
  89 // ---------------------------------------------------------------------------- 
  91 // instead of duplicating the same code which sets and then restores text 
  92 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, 
  93 // encapsulate this in a small helper class 
  95 // wxColourChanger: changes the text colours in the ctor if required and 
  96 //                  restores them in the dtor 
 100     wxColourChanger(wxDC
& dc
); 
 106     COLORREF m_colFgOld
, m_colBgOld
; 
 111 // =========================================================================== 
 113 // =========================================================================== 
 115 // ---------------------------------------------------------------------------- 
 117 // ---------------------------------------------------------------------------- 
 119 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
) 
 121     if ( dc
.GetBrush().GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 123         HDC hdc 
= GetHdcOf(dc
); 
 124         m_colFgOld 
= ::GetTextColor(hdc
); 
 125         m_colBgOld 
= ::GetBkColor(hdc
); 
 127         // note that Windows convention is opposite to wxWindows one, this is 
 128         // why text colour becomes the background one and vice versa 
 129         const wxColour
& colFg 
= dc
.GetTextForeground(); 
 132             ::SetBkColor(hdc
, colFg
.GetPixel()); 
 135         const wxColour
& colBg 
= dc
.GetTextBackground(); 
 138             ::SetTextColor(hdc
, colBg
.GetPixel()); 
 142                   dc
.GetBackgroundMode() == wxTRANSPARENT 
? TRANSPARENT
 
 145         // flag which telsl us to undo changes in the dtor 
 150         // nothing done, nothing to undo 
 155 wxColourChanger::~wxColourChanger() 
 159         // restore the colours we changed 
 160         HDC hdc 
= GetHdcOf(m_dc
); 
 162         ::SetBkMode(hdc
, TRANSPARENT
); 
 163         ::SetTextColor(hdc
, m_colFgOld
); 
 164         ::SetBkColor(hdc
, m_colBgOld
); 
 168 // --------------------------------------------------------------------------- 
 170 // --------------------------------------------------------------------------- 
 172 // Default constructor 
 183 #endif // wxUSE_PALETTE 
 188     m_windowExtX 
= VIEWPORT_EXTENT
; 
 189     m_windowExtY 
= VIEWPORT_EXTENT
; 
 197         SelectOldObjects(m_hDC
); 
 199         // if we own the HDC, we delete it, otherwise we just release it 
 203             ::DeleteDC(GetHdc()); 
 205         else // we don't own our HDC 
 209                 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc()); 
 213                 // Must have been a wxScreenDC 
 214                 ::ReleaseDC((HWND
) NULL
, GetHdc()); 
 220 // This will select current objects out of the DC, 
 221 // which is what you have to do before deleting the 
 223 void wxDC::SelectOldObjects(WXHDC dc
) 
 229             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 230             if (m_selectedBitmap
.Ok()) 
 232                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 238             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 243             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 248             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 255             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
); 
 258 #endif // wxUSE_PALETTE 
 261     m_brush 
= wxNullBrush
; 
 264     m_palette 
= wxNullPalette
; 
 265 #endif // wxUSE_PALETTE 
 267     m_backgroundBrush 
= wxNullBrush
; 
 268     m_selectedBitmap 
= wxNullBitmap
; 
 271 // --------------------------------------------------------------------------- 
 273 // --------------------------------------------------------------------------- 
 275 void wxDC::UpdateClipBox() 
 277 #ifdef __WXMICROWIN__ 
 278     if (!GetHDC()) return; 
 282     GetClipBox(GetHdc(), &rect
); 
 284     m_clipX1 
= (wxCoord
) XDEV2LOG(rect
.left
); 
 285     m_clipY1 
= (wxCoord
) YDEV2LOG(rect
.top
); 
 286     m_clipX2 
= (wxCoord
) XDEV2LOG(rect
.right
); 
 287     m_clipY2 
= (wxCoord
) YDEV2LOG(rect
.bottom
); 
 290 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 292 #ifdef __WXMICROWIN__ 
 293     if (!GetHDC()) return; 
 298     // the region coords are always the device ones, so do the translation 
 301     // FIXME: possible +/-1 error here, to check! 
 302     HRGN hrgn 
= ::CreateRectRgn(LogicalToDeviceX(x
), 
 304                                 LogicalToDeviceX(x 
+ w
), 
 305                                 LogicalToDeviceY(y 
+ h
)); 
 308         wxLogLastError(_T("CreateRectRgn")); 
 312         if ( ::SelectClipRgn(GetHdc(), hrgn
) == ERROR 
) 
 314             wxLogLastError(_T("SelectClipRgn")); 
 322 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 324 #ifdef __WXMICROWIN__ 
 325     if (!GetHDC()) return; 
 328     wxCHECK_RET( GetHrgnOf(region
), wxT("invalid clipping region") ); 
 333     SelectClipRgn(GetHdc(), GetHrgnOf(region
)); 
 335     ExtSelectClipRgn(GetHdc(), GetHrgnOf(region
), RGN_AND
); 
 341 void wxDC::DestroyClippingRegion() 
 343 #ifdef __WXMICROWIN__ 
 344     if (!GetHDC()) return; 
 347     if (m_clipping 
&& m_hDC
) 
 349         // TODO: this should restore the previous clipping region, 
 350         // so that OnPaint processing works correctly, and the update clipping region 
 351         // doesn't get destroyed after the first DestroyClippingRegion. 
 352         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 353         SelectClipRgn(GetHdc(), rgn
); 
 360 // --------------------------------------------------------------------------- 
 361 // query capabilities 
 362 // --------------------------------------------------------------------------- 
 364 bool wxDC::CanDrawBitmap() const 
 369 bool wxDC::CanGetTextExtent() const 
 371 #ifdef __WXMICROWIN__ 
 372     // TODO Extend MicroWindows' GetDeviceCaps function 
 375     // What sort of display is it? 
 376     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 378     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 382 int wxDC::GetDepth() const 
 384 #ifdef __WXMICROWIN__ 
 385     if (!GetHDC()) return 16; 
 388     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 391 // --------------------------------------------------------------------------- 
 393 // --------------------------------------------------------------------------- 
 397 #ifdef __WXMICROWIN__ 
 398     if (!GetHDC()) return; 
 404         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 408         // No, I think we should simply ignore this if printing on e.g. 
 410         // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 
 411         if (!m_selectedBitmap
.Ok()) 
 414         rect
.left 
= 0; rect
.top 
= 0; 
 415         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 416         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 419     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 421     DWORD colour 
= GetBkColor(GetHdc()); 
 422     HBRUSH brush 
= CreateSolidBrush(colour
); 
 423     FillRect(GetHdc(), &rect
, brush
); 
 426     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 427     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 428     ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
); 
 429     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 430     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 433 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
) 
 435 #ifdef __WXMICROWIN__ 
 436     if (!GetHDC()) return; 
 439     if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 441                          style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 444         // quoting from the MSDN docs: 
 446         //      Following are some of the reasons this function might fail: 
 448         //      * The filling could not be completed. 
 449         //      * The specified point has the boundary color specified by the 
 450         //        crColor parameter (if FLOODFILLBORDER was requested). 
 451         //      * The specified point does not have the color specified by 
 452         //        crColor (if FLOODFILLSURFACE was requested) 
 453         //      * The point is outside the clipping region that is, it is not 
 454         //        visible on the device. 
 456         wxLogLastError(wxT("ExtFloodFill")); 
 459     CalcBoundingBox(x
, y
); 
 462 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour 
*col
) const 
 464 #ifdef __WXMICROWIN__ 
 465     if (!GetHDC()) return FALSE
; 
 468     wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") ); 
 470     // get the color of the pixel 
 471     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 473     wxRGBToColour(*col
, pixelcolor
); 
 478 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
) 
 480 #ifdef __WXMICROWIN__ 
 481     if (!GetHDC()) return; 
 484     wxCoord x1 
= x
-VIEWPORT_EXTENT
; 
 485     wxCoord y1 
= y
-VIEWPORT_EXTENT
; 
 486     wxCoord x2 
= x
+VIEWPORT_EXTENT
; 
 487     wxCoord y2 
= y
+VIEWPORT_EXTENT
; 
 489     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
); 
 490     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 492     (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
); 
 493     (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 495     CalcBoundingBox(x1
, y1
); 
 496     CalcBoundingBox(x2
, y2
); 
 499 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 501 #ifdef __WXMICROWIN__ 
 502     if (!GetHDC()) return; 
 505     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
); 
 506     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 508     // Normalization: Windows doesn't draw the last point of the line. 
 509     // But apparently neither does GTK+, so we take it out again. 
 510 //    (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2)); 
 512     CalcBoundingBox(x1
, y1
); 
 513     CalcBoundingBox(x2
, y2
); 
 516 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) 
 517 // and ending at (x2, y2) 
 518 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
, 
 519                      wxCoord x2
, wxCoord y2
, 
 520                      wxCoord xc
, wxCoord yc
) 
 522 #ifdef __WXMICROWIN__ 
 523     if (!GetHDC()) return; 
 526     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 530     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
); 
 531     wxCoord r 
= (wxCoord
)radius
; 
 533     // treat the special case of full circle separately 
 534     if ( x1 
== x2 
&& y1 
== y2 
) 
 536         DrawEllipse(xc 
- r
, yc 
- r
, 2*r
, 2*r
); 
 540     wxCoord xx1 
= XLOG2DEV(x1
); 
 541     wxCoord yy1 
= YLOG2DEV(y1
); 
 542     wxCoord xx2 
= XLOG2DEV(x2
); 
 543     wxCoord yy2 
= YLOG2DEV(y2
); 
 544     wxCoord xxc 
= XLOG2DEV(xc
); 
 545     wxCoord yyc 
= YLOG2DEV(yc
); 
 546     wxCoord ray 
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 548     wxCoord xxx1 
= (wxCoord
) (xxc
-ray
); 
 549     wxCoord yyy1 
= (wxCoord
) (yyc
-ray
); 
 550     wxCoord xxx2 
= (wxCoord
) (xxc
+ray
); 
 551     wxCoord yyy2 
= (wxCoord
) (yyc
+ray
); 
 553     if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT 
) 
 555         // Have to add 1 to bottom-right corner of rectangle 
 556         // to make semi-circles look right (crooked line otherwise). 
 557         // Unfortunately this is not a reliable method, depends 
 558         // on the size of shape. 
 559         // TODO: figure out why this happens! 
 560         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
); 
 564         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
); 
 567     CalcBoundingBox(xc 
- r
, yc 
- r
); 
 568     CalcBoundingBox(xc 
+ r
, yc 
+ r
); 
 571 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
 572                            wxCoord width
, wxCoord height
) 
 574 #ifdef __WXMICROWIN__ 
 575     if (!GetHDC()) return; 
 578     wxCoord x2 
= x1 
+ width
, 
 581 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__) 
 588     DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
); 
 590     // In WIN16, draw a cross 
 591     HPEN blackPen 
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0)); 
 592     HPEN whiteBrush 
= (HPEN
)::GetStockObject(WHITE_BRUSH
); 
 593     HPEN hPenOld 
= (HPEN
)::SelectObject(GetHdc(), blackPen
); 
 594     HPEN hBrushOld 
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
); 
 595     ::SetROP2(GetHdc(), R2_COPYPEN
); 
 596     Rectangle(GetHdc(), x1
, y1
, x2
, y2
); 
 597     MoveToEx(GetHdc(), x1
, y1
, NULL
); 
 598     LineTo(GetHdc(), x2
, y2
); 
 599     MoveToEx(GetHdc(), x2
, y1
, NULL
); 
 600     LineTo(GetHdc(), x1
, y2
); 
 601     ::SelectObject(GetHdc(), hPenOld
); 
 602     ::SelectObject(GetHdc(), hBrushOld
); 
 603     ::DeleteObject(blackPen
); 
 606     CalcBoundingBox(x1
, y1
); 
 607     CalcBoundingBox(x2
, y2
); 
 610 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
) 
 612 #ifdef __WXMICROWIN__ 
 613     if (!GetHDC()) return; 
 616     COLORREF color 
= 0x00ffffff; 
 619         color 
= m_pen
.GetColour().GetPixel(); 
 622     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 624     CalcBoundingBox(x
, y
); 
 627 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
) 
 629 #ifdef __WXMICROWIN__ 
 630     if (!GetHDC()) return; 
 633     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 635     // Do things less efficiently if we have offsets 
 636     if (xoffset 
!= 0 || yoffset 
!= 0) 
 638         POINT 
*cpoints 
= new POINT
[n
]; 
 640         for (i 
= 0; i 
< n
; i
++) 
 642             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 643             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 645             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 647         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 648         (void)Polygon(GetHdc(), cpoints
, n
); 
 649         SetPolyFillMode(GetHdc(),prev
); 
 655         for (i 
= 0; i 
< n
; i
++) 
 656             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 658         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 659         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 660         SetPolyFillMode(GetHdc(),prev
); 
 664 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 666 #ifdef __WXMICROWIN__ 
 667     if (!GetHDC()) return; 
 670     // Do things less efficiently if we have offsets 
 671     if (xoffset 
!= 0 || yoffset 
!= 0) 
 673         POINT 
*cpoints 
= new POINT
[n
]; 
 675         for (i 
= 0; i 
< n
; i
++) 
 677             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 678             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 680             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 682         (void)Polyline(GetHdc(), cpoints
, n
); 
 688         for (i 
= 0; i 
< n
; i
++) 
 689             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 691         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 695 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 697 #ifdef __WXMICROWIN__ 
 698     if (!GetHDC()) return; 
 701     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 703     wxCoord x2 
= x 
+ width
; 
 704     wxCoord y2 
= y 
+ height
; 
 706     if ((m_logicalFunction 
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
)) 
 709         rect
.left 
= XLOG2DEV(x
); 
 710         rect
.top 
= YLOG2DEV(y
); 
 711         rect
.right 
= XLOG2DEV(x2
); 
 712         rect
.bottom 
= YLOG2DEV(y2
); 
 713         (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() ); 
 717         // Windows draws the filled rectangles without outline (i.e. drawn with a 
 718         // transparent pen) one pixel smaller in both directions and we want them 
 719         // to have the same size regardless of which pen is used - adjust 
 721         // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. 
 722         if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 728         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 732     CalcBoundingBox(x
, y
); 
 733     CalcBoundingBox(x2
, y2
); 
 736 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 738 #ifdef __WXMICROWIN__ 
 739     if (!GetHDC()) return; 
 742     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 744     // Now, a negative radius value is interpreted to mean 
 745     // 'the proportion of the smallest X or Y dimension' 
 749         double smallest 
= 0.0; 
 754         radius 
= (- radius 
* smallest
); 
 757     wxCoord x2 
= (x
+width
); 
 758     wxCoord y2 
= (y
+height
); 
 760     // Windows draws the filled rectangles without outline (i.e. drawn with a 
 761     // transparent pen) one pixel smaller in both directions and we want them 
 762     // to have the same size regardless of which pen is used - adjust 
 763     if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 769     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 770         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 772     CalcBoundingBox(x
, y
); 
 773     CalcBoundingBox(x2
, y2
); 
 776 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 778 #ifdef __WXMICROWIN__ 
 779     if (!GetHDC()) return; 
 782     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 784     wxCoord x2 
= (x
+width
); 
 785     wxCoord y2 
= (y
+height
); 
 787     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 789     CalcBoundingBox(x
, y
); 
 790     CalcBoundingBox(x2
, y2
); 
 793 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
 794 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 796 #ifdef __WXMICROWIN__ 
 797     if (!GetHDC()) return; 
 800     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 805     int rx1 
= XLOG2DEV(x
+w
/2); 
 806     int ry1 
= YLOG2DEV(y
+h
/2); 
 813     rx1 
+= (int)(100.0 * abs(w
) * cos(sa
)); 
 814     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa
)); 
 815     rx2 
+= (int)(100.0 * abs(w
) * cos(ea
)); 
 816     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea
)); 
 818     // draw pie with NULL_PEN first and then outline otherwise a line is 
 819     // drawn from the start and end points to the centre 
 820     HPEN hpenOld 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 823         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
 828         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
 829                   rx1
, ry1
-1, rx2
, ry2
-1); 
 832     ::SelectObject(GetHdc(), hpenOld
); 
 834     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
 837     CalcBoundingBox(x
, y
); 
 838     CalcBoundingBox(x2
, y2
); 
 841 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
) 
 843 #ifdef __WXMICROWIN__ 
 844     if (!GetHDC()) return; 
 847     wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") ); 
 850     ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
); 
 852     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
)); 
 855     CalcBoundingBox(x
, y
); 
 856     CalcBoundingBox(x 
+ icon
.GetWidth(), y 
+ icon
.GetHeight()); 
 859 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, wxCoord x
, wxCoord y
, bool useMask 
) 
 861 #ifdef __WXMICROWIN__ 
 862     if (!GetHDC()) return; 
 865     wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 
 867     int width 
= bmp
.GetWidth(), 
 868         height 
= bmp
.GetHeight(); 
 870     HBITMAP hbmpMask 
= 0; 
 874 #endif // wxUSE_PALETTE 
 878         wxMask 
*mask 
= bmp
.GetMask(); 
 880             hbmpMask 
= (HBITMAP
)mask
->GetMaskBitmap(); 
 884             // don't give assert here because this would break existing 
 885             // programs - just silently ignore useMask parameter 
 893         // use MaskBlt() with ROP which doesn't do anything to dst in the mask 
 895         // On some systems, MaskBlt succeeds yet is much much slower 
 896         // than the wxWindows fall-back implementation. So we need 
 897         // to be able to switch this on and off at runtime. 
 899 #if wxUSE_SYSTEM_OPTIONS 
 900         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
 904             HDC hdcMem 
= ::CreateCompatibleDC(GetHdc()); 
 905             ::SelectObject(hdcMem
, GetHbitmapOf(bmp
)); 
 908             wxPalette 
*pal 
= bmp
.GetPalette(); 
 909             if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
 911                 oldPal 
= ::SelectPalette( hdcMem
, GetHpalette(pal
), FALSE
); 
 912                 ::RealizePalette(hdcMem
); 
 914 #endif // wxUSE_PALETTE 
 916             ok 
= ::MaskBlt(cdc
, x
, y
, width
, height
, 
 919                             MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0; 
 923                 ::SelectPalette(hdcMem
, oldPal
, FALSE
); 
 924 #endif // wxUSE_PALETTE 
 932             // Rather than reproduce wxDC::Blit, let's do it at the wxWin API 
 935             memDC
.SelectObject(bmp
); 
 937             Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
); 
 939             memDC
.SelectObject(wxNullBitmap
); 
 942     else // no mask, just use BitBlt() 
 945         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
 946         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
 948         wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") ); 
 950         COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
 951         COLORREF old_background 
= ::GetBkColor(GetHdc()); 
 952         if (m_textForegroundColour
.Ok()) 
 954             ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
 956         if (m_textBackgroundColour
.Ok()) 
 958             ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
 962             wxPalette 
*pal 
= bmp
.GetPalette(); 
 963             if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
 965                 oldPal 
= ::SelectPalette( hdcMem
, GetHpalette(pal
), FALSE
); 
 966                 ::RealizePalette(hdcMem
); 
 968 #endif // wxUSE_PALETTE 
 970         ::SelectObject( memdc
, hbitmap 
); 
 971         ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
); 
 975             ::SelectPalette(memdc
, oldPal
, FALSE
); 
 976 #endif // wxUSE_PALETTE 
 980         ::SetTextColor(GetHdc(), old_textground
); 
 981         ::SetBkColor(GetHdc(), old_background
); 
 985 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
) 
 987 #ifdef __WXMICROWIN__ 
 988     if (!GetHDC()) return; 
 991     DrawAnyText(text
, x
, y
); 
 993     // update the bounding box 
 994     CalcBoundingBox(x
, y
); 
 997     GetTextExtent(text
, &w
, &h
); 
 998     CalcBoundingBox(x 
+ w
, y 
+ h
); 
1001 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1003 #ifdef __WXMICROWIN__ 
1004     if (!GetHDC()) return; 
1007     // prepare for drawing the text 
1008     if ( m_textForegroundColour
.Ok() ) 
1009         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
1011     DWORD old_background 
= 0; 
1012     if ( m_textBackgroundColour
.Ok() ) 
1014         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1017     SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
1020     if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
1021                    text
.c_str(), text
.length()) == 0 ) 
1023         wxLogLastError(wxT("TextOut")); 
1026     // restore the old parameters (text foreground colour may be left because 
1027     // it never is set to anything else, but background should remain 
1028     // transparent even if we just drew an opaque string) 
1029     if ( m_textBackgroundColour
.Ok() ) 
1030         (void)SetBkColor(GetHdc(), old_background
); 
1032     SetBkMode(GetHdc(), TRANSPARENT
); 
1035 void wxDC::DoDrawRotatedText(const wxString
& text
, 
1036                              wxCoord x
, wxCoord y
, 
1039 #ifdef __WXMICROWIN__ 
1040     if (!GetHDC()) return; 
1043     // we test that we have some font because otherwise we should still use the 
1044     // "else" part below to avoid that DrawRotatedText(angle = 180) and 
1045     // DrawRotatedText(angle = 0) use different fonts (we can't use the default 
1046     // font for drawing rotated fonts unfortunately) 
1047     if ( (angle 
== 0.0) && m_font
.Ok() ) 
1049         DoDrawText(text
, x
, y
); 
1051 #ifndef __WXMICROWIN__ 
1054         // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) 
1055         //     because it's not TrueType and so can't have non zero 
1056         //     orientation/escapement under Win9x 
1057         wxFont font 
= m_font
.Ok() ? m_font 
: *wxSWISS_FONT
; 
1058         HFONT hfont 
= (HFONT
)font
.GetResourceHandle(); 
1060         if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 ) 
1062             wxLogLastError(wxT("GetObject(hfont)")); 
1065         // GDI wants the angle in tenth of degree 
1066         long angle10 
= (long)(angle 
* 10); 
1067         lf
.lfEscapement 
= angle10
; 
1068         lf
. lfOrientation 
= angle10
; 
1070         hfont 
= ::CreateFontIndirect(&lf
); 
1073             wxLogLastError(wxT("CreateFont")); 
1077             HFONT hfontOld 
= (HFONT
)::SelectObject(GetHdc(), hfont
); 
1079             DrawAnyText(text
, x
, y
); 
1081             (void)::SelectObject(GetHdc(), hfontOld
); 
1082             (void)::DeleteObject(hfont
); 
1085         // call the bounding box by adding all four vertices of the rectangle 
1086         // containing the text to it (simpler and probably not slower than 
1087         // determining which of them is really topmost/leftmost/...) 
1089         GetTextExtent(text
, &w
, &h
); 
1091         double rad 
= DegToRad(angle
); 
1093         // "upper left" and "upper right" 
1094         CalcBoundingBox(x
, y
); 
1095         CalcBoundingBox(x 
+ w
*cos(rad
), y 
- h
*sin(rad
)); 
1097         // "bottom left" and "bottom right" 
1098         x 
+= (wxCoord
)(h
*sin(rad
)); 
1099         y 
+= (wxCoord
)(h
*cos(rad
)); 
1100         CalcBoundingBox(x
, y
); 
1101         CalcBoundingBox(x 
+ h
*sin(rad
), y 
+ h
*cos(rad
)); 
1106 // --------------------------------------------------------------------------- 
1108 // --------------------------------------------------------------------------- 
1112 void wxDC::SetPalette(const wxPalette
& palette
) 
1114 #ifdef __WXMICROWIN__ 
1115     if (!GetHDC()) return; 
1118     // Set the old object temporarily, in case the assignment deletes an object 
1119     // that's not yet selected out. 
1122         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
); 
1126     m_palette 
= palette
; 
1128     if (!m_palette
.Ok()) 
1130         // Setting a NULL colourmap is a way of restoring 
1131         // the original colourmap 
1134             ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
); 
1141     if (m_palette
.Ok() && m_palette
.GetHPALETTE()) 
1143         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
); 
1145             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
1147         ::RealizePalette(GetHdc()); 
1151 #endif // wxUSE_PALETTE 
1153 void wxDC::SetFont(const wxFont
& the_font
) 
1155 #ifdef __WXMICROWIN__ 
1156     if (!GetHDC()) return; 
1159     // Set the old object temporarily, in case the assignment deletes an object 
1160     // that's not yet selected out. 
1163         ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
1172             ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
1176     if (m_font
.Ok() && m_font
.GetResourceHandle()) 
1178         HFONT f 
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle()); 
1179         if (f 
== (HFONT
) NULL
) 
1181             wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont.")); 
1184             m_oldFont 
= (WXHFONT
) f
; 
1188 void wxDC::SetPen(const wxPen
& pen
) 
1190 #ifdef __WXMICROWIN__ 
1191     if (!GetHDC()) return; 
1194     // Set the old object temporarily, in case the assignment deletes an object 
1195     // that's not yet selected out. 
1198         ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
1207             ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
1213         if (m_pen
.GetResourceHandle()) 
1215             HPEN p 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle()); 
1217                 m_oldPen 
= (WXHPEN
) p
; 
1222 void wxDC::SetBrush(const wxBrush
& brush
) 
1224 #ifdef __WXMICROWIN__ 
1225     if (!GetHDC()) return; 
1228     // Set the old object temporarily, in case the assignment deletes an object 
1229     // that's not yet selected out. 
1232         ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
1241             ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
1247         // to make sure the brush is alligned with the logical coordinates 
1248         wxBitmap 
*stipple 
= m_brush
.GetStipple(); 
1249         if ( stipple 
&& stipple
->Ok() ) 
1252                 ::SetBrushOrgEx(GetHdc(), 
1253                             m_deviceOriginX 
% stipple
->GetWidth(), 
1254                             m_deviceOriginY 
% stipple
->GetHeight(), 
1255                             NULL
);  // don't need previous brush origin 
1257                 ::SetBrushOrg(GetHdc(), 
1258                             m_deviceOriginX 
% stipple
->GetWidth(), 
1259                             m_deviceOriginY 
% stipple
->GetHeight()); 
1263         if ( m_brush
.GetResourceHandle() ) 
1266             b 
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle()); 
1268                 m_oldBrush 
= (WXHBRUSH
) b
; 
1273 void wxDC::SetBackground(const wxBrush
& brush
) 
1275 #ifdef __WXMICROWIN__ 
1276     if (!GetHDC()) return; 
1279     m_backgroundBrush 
= brush
; 
1281     if (!m_backgroundBrush
.Ok()) 
1286         bool customColours 
= TRUE
; 
1287         // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to 
1288         // change background colours from the control-panel specified colours. 
1289         if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
)) 
1290             customColours 
= FALSE
; 
1294             if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
) 
1296                 m_canvas
->SetTransparent(TRUE
); 
1300                 // New behaviour, 10/2/99: setting the background brush of a DC 
1301                 // doesn't affect the window background colour. However, 
1302                 // I'm leaving in the transparency setting because it's needed by 
1303                 // various controls (e.g. wxStaticText) to determine whether to draw 
1304                 // transparently or not. TODO: maybe this should be a new function 
1305                 // wxWindow::SetTransparency(). Should that apply to the child itself, or the 
1307                 //        m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour()); 
1308                 m_canvas
->SetTransparent(FALSE
); 
1312     COLORREF new_color 
= m_backgroundBrush
.GetColour().GetPixel(); 
1314         (void)SetBkColor(GetHdc(), new_color
); 
1318 void wxDC::SetBackgroundMode(int mode
) 
1320 #ifdef __WXMICROWIN__ 
1321     if (!GetHDC()) return; 
1324     m_backgroundMode 
= mode
; 
1326     // SetBackgroundColour now only refers to text background 
1327     // and m_backgroundMode is used there 
1330     if (m_backgroundMode == wxTRANSPARENT) 
1331         ::SetBkMode(GetHdc(), TRANSPARENT); 
1333         ::SetBkMode(GetHdc(), OPAQUE); 
1334         Last change:  AC   29 Jan 101    8:54 pm 
1338 void wxDC::SetLogicalFunction(int function
) 
1340 #ifdef __WXMICROWIN__ 
1341     if (!GetHDC()) return; 
1344     m_logicalFunction 
= function
; 
1349 void wxDC::SetRop(WXHDC dc
) 
1351     if ( !dc 
|| m_logicalFunction 
< 0 ) 
1356     switch (m_logicalFunction
) 
1358         case wxCLEAR
:        rop 
= R2_BLACK
;         break; 
1359         case wxXOR
:          rop 
= R2_XORPEN
;        break; 
1360         case wxINVERT
:       rop 
= R2_NOT
;           break; 
1361         case wxOR_REVERSE
:   rop 
= R2_MERGEPENNOT
;   break; 
1362         case wxAND_REVERSE
:  rop 
= R2_MASKPENNOT
;    break; 
1363         case wxCOPY
:         rop 
= R2_COPYPEN
;       break; 
1364         case wxAND
:          rop 
= R2_MASKPEN
;       break; 
1365         case wxAND_INVERT
:   rop 
= R2_MASKNOTPEN
;    break; 
1366         case wxNO_OP
:        rop 
= R2_NOP
;           break; 
1367         case wxNOR
:          rop 
= R2_NOTMERGEPEN
;   break; 
1368         case wxEQUIV
:        rop 
= R2_NOTXORPEN
;     break; 
1369         case wxSRC_INVERT
:   rop 
= R2_NOTCOPYPEN
;    break; 
1370         case wxOR_INVERT
:    rop 
= R2_MERGENOTPEN
;   break; 
1371         case wxNAND
:         rop 
= R2_NOTMASKPEN
;    break; 
1372         case wxOR
:           rop 
= R2_MERGEPEN
;      break; 
1373         case wxSET
:          rop 
= R2_WHITE
;         break; 
1376            wxFAIL_MSG( wxT("unsupported logical function") ); 
1380     SetROP2(GetHdc(), rop
); 
1383 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
)) 
1385     // We might be previewing, so return TRUE to let it continue. 
1393 void wxDC::StartPage() 
1397 void wxDC::EndPage() 
1401 // --------------------------------------------------------------------------- 
1403 // --------------------------------------------------------------------------- 
1405 wxCoord 
wxDC::GetCharHeight() const 
1407 #ifdef __WXMICROWIN__ 
1408     if (!GetHDC()) return 0; 
1411     TEXTMETRIC lpTextMetric
; 
1413     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1415     return YDEV2LOGREL(lpTextMetric
.tmHeight
); 
1418 wxCoord 
wxDC::GetCharWidth() const 
1420 #ifdef __WXMICROWIN__ 
1421     if (!GetHDC()) return 0; 
1424     TEXTMETRIC lpTextMetric
; 
1426     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1428     return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
); 
1431 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord 
*x
, wxCoord 
*y
, 
1432                            wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1435 #ifdef __WXMICROWIN__ 
1440         if (descent
) *descent 
= 0; 
1441         if (externalLeading
) *externalLeading 
= 0; 
1449         wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") ); 
1451         hfontOld 
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
)); 
1453     else // don't change the font 
1461     GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
); 
1462     GetTextMetrics(GetHdc(), &tm
); 
1464     if (x
) *x 
= XDEV2LOGREL(sizeRect
.cx
); 
1465     if (y
) *y 
= YDEV2LOGREL(sizeRect
.cy
); 
1466     if (descent
) *descent 
= tm
.tmDescent
; 
1467     if (externalLeading
) *externalLeading 
= tm
.tmExternalLeading
; 
1471         ::SelectObject(GetHdc(), hfontOld
); 
1475 void wxDC::SetMapMode(int mode
) 
1477 #ifdef __WXMICROWIN__ 
1478     if (!GetHDC()) return; 
1481     m_mappingMode 
= mode
; 
1483     int pixel_width 
= 0; 
1484     int pixel_height 
= 0; 
1488     pixel_width 
= GetDeviceCaps(GetHdc(), HORZRES
); 
1489     pixel_height 
= GetDeviceCaps(GetHdc(), VERTRES
); 
1490     mm_width 
= GetDeviceCaps(GetHdc(), HORZSIZE
); 
1491     mm_height 
= GetDeviceCaps(GetHdc(), VERTSIZE
); 
1493     if ((pixel_width 
== 0) || (pixel_height 
== 0) || (mm_width 
== 0) || (mm_height 
== 0)) 
1498     double mm2pixelsX 
= pixel_width
/mm_width
; 
1499     double mm2pixelsY 
= pixel_height
/mm_height
; 
1505             m_logicalScaleX 
= (twips2mm 
* mm2pixelsX
); 
1506             m_logicalScaleY 
= (twips2mm 
* mm2pixelsY
); 
1511             m_logicalScaleX 
= (pt2mm 
* mm2pixelsX
); 
1512             m_logicalScaleY 
= (pt2mm 
* mm2pixelsY
); 
1517             m_logicalScaleX 
= mm2pixelsX
; 
1518             m_logicalScaleY 
= mm2pixelsY
; 
1523             m_logicalScaleX 
= (mm2pixelsX
/10.0); 
1524             m_logicalScaleY 
= (mm2pixelsY
/10.0); 
1530             m_logicalScaleX 
= 1.0; 
1531             m_logicalScaleY 
= 1.0; 
1536     if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
) 
1537         ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1539     SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1540     m_windowExtX 
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
); 
1541     m_windowExtY 
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
); 
1542     ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
); 
1543     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1544     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1547 void wxDC::SetUserScale(double x
, double y
) 
1549 #ifdef __WXMICROWIN__ 
1550     if (!GetHDC()) return; 
1556     SetMapMode(m_mappingMode
); 
1559 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
) 
1561 #ifdef __WXMICROWIN__ 
1562     if (!GetHDC()) return; 
1565     m_signX 
= xLeftRight 
? 1 : -1; 
1566     m_signY 
= yBottomUp 
? -1 : 1; 
1568     SetMapMode(m_mappingMode
); 
1571 void wxDC::SetSystemScale(double x
, double y
) 
1573 #ifdef __WXMICROWIN__ 
1574     if (!GetHDC()) return; 
1580     SetMapMode(m_mappingMode
); 
1583 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1585 #ifdef __WXMICROWIN__ 
1586     if (!GetHDC()) return; 
1589     m_logicalOriginX 
= x
; 
1590     m_logicalOriginY 
= y
; 
1592     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1595 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1597 #ifdef __WXMICROWIN__ 
1598     if (!GetHDC()) return; 
1601     m_deviceOriginX 
= x
; 
1602     m_deviceOriginY 
= y
; 
1604     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1607 // --------------------------------------------------------------------------- 
1608 // coordinates transformations 
1609 // --------------------------------------------------------------------------- 
1611 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1613     double xRel 
= x 
- m_deviceOriginX
; 
1614     xRel 
/= m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
; 
1615     return (wxCoord
)(xRel 
+ m_logicalOriginX
); 
1618 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1620     return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
)); 
1623 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
1625     double yRel 
= y 
- m_deviceOriginY
; 
1626     yRel 
/= m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
; 
1627     return (wxCoord
)(yRel 
+ m_logicalOriginY
); 
1630 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
1632     return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
)); 
1635 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
1637     return (wxCoord
) ((x 
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX 
+ m_deviceOriginX
); 
1640 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
1642     return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
); 
1645 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
1647     return (wxCoord
) ((y 
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY 
+ m_deviceOriginY
); 
1650 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
1652     return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
); 
1655 // --------------------------------------------------------------------------- 
1657 // --------------------------------------------------------------------------- 
1659 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, 
1660                   wxCoord width
, wxCoord height
, 
1661                   wxDC 
*source
, wxCoord xsrc
, wxCoord ysrc
, 
1662                   int rop
, bool useMask
, 
1663                   wxCoord xsrcMask
, wxCoord ysrcMask
) 
1665 #ifdef __WXMICROWIN__ 
1666     if (!GetHDC()) return FALSE
; 
1669     wxMask 
*mask 
= NULL
; 
1672         const wxBitmap
& bmp 
= source
->m_selectedBitmap
; 
1673         mask 
= bmp
.GetMask(); 
1675         if ( !(bmp
.Ok() && mask 
&& mask
->GetMaskBitmap()) ) 
1677             // don't give assert here because this would break existing 
1678             // programs - just silently ignore useMask parameter 
1683     if (xsrcMask 
== -1 && ysrcMask 
== -1) 
1685         xsrcMask 
= xsrc
; ysrcMask 
= ysrc
; 
1688     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1689     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1690     if (m_textForegroundColour
.Ok()) 
1692         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1694     if (m_textBackgroundColour
.Ok()) 
1696         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1699     DWORD dwRop 
= SRCCOPY
; 
1702         case wxXOR
:          dwRop 
= SRCINVERT
;        break; 
1703         case wxINVERT
:       dwRop 
= DSTINVERT
;        break; 
1704         case wxOR_REVERSE
:   dwRop 
= 0x00DD0228;       break; 
1705         case wxAND_REVERSE
:  dwRop 
= SRCERASE
;         break; 
1706         case wxCLEAR
:        dwRop 
= BLACKNESS
;        break; 
1707         case wxSET
:          dwRop 
= WHITENESS
;        break; 
1708         case wxOR_INVERT
:    dwRop 
= MERGEPAINT
;       break; 
1709         case wxAND
:          dwRop 
= SRCAND
;           break; 
1710         case wxOR
:           dwRop 
= SRCPAINT
;         break; 
1711         case wxEQUIV
:        dwRop 
= 0x00990066;       break; 
1712         case wxNAND
:         dwRop 
= 0x007700E6;       break; 
1713         case wxAND_INVERT
:   dwRop 
= 0x00220326;       break; 
1714         case wxCOPY
:         dwRop 
= SRCCOPY
;          break; 
1715         case wxNO_OP
:        dwRop 
= DSTCOPY
;          break; 
1716         case wxSRC_INVERT
:   dwRop 
= NOTSRCCOPY
;       break; 
1717         case wxNOR
:          dwRop 
= NOTSRCCOPY
;       break; 
1719            wxFAIL_MSG( wxT("unsupported logical function") ); 
1723     bool success 
= FALSE
; 
1728         // we want the part of the image corresponding to the mask to be 
1729         // transparent, so use "DSTCOPY" ROP for the mask points (the usual 
1730         // meaning of fg and bg is inverted which corresponds to wxWin notion 
1731         // of the mask which is also contrary to the Windows one) 
1733         // On some systems, MaskBlt succeeds yet is much much slower 
1734         // than the wxWindows fall-back implementation. So we need 
1735         // to be able to switch this on and off at runtime. 
1736 #if wxUSE_SYSTEM_OPTIONS 
1737         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1740            success 
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
, 
1741                             GetHdcOf(*source
), xsrc
, ysrc
, 
1742                             (HBITMAP
)mask
->GetMaskBitmap(), xsrcMask
, ysrcMask
, 
1743                             MAKEROP4(dwRop
, DSTCOPY
)) != 0; 
1749             // Blit bitmap with mask 
1752             HBITMAP buffer_bmap 
; 
1754 #if wxUSE_DC_CACHEING 
1755             // create a temp buffer bitmap and DCs to access it and the mask 
1756             wxDCCacheEntry
* dcCacheEntry1 
= FindDCInCache(NULL
, source
->GetHDC()); 
1757             dc_mask 
= (HDC
) dcCacheEntry1
->m_dc
; 
1759             wxDCCacheEntry
* dcCacheEntry2 
= FindDCInCache(dcCacheEntry1
, GetHDC()); 
1760             dc_buffer 
= (HDC
) dcCacheEntry2
->m_dc
; 
1762             wxDCCacheEntry
* bitmapCacheEntry 
= FindBitmapInCache(GetHDC(), 
1765             buffer_bmap 
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
; 
1766 #else // !wxUSE_DC_CACHEING 
1767             // create a temp buffer bitmap and DCs to access it and the mask 
1768             dc_mask 
= ::CreateCompatibleDC(GetHdcOf(*source
)); 
1769             dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
1770             buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
1771 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING 
1772             ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap()); 
1773             ::SelectObject(dc_buffer
, buffer_bmap
); 
1775             // copy dest to buffer 
1776             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1777                            GetHdc(), xdest
, ydest
, SRCCOPY
) ) 
1779                 wxLogLastError(wxT("BitBlt")); 
1782             // copy src to buffer using selected raster op 
1783             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1784                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) ) 
1786                 wxLogLastError(wxT("BitBlt")); 
1789             // set masked area in buffer to BLACK (pixel value 0) 
1790             COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
1791             COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
1792             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1793                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
1795                 wxLogLastError(wxT("BitBlt")); 
1798             // set unmasked area in dest to BLACK 
1799             ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
1800             ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
1801             if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
, 
1802                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
1804                 wxLogLastError(wxT("BitBlt")); 
1806             ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
1807             ::SetTextColor(GetHdc(), prevCol
); 
1809             // OR buffer to dest 
1810             success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
1811                                (int)width
, (int)height
, 
1812                                dc_buffer
, 0, 0, SRCPAINT
) != 0; 
1815                 wxLogLastError(wxT("BitBlt")); 
1818             // tidy up temporary DCs and bitmap 
1819             ::SelectObject(dc_mask
, 0); 
1820             ::SelectObject(dc_buffer
, 0); 
1822 #if !wxUSE_DC_CACHEING 
1824                 ::DeleteDC(dc_mask
); 
1825                 ::DeleteDC(dc_buffer
); 
1826                 ::DeleteObject(buffer_bmap
); 
1831     else // no mask, just BitBlt() it 
1833         success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
1834                            (int)width
, (int)height
, 
1835                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0; 
1838             wxLogLastError(wxT("BitBlt")); 
1841     ::SetTextColor(GetHdc(), old_textground
); 
1842     ::SetBkColor(GetHdc(), old_background
); 
1847 void wxDC::DoGetSize(int *w
, int *h
) const 
1849 #ifdef __WXMICROWIN__ 
1850     if (!GetHDC()) return; 
1853     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
1854     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
1857 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
1859 #ifdef __WXMICROWIN__ 
1860     if (!GetHDC()) return; 
1863     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
); 
1864     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1867 wxSize 
wxDC::GetPPI() const 
1869 #ifdef __WXMICROWIN__ 
1870     if (!GetHDC()) return wxSize(); 
1873     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
1874     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
1876     return wxSize(x
, y
); 
1879 // For use by wxWindows only, unless custom units are required. 
1880 void wxDC::SetLogicalScale(double x
, double y
) 
1882 #ifdef __WXMICROWIN__ 
1883     if (!GetHDC()) return; 
1886     m_logicalScaleX 
= x
; 
1887     m_logicalScaleY 
= y
; 
1890 #if WXWIN_COMPATIBILITY 
1891 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
, 
1892                          float *descent
, float *externalLeading
, 
1893                          wxFont 
*theFont
, bool use16bit
) const 
1895 #ifdef __WXMICROWIN__ 
1896     if (!GetHDC()) return; 
1899     wxCoord x1
, y1
, descent1
, externalLeading1
; 
1900     GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
); 
1903         *descent 
= descent1
; 
1904     if (externalLeading
) 
1905         *externalLeading 
= externalLeading1
; 
1909 #if wxUSE_DC_CACHEING 
1912  * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will 
1913  * improve it in due course, either using arrays, or simply storing pointers to one 
1914  * entry for the bitmap, and two for the DCs. -- JACS 
1917 wxList 
wxDC::sm_bitmapCache
; 
1918 wxList 
wxDC::sm_dcCache
; 
1920 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
) 
1929 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
) 
1938 wxDCCacheEntry::~wxDCCacheEntry() 
1941         ::DeleteObject((HBITMAP
) m_bitmap
); 
1943         ::DeleteDC((HDC
) m_dc
); 
1946 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
) 
1948     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
1949     wxNode
* node 
= sm_bitmapCache
.First(); 
1952         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->Data(); 
1954         if (entry
->m_depth 
== depth
) 
1956             if (entry
->m_width 
< w 
|| entry
->m_height 
< h
) 
1958                 ::DeleteObject((HBITMAP
) entry
->m_bitmap
); 
1959                 entry
->m_bitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
1960                 if ( !entry
->m_bitmap
) 
1962                     wxLogLastError(wxT("CreateCompatibleBitmap")); 
1964                 entry
->m_width 
= w
; entry
->m_height 
= h
; 
1970         node 
= node
->Next(); 
1972     WXHBITMAP hBitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
1975         wxLogLastError(wxT("CreateCompatibleBitmap")); 
1977     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
); 
1978     AddToBitmapCache(entry
); 
1982 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
) 
1984     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
1985     wxNode
* node 
= sm_dcCache
.First(); 
1988         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->Data(); 
1990         // Don't return the same one as we already have 
1991         if (!notThis 
|| (notThis 
!= entry
)) 
1993             if (entry
->m_depth 
== depth
) 
1999         node 
= node
->Next(); 
2001     WXHDC hDC 
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
); 
2004         wxLogLastError(wxT("CreateCompatibleDC")); 
2006     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hDC
, depth
); 
2007     AddToDCCache(entry
); 
2011 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
) 
2013     sm_bitmapCache
.Append(entry
); 
2016 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
) 
2018     sm_dcCache
.Append(entry
); 
2021 void wxDC::ClearCache() 
2023     sm_bitmapCache
.DeleteContents(TRUE
); 
2024     sm_bitmapCache
.Clear(); 
2025     sm_bitmapCache
.DeleteContents(FALSE
); 
2026     sm_dcCache
.DeleteContents(TRUE
); 
2028     sm_dcCache
.DeleteContents(FALSE
); 
2031 // Clean up cache at app exit 
2032 class wxDCModule 
: public wxModule
 
2035     virtual bool OnInit() { return TRUE
; } 
2036     virtual void OnExit() { wxDC::ClearCache(); } 
2039     DECLARE_DYNAMIC_CLASS(wxDCModule
) 
2042 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
) 
2045     // wxUSE_DC_CACHEING