1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  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/msw/private.h" // needs to be before #include <commdlg.h> 
  45 #include "wx/sysopt.h" 
  46 #include "wx/dcprint.h" 
  47 #include "wx/module.h" 
  48 #include "wx/dynload.h" 
  50 #ifdef wxHAVE_RAW_BITMAP 
  51 #include "wx/rawbmp.h" 
  57 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__) 
  66 #define AC_SRC_ALPHA 1 
  69 /* Quaternary raster codes */ 
  71 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) 
  74 // apparently with MicroWindows it is possible that HDC is 0 so we have to 
  75 // check for this ourselves 
  77     #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return; 
  78     #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x; 
  80     #define WXMICROWIN_CHECK_HDC 
  81     #define WXMICROWIN_CHECK_HDC_RET(x) 
  84 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
) 
  86 // --------------------------------------------------------------------------- 
  88 // --------------------------------------------------------------------------- 
  90 static const int VIEWPORT_EXTENT 
= 1000; 
  92 static const int MM_POINTS 
= 9; 
  93 static const int MM_METRIC 
= 10; 
  95 // usually this is defined in math.h 
  97     static const double M_PI 
= 3.14159265358979323846; 
 100 // ROPs which don't have standard names (see "Ternary Raster Operations" in the 
 101 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) 
 102 #define DSTCOPY 0x00AA0029      // a.k.a. NOP operation 
 104 // ---------------------------------------------------------------------------- 
 105 // macros for logical <-> device coords conversion 
 106 // ---------------------------------------------------------------------------- 
 109    We currently let Windows do all the translations itself so these macros are 
 110    not really needed (any more) but keep them to enhance readability of the 
 111    code by allowing to see where are the logical and where are the device 
 116 #define XLOG2DEV(x) (x) 
 117 #define YLOG2DEV(y) (y) 
 120 #define XDEV2LOG(x) (x) 
 121 #define YDEV2LOG(y) (y) 
 123 // --------------------------------------------------------------------------- 
 125 // --------------------------------------------------------------------------- 
 127 // convert degrees to radians 
 128 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
 130 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha 
 132 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed 
 133 //     to pass it to this function but as we already have it at the point 
 134 //     of call anyhow we do 
 136 // return true if we could draw the bitmap in one way or the other, false 
 138 static bool AlphaBlt(HDC hdcDst
, 
 139                      int x
, int y
, int w
, int h
, 
 141                      const wxBitmap
& bmpSrc
); 
 143 #ifdef wxHAVE_RAW_BITMAP 
 144 // our (limited) AlphaBlend() replacement 
 146 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
); 
 149 // ---------------------------------------------------------------------------- 
 151 // ---------------------------------------------------------------------------- 
 153 // instead of duplicating the same code which sets and then restores text 
 154 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, 
 155 // encapsulate this in a small helper class 
 157 // wxColourChanger: changes the text colours in the ctor if required and 
 158 //                  restores them in the dtor 
 159 class wxColourChanger
 
 162     wxColourChanger(wxDC
& dc
); 
 168     COLORREF m_colFgOld
, m_colBgOld
; 
 172     DECLARE_NO_COPY_CLASS(wxColourChanger
) 
 175 // this class saves the old stretch blit mode during its life time 
 176 class StretchBltModeChanger
 
 179     StretchBltModeChanger(HDC hdc
, int mode
) 
 183         m_modeOld 
= ::SetStretchBltMode(m_hdc
, mode
); 
 185             wxLogLastError(_T("SetStretchBltMode")); 
 189     ~StretchBltModeChanger() 
 192         if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) ) 
 193             wxLogLastError(_T("SetStretchBltMode")); 
 202     DECLARE_NO_COPY_CLASS(StretchBltModeChanger
) 
 205 // =========================================================================== 
 207 // =========================================================================== 
 209 // ---------------------------------------------------------------------------- 
 211 // ---------------------------------------------------------------------------- 
 213 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
) 
 215     const wxBrush
& brush 
= dc
.GetBrush(); 
 216     if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 218         HDC hdc 
= GetHdcOf(dc
); 
 219         m_colFgOld 
= ::GetTextColor(hdc
); 
 220         m_colBgOld 
= ::GetBkColor(hdc
); 
 222         // note that Windows convention is opposite to wxWindows one, this is 
 223         // why text colour becomes the background one and vice versa 
 224         const wxColour
& colFg 
= dc
.GetTextForeground(); 
 227             ::SetBkColor(hdc
, colFg
.GetPixel()); 
 230         const wxColour
& colBg 
= dc
.GetTextBackground(); 
 233             ::SetTextColor(hdc
, colBg
.GetPixel()); 
 237                   dc
.GetBackgroundMode() == wxTRANSPARENT 
? TRANSPARENT
 
 240         // flag which telsl us to undo changes in the dtor 
 245         // nothing done, nothing to undo 
 250 wxColourChanger::~wxColourChanger() 
 254         // restore the colours we changed 
 255         HDC hdc 
= GetHdcOf(m_dc
); 
 257         ::SetBkMode(hdc
, TRANSPARENT
); 
 258         ::SetTextColor(hdc
, m_colFgOld
); 
 259         ::SetBkColor(hdc
, m_colBgOld
); 
 263 // --------------------------------------------------------------------------- 
 265 // --------------------------------------------------------------------------- 
 267 // Default constructor 
 278 #endif // wxUSE_PALETTE 
 288         SelectOldObjects(m_hDC
); 
 290         // if we own the HDC, we delete it, otherwise we just release it 
 294             ::DeleteDC(GetHdc()); 
 296         else // we don't own our HDC 
 300                 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc()); 
 304                 // Must have been a wxScreenDC 
 305                 ::ReleaseDC((HWND
) NULL
, GetHdc()); 
 311 // This will select current objects out of the DC, 
 312 // which is what you have to do before deleting the 
 314 void wxDC::SelectOldObjects(WXHDC dc
) 
 320             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 322             if (m_selectedBitmap
.Ok()) 
 324                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 331             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 336             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 341             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 348             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
); 
 351 #endif // wxUSE_PALETTE 
 354     m_brush 
= wxNullBrush
; 
 357     m_palette 
= wxNullPalette
; 
 358 #endif // wxUSE_PALETTE 
 360     m_backgroundBrush 
= wxNullBrush
; 
 361     m_selectedBitmap 
= wxNullBitmap
; 
 364 // --------------------------------------------------------------------------- 
 366 // --------------------------------------------------------------------------- 
 368 void wxDC::UpdateClipBox() 
 373     ::GetClipBox(GetHdc(), &rect
); 
 375     m_clipX1 
= (wxCoord
) XDEV2LOG(rect
.left
); 
 376     m_clipY1 
= (wxCoord
) YDEV2LOG(rect
.top
); 
 377     m_clipX2 
= (wxCoord
) XDEV2LOG(rect
.right
); 
 378     m_clipY2 
= (wxCoord
) YDEV2LOG(rect
.bottom
); 
 381 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion() 
 382 void wxDC::SetClippingHrgn(WXHRGN hrgn
) 
 384     wxCHECK_RET( hrgn
, wxT("invalid clipping region") ); 
 388     // note that we combine the new clipping region with the existing one: this 
 389     // is compatible with what the other ports do and is the documented 
 390     // behaviour now (starting with 2.3.3) 
 391 #if defined(__WIN16__) || defined(__WXWINCE__) 
 393     if ( !::GetClipBox(GetHdc(), &rectClip
) ) 
 396     HRGN hrgnDest 
= ::CreateRectRgn(0, 0, 0, 0); 
 397     HRGN hrgnClipOld 
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
, 
 398                                        rectClip
.right
, rectClip
.bottom
); 
 400     if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR 
) 
 402         ::SelectClipRgn(GetHdc(), hrgnDest
); 
 405     ::DeleteObject(hrgnClipOld
); 
 406     ::DeleteObject(hrgnDest
); 
 408     if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR 
) 
 410         wxLogLastError(_T("ExtSelectClipRgn")); 
 421 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 423     // the region coords are always the device ones, so do the translation 
 426     // FIXME: possible +/-1 error here, to check! 
 427     HRGN hrgn 
= ::CreateRectRgn(LogicalToDeviceX(x
), 
 429                                 LogicalToDeviceX(x 
+ w
), 
 430                                 LogicalToDeviceY(y 
+ h
)); 
 433         wxLogLastError(_T("CreateRectRgn")); 
 437         SetClippingHrgn((WXHRGN
)hrgn
); 
 439         ::DeleteObject(hrgn
); 
 443 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 445     SetClippingHrgn(region
.GetHRGN()); 
 448 void wxDC::DestroyClippingRegion() 
 452     if (m_clipping 
&& m_hDC
) 
 454         // TODO: this should restore the previous clipping region, 
 455         //       so that OnPaint processing works correctly, and the update 
 456         //       clipping region doesn't get destroyed after the first 
 457         //       DestroyClippingRegion. 
 458         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 459         ::SelectClipRgn(GetHdc(), rgn
); 
 466 // --------------------------------------------------------------------------- 
 467 // query capabilities 
 468 // --------------------------------------------------------------------------- 
 470 bool wxDC::CanDrawBitmap() const 
 475 bool wxDC::CanGetTextExtent() const 
 477 #ifdef __WXMICROWIN__ 
 478     // TODO Extend MicroWindows' GetDeviceCaps function 
 481     // What sort of display is it? 
 482     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 484     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 488 int wxDC::GetDepth() const 
 490     WXMICROWIN_CHECK_HDC_RET(16) 
 492     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 495 // --------------------------------------------------------------------------- 
 497 // --------------------------------------------------------------------------- 
 506         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 510         // No, I think we should simply ignore this if printing on e.g. 
 512         // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 
 513         if (!m_selectedBitmap
.Ok()) 
 516         rect
.left 
= 0; rect
.top 
= 0; 
 517         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 518         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 522     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 525     DWORD colour 
= ::GetBkColor(GetHdc()); 
 526     HBRUSH brush 
= ::CreateSolidBrush(colour
); 
 527     ::FillRect(GetHdc(), &rect
, brush
); 
 528     ::DeleteObject(brush
); 
 530     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
 531         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
 534     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 536     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 537     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
 538     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 539     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 543 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
) 
 549     WXMICROWIN_CHECK_HDC_RET(false) 
 551     bool success 
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 553                          style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 554                                                   : FLOODFILLBORDER
) ) ; 
 557         // quoting from the MSDN docs: 
 559         //      Following are some of the reasons this function might fail: 
 561         //      * The filling could not be completed. 
 562         //      * The specified point has the boundary color specified by the 
 563         //        crColor parameter (if FLOODFILLBORDER was requested). 
 564         //      * The specified point does not have the color specified by 
 565         //        crColor (if FLOODFILLSURFACE was requested) 
 566         //      * The point is outside the clipping region that is, it is not 
 567         //        visible on the device. 
 569         wxLogLastError(wxT("ExtFloodFill")); 
 572     CalcBoundingBox(x
, y
); 
 578 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour 
*col
) const 
 580     WXMICROWIN_CHECK_HDC_RET(false) 
 582     wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") ); 
 584     // get the color of the pixel 
 585     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 587     wxRGBToColour(*col
, pixelcolor
); 
 592 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
) 
 596     wxCoord x1 
= x
-VIEWPORT_EXTENT
; 
 597     wxCoord y1 
= y
-VIEWPORT_EXTENT
; 
 598     wxCoord x2 
= x
+VIEWPORT_EXTENT
; 
 599     wxCoord y2 
= y
+VIEWPORT_EXTENT
; 
 601     wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 602     wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 604     CalcBoundingBox(x1
, y1
); 
 605     CalcBoundingBox(x2
, y2
); 
 608 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 612     wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 614     CalcBoundingBox(x1
, y1
); 
 615     CalcBoundingBox(x2
, y2
); 
 618 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) 
 619 // and ending at (x2, y2) 
 620 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
, 
 621                      wxCoord x2
, wxCoord y2
, 
 622                      wxCoord xc
, wxCoord yc
) 
 625     // Slower emulation since WinCE doesn't support Pie and Arc 
 626     double r 
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) ); 
 627     double sa 
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180 
 628     if( y1
>yc 
) sa 
= -sa
; // below center 
 629     double ea 
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180; 
 630     DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea 
); 
 635     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 639     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
); 
 640     wxCoord r 
= (wxCoord
)radius
; 
 642     // treat the special case of full circle separately 
 643     if ( x1 
== x2 
&& y1 
== y2 
) 
 645         DrawEllipse(xc 
- r
, yc 
- r
, 2*r
, 2*r
); 
 649     wxCoord xx1 
= XLOG2DEV(x1
); 
 650     wxCoord yy1 
= YLOG2DEV(y1
); 
 651     wxCoord xx2 
= XLOG2DEV(x2
); 
 652     wxCoord yy2 
= YLOG2DEV(y2
); 
 653     wxCoord xxc 
= XLOG2DEV(xc
); 
 654     wxCoord yyc 
= YLOG2DEV(yc
); 
 655     wxCoord ray 
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 657     wxCoord xxx1 
= (wxCoord
) (xxc
-ray
); 
 658     wxCoord yyy1 
= (wxCoord
) (yyc
-ray
); 
 659     wxCoord xxx2 
= (wxCoord
) (xxc
+ray
); 
 660     wxCoord yyy2 
= (wxCoord
) (yyc
+ray
); 
 662     if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT 
) 
 664         // Have to add 1 to bottom-right corner of rectangle 
 665         // to make semi-circles look right (crooked line otherwise). 
 666         // Unfortunately this is not a reliable method, depends 
 667         // on the size of shape. 
 668         // TODO: figure out why this happens! 
 669         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
); 
 673         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
); 
 676     CalcBoundingBox(xc 
- r
, yc 
- r
); 
 677     CalcBoundingBox(xc 
+ r
, yc 
+ r
); 
 681 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
 682                            wxCoord width
, wxCoord height
) 
 686     wxCoord x2 
= x1 
+ width
, 
 689 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__) 
 697     DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
); 
 699     DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
); 
 702     // In WIN16, draw a cross 
 703     HPEN blackPen 
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0)); 
 704     HPEN whiteBrush 
= (HPEN
)::GetStockObject(WHITE_BRUSH
); 
 705     HPEN hPenOld 
= (HPEN
)::SelectObject(GetHdc(), blackPen
); 
 706     HPEN hBrushOld 
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
); 
 707     ::SetROP2(GetHdc(), R2_COPYPEN
); 
 708     Rectangle(GetHdc(), x1
, y1
, x2
, y2
); 
 709     MoveToEx(GetHdc(), x1
, y1
, NULL
); 
 710     LineTo(GetHdc(), x2
, y2
); 
 711     MoveToEx(GetHdc(), x2
, y1
, NULL
); 
 712     LineTo(GetHdc(), x1
, y2
); 
 713     ::SelectObject(GetHdc(), hPenOld
); 
 714     ::SelectObject(GetHdc(), hBrushOld
); 
 715     ::DeleteObject(blackPen
); 
 718     CalcBoundingBox(x1
, y1
); 
 719     CalcBoundingBox(x2
, y2
); 
 722 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
) 
 726     COLORREF color 
= 0x00ffffff; 
 729         color 
= m_pen
.GetColour().GetPixel(); 
 732     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 734     CalcBoundingBox(x
, y
); 
 737 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
) 
 741     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 743     // Do things less efficiently if we have offsets 
 744     if (xoffset 
!= 0 || yoffset 
!= 0) 
 746         POINT 
*cpoints 
= new POINT
[n
]; 
 748         for (i 
= 0; i 
< n
; i
++) 
 750             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 751             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 753             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 756         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 758         (void)Polygon(GetHdc(), cpoints
, n
); 
 760         SetPolyFillMode(GetHdc(),prev
); 
 767         for (i 
= 0; i 
< n
; i
++) 
 768             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 771         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 773         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 775         SetPolyFillMode(GetHdc(),prev
); 
 781 wxDC::DoDrawPolyPolygon(int n
, 
 790     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 792     for (i 
= cnt 
= 0; i 
< n
; i
++) 
 795     // Do things less efficiently if we have offsets 
 796     if (xoffset 
!= 0 || yoffset 
!= 0) 
 798         POINT 
*cpoints 
= new POINT
[cnt
]; 
 799         for (i 
= 0; i 
< cnt
; i
++) 
 801             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 802             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 804             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 806         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 807         (void)PolyPolygon(GetHdc(), cpoints
, start
, n
); 
 808         SetPolyFillMode(GetHdc(),prev
); 
 813         for (i 
= 0; i 
< cnt
; i
++) 
 814             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 816         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 817         (void)PolyPolygon(GetHdc(), (POINT
*) points
, start
, n
); 
 818         SetPolyFillMode(GetHdc(),prev
); 
 822 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 826     // Do things less efficiently if we have offsets 
 827     if (xoffset 
!= 0 || yoffset 
!= 0) 
 829         POINT 
*cpoints 
= new POINT
[n
]; 
 831         for (i 
= 0; i 
< n
; i
++) 
 833             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 834             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 836             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 838         (void)Polyline(GetHdc(), cpoints
, n
); 
 844         for (i 
= 0; i 
< n
; i
++) 
 845             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 847         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 851 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 855     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 857     wxCoord x2 
= x 
+ width
; 
 858     wxCoord y2 
= y 
+ height
; 
 860     if ((m_logicalFunction 
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
)) 
 863         rect
.left 
= XLOG2DEV(x
); 
 864         rect
.top 
= YLOG2DEV(y
); 
 865         rect
.right 
= XLOG2DEV(x2
); 
 866         rect
.bottom 
= YLOG2DEV(y2
); 
 867         (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() ); 
 871         // Windows draws the filled rectangles without outline (i.e. drawn with a 
 872         // transparent pen) one pixel smaller in both directions and we want them 
 873         // to have the same size regardless of which pen is used - adjust 
 875         // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. 
 876         if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 882         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 886     CalcBoundingBox(x
, y
); 
 887     CalcBoundingBox(x2
, y2
); 
 890 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 894     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 896     // Now, a negative radius value is interpreted to mean 
 897     // 'the proportion of the smallest X or Y dimension' 
 901         double smallest 
= (width 
< height
) ? width 
: height
; 
 902         radius 
= (- radius 
* smallest
); 
 905     wxCoord x2 
= (x
+width
); 
 906     wxCoord y2 
= (y
+height
); 
 908     // Windows draws the filled rectangles without outline (i.e. drawn with a 
 909     // transparent pen) one pixel smaller in both directions and we want them 
 910     // to have the same size regardless of which pen is used - adjust 
 911     if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 917     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 918         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 920     CalcBoundingBox(x
, y
); 
 921     CalcBoundingBox(x2
, y2
); 
 924 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 928     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 930     wxCoord x2 
= (x
+width
); 
 931     wxCoord y2 
= (y
+height
); 
 933     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 935     CalcBoundingBox(x
, y
); 
 936     CalcBoundingBox(x2
, y2
); 
 939 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
 940 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 943     DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea 
); 
 948     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 953     int rx1 
= XLOG2DEV(x
+w
/2); 
 954     int ry1 
= YLOG2DEV(y
+h
/2); 
 961     rx1 
+= (int)(100.0 * abs(w
) * cos(sa
)); 
 962     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa
)); 
 963     rx2 
+= (int)(100.0 * abs(w
) * cos(ea
)); 
 964     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea
)); 
 966     // draw pie with NULL_PEN first and then outline otherwise a line is 
 967     // drawn from the start and end points to the centre 
 968     HPEN hpenOld 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 971         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
 976         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
 977                   rx1
, ry1
-1, rx2
, ry2
-1); 
 980     ::SelectObject(GetHdc(), hpenOld
); 
 982     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
 985     CalcBoundingBox(x
, y
); 
 986     CalcBoundingBox(x2
, y2
); 
 990 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
) 
 994     wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") ); 
 997     ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
); 
 999     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
)); 
1002     CalcBoundingBox(x
, y
); 
1003     CalcBoundingBox(x 
+ icon
.GetWidth(), y 
+ icon
.GetHeight()); 
1006 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, wxCoord x
, wxCoord y
, bool useMask 
) 
1008     WXMICROWIN_CHECK_HDC
 
1010     wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 
1012     int width 
= bmp
.GetWidth(), 
1013         height 
= bmp
.GetHeight(); 
1015     HBITMAP hbmpMask 
= 0; 
1018     HPALETTE oldPal 
= 0; 
1019 #endif // wxUSE_PALETTE 
1021     if ( bmp
.HasAlpha() ) 
1024         SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmp
)); 
1026         if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) ) 
1032         wxMask 
*mask 
= bmp
.GetMask(); 
1034             hbmpMask 
= (HBITMAP
)mask
->GetMaskBitmap(); 
1038             // don't give assert here because this would break existing 
1039             // programs - just silently ignore useMask parameter 
1046         // use MaskBlt() with ROP which doesn't do anything to dst in the mask 
1048         // On some systems, MaskBlt succeeds yet is much much slower 
1049         // than the wxWindows fall-back implementation. So we need 
1050         // to be able to switch this on and off at runtime. 
1052 #if wxUSE_SYSTEM_OPTIONS 
1053         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1057             HDC hdcMem 
= ::CreateCompatibleDC(GetHdc()); 
1058             HGDIOBJ hOldBitmap 
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
)); 
1060             wxPalette 
*pal 
= bmp
.GetPalette(); 
1061             if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1063                 oldPal 
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
); 
1064                 ::RealizePalette(hdcMem
); 
1066 #endif // wxUSE_PALETTE 
1068             ok 
= ::MaskBlt(cdc
, x
, y
, width
, height
, 
1071                             MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0; 
1075                 ::SelectPalette(hdcMem
, oldPal
, FALSE
); 
1076 #endif // wxUSE_PALETTE 
1078             ::SelectObject(hdcMem
, hOldBitmap
); 
1085             // Rather than reproduce wxDC::Blit, let's do it at the wxWin API 
1088             memDC
.SelectObject(bmp
); 
1090             Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
); 
1092             memDC
.SelectObject(wxNullBitmap
); 
1095     else // no mask, just use BitBlt() 
1098         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
1099         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
1101         wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") ); 
1103         COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1104         COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1105         if (m_textForegroundColour
.Ok()) 
1107             ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1109         if (m_textBackgroundColour
.Ok()) 
1111             ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1115         wxPalette 
*pal 
= bmp
.GetPalette(); 
1116         if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1118             oldPal 
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
); 
1119             ::RealizePalette(memdc
); 
1121 #endif // wxUSE_PALETTE 
1123         HGDIOBJ hOldBitmap 
= ::SelectObject( memdc
, hbitmap 
); 
1124         ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
); 
1128             ::SelectPalette(memdc
, oldPal
, FALSE
); 
1129 #endif // wxUSE_PALETTE 
1131         ::SelectObject( memdc
, hOldBitmap 
); 
1132         ::DeleteDC( memdc 
); 
1134         ::SetTextColor(GetHdc(), old_textground
); 
1135         ::SetBkColor(GetHdc(), old_background
); 
1139 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1141     WXMICROWIN_CHECK_HDC
 
1143     DrawAnyText(text
, x
, y
); 
1145     // update the bounding box 
1146     CalcBoundingBox(x
, y
); 
1149     GetTextExtent(text
, &w
, &h
); 
1150     CalcBoundingBox(x 
+ w
, y 
+ h
); 
1153 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1155     WXMICROWIN_CHECK_HDC
 
1157     // prepare for drawing the text 
1158     if ( m_textForegroundColour
.Ok() ) 
1159         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
1161     DWORD old_background 
= 0; 
1162     if ( m_textBackgroundColour
.Ok() ) 
1164         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1167     SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
1171     if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
, 
1172                    text
.c_str(), text
.length(), NULL
) == 0 ) 
1174         wxLogLastError(wxT("TextOut")); 
1177     if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
1178                    text
.c_str(), text
.length()) == 0 ) 
1180         wxLogLastError(wxT("TextOut")); 
1184     // restore the old parameters (text foreground colour may be left because 
1185     // it never is set to anything else, but background should remain 
1186     // transparent even if we just drew an opaque string) 
1187     if ( m_textBackgroundColour
.Ok() ) 
1188         (void)SetBkColor(GetHdc(), old_background
); 
1190     SetBkMode(GetHdc(), TRANSPARENT
); 
1193 void wxDC::DoDrawRotatedText(const wxString
& text
, 
1194                              wxCoord x
, wxCoord y
, 
1197     WXMICROWIN_CHECK_HDC
 
1199     // we test that we have some font because otherwise we should still use the 
1200     // "else" part below to avoid that DrawRotatedText(angle = 180) and 
1201     // DrawRotatedText(angle = 0) use different fonts (we can't use the default 
1202     // font for drawing rotated fonts unfortunately) 
1203     if ( (angle 
== 0.0) && m_font
.Ok() ) 
1205         DoDrawText(text
, x
, y
); 
1207 #ifndef __WXMICROWIN__ 
1210         // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) 
1211         //     because it's not TrueType and so can't have non zero 
1212         //     orientation/escapement under Win9x 
1213         wxFont font 
= m_font
.Ok() ? m_font 
: *wxSWISS_FONT
; 
1214         HFONT hfont 
= (HFONT
)font
.GetResourceHandle(); 
1216         if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 ) 
1218             wxLogLastError(wxT("GetObject(hfont)")); 
1221         // GDI wants the angle in tenth of degree 
1222         long angle10 
= (long)(angle 
* 10); 
1223         lf
.lfEscapement 
= angle10
; 
1224         lf
. lfOrientation 
= angle10
; 
1226         hfont 
= ::CreateFontIndirect(&lf
); 
1229             wxLogLastError(wxT("CreateFont")); 
1233             HFONT hfontOld 
= (HFONT
)::SelectObject(GetHdc(), hfont
); 
1235             DrawAnyText(text
, x
, y
); 
1237             (void)::SelectObject(GetHdc(), hfontOld
); 
1238             (void)::DeleteObject(hfont
); 
1241         // call the bounding box by adding all four vertices of the rectangle 
1242         // containing the text to it (simpler and probably not slower than 
1243         // determining which of them is really topmost/leftmost/...) 
1245         GetTextExtent(text
, &w
, &h
); 
1247         double rad 
= DegToRad(angle
); 
1249         // "upper left" and "upper right" 
1250         CalcBoundingBox(x
, y
); 
1251         CalcBoundingBox(x 
+ wxCoord(w
*cos(rad
)), y 
- wxCoord(h
*sin(rad
))); 
1253         // "bottom left" and "bottom right" 
1254         x 
+= (wxCoord
)(h
*sin(rad
)); 
1255         y 
+= (wxCoord
)(h
*cos(rad
)); 
1256         CalcBoundingBox(x
, y
); 
1257         CalcBoundingBox(x 
+ wxCoord(h
*sin(rad
)), y 
+ wxCoord(h
*cos(rad
))); 
1262 // --------------------------------------------------------------------------- 
1264 // --------------------------------------------------------------------------- 
1268 void wxDC::DoSelectPalette(bool realize
) 
1270     WXMICROWIN_CHECK_HDC
 
1272     // Set the old object temporarily, in case the assignment deletes an object 
1273     // that's not yet selected out. 
1276         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
); 
1280     if ( m_palette
.Ok() ) 
1282         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), 
1283                                           GetHpaletteOf(m_palette
), 
1286             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
1289             ::RealizePalette(GetHdc()); 
1293 void wxDC::SetPalette(const wxPalette
& palette
) 
1297         m_palette 
= palette
; 
1298         DoSelectPalette(true); 
1302 void wxDC::InitializePalette() 
1304     if ( wxDisplayDepth() <= 8 ) 
1306         // look for any window or parent that has a custom palette. If any has 
1307         // one then we need to use it in drawing operations 
1308         wxWindow 
*win 
= m_canvas
->GetAncestorWithCustomPalette(); 
1310         m_hasCustomPalette 
= win 
&& win
->HasCustomPalette(); 
1311         if ( m_hasCustomPalette 
) 
1313             m_palette 
= win
->GetPalette(); 
1315             // turn on MSW translation for this palette 
1321 #endif // wxUSE_PALETTE 
1323 // SetFont/Pen/Brush() really ask to be implemented as a single template 
1324 // function... but doing it is not worth breaking OpenWatcom build <sigh> 
1326 void wxDC::SetFont(const wxFont
& font
) 
1328     WXMICROWIN_CHECK_HDC
 
1330     if ( font 
== m_font 
) 
1335         HGDIOBJ hfont 
= ::SelectObject(GetHdc(), GetHfontOf(font
)); 
1336         if ( hfont 
== HGDI_ERROR 
) 
1338             wxLogLastError(_T("SelectObject(font)")); 
1343                 m_oldFont 
= (WXHPEN
)hfont
; 
1348     else // invalid font, reset the current font 
1352             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR 
) 
1354                 wxLogLastError(_T("SelectObject(old font)")); 
1360         m_font 
= wxNullFont
; 
1364 void wxDC::SetPen(const wxPen
& pen
) 
1366     WXMICROWIN_CHECK_HDC
 
1373         HGDIOBJ hpen 
= ::SelectObject(GetHdc(), GetHpenOf(pen
)); 
1374         if ( hpen 
== HGDI_ERROR 
) 
1376             wxLogLastError(_T("SelectObject(pen)")); 
1381                 m_oldPen 
= (WXHPEN
)hpen
; 
1386     else // invalid pen, reset the current pen 
1390             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR 
) 
1392                 wxLogLastError(_T("SelectObject(old pen)")); 
1402 void wxDC::SetBrush(const wxBrush
& brush
) 
1404     WXMICROWIN_CHECK_HDC
 
1406     if ( brush 
== m_brush 
) 
1411         // we must make sure the brush is aligned with the logical coordinates 
1412         // before selecting it 
1413         wxBitmap 
*stipple 
= brush
.GetStipple(); 
1414         if ( stipple 
&& stipple
->Ok() ) 
1416             if ( !::SetBrushOrgEx
 
1419                         m_deviceOriginX 
% stipple
->GetWidth(), 
1420                         m_deviceOriginY 
% stipple
->GetHeight(), 
1421                         NULL                    
// [out] previous brush origin 
1424                 wxLogLastError(_T("SetBrushOrgEx()")); 
1428         HGDIOBJ hbrush 
= ::SelectObject(GetHdc(), GetHbrushOf(brush
)); 
1429         if ( hbrush 
== HGDI_ERROR 
) 
1431             wxLogLastError(_T("SelectObject(brush)")); 
1436                 m_oldBrush 
= (WXHPEN
)hbrush
; 
1441     else // invalid brush, reset the current brush 
1445             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR 
) 
1447                 wxLogLastError(_T("SelectObject(old brush)")); 
1453         m_brush 
= wxNullBrush
; 
1457 void wxDC::SetBackground(const wxBrush
& brush
) 
1459     WXMICROWIN_CHECK_HDC
 
1461     m_backgroundBrush 
= brush
; 
1463     if ( m_backgroundBrush
.Ok() ) 
1465         (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel()); 
1469 void wxDC::SetBackgroundMode(int mode
) 
1471     WXMICROWIN_CHECK_HDC
 
1473     m_backgroundMode 
= mode
; 
1475     // SetBackgroundColour now only refers to text background 
1476     // and m_backgroundMode is used there 
1479 void wxDC::SetLogicalFunction(int function
) 
1481     WXMICROWIN_CHECK_HDC
 
1483     m_logicalFunction 
= function
; 
1488 void wxDC::SetRop(WXHDC dc
) 
1490     if ( !dc 
|| m_logicalFunction 
< 0 ) 
1495     switch (m_logicalFunction
) 
1497         case wxCLEAR
:        rop 
= R2_BLACK
;         break; 
1498         case wxXOR
:          rop 
= R2_XORPEN
;        break; 
1499         case wxINVERT
:       rop 
= R2_NOT
;           break; 
1500         case wxOR_REVERSE
:   rop 
= R2_MERGEPENNOT
;   break; 
1501         case wxAND_REVERSE
:  rop 
= R2_MASKPENNOT
;    break; 
1502         case wxCOPY
:         rop 
= R2_COPYPEN
;       break; 
1503         case wxAND
:          rop 
= R2_MASKPEN
;       break; 
1504         case wxAND_INVERT
:   rop 
= R2_MASKNOTPEN
;    break; 
1505         case wxNO_OP
:        rop 
= R2_NOP
;           break; 
1506         case wxNOR
:          rop 
= R2_NOTMERGEPEN
;   break; 
1507         case wxEQUIV
:        rop 
= R2_NOTXORPEN
;     break; 
1508         case wxSRC_INVERT
:   rop 
= R2_NOTCOPYPEN
;    break; 
1509         case wxOR_INVERT
:    rop 
= R2_MERGENOTPEN
;   break; 
1510         case wxNAND
:         rop 
= R2_NOTMASKPEN
;    break; 
1511         case wxOR
:           rop 
= R2_MERGEPEN
;      break; 
1512         case wxSET
:          rop 
= R2_WHITE
;         break; 
1515            wxFAIL_MSG( wxT("unsupported logical function") ); 
1519     SetROP2(GetHdc(), rop
); 
1522 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
)) 
1524     // We might be previewing, so return true to let it continue. 
1532 void wxDC::StartPage() 
1536 void wxDC::EndPage() 
1540 // --------------------------------------------------------------------------- 
1542 // --------------------------------------------------------------------------- 
1544 wxCoord 
wxDC::GetCharHeight() const 
1546     WXMICROWIN_CHECK_HDC_RET(0) 
1548     TEXTMETRIC lpTextMetric
; 
1550     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1552     return lpTextMetric
.tmHeight
; 
1555 wxCoord 
wxDC::GetCharWidth() const 
1557     WXMICROWIN_CHECK_HDC_RET(0) 
1559     TEXTMETRIC lpTextMetric
; 
1561     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1563     return lpTextMetric
.tmAveCharWidth
; 
1566 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord 
*x
, wxCoord 
*y
, 
1567                            wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1570 #ifdef __WXMICROWIN__ 
1575         if (descent
) *descent 
= 0; 
1576         if (externalLeading
) *externalLeading 
= 0; 
1579 #endif // __WXMICROWIN__ 
1584         wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") ); 
1586         hfontOld 
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
)); 
1588     else // don't change the font 
1596     GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
); 
1597     GetTextMetrics(GetHdc(), &tm
); 
1604         *descent 
= tm
.tmDescent
; 
1605     if (externalLeading
) 
1606         *externalLeading 
= tm
.tmExternalLeading
; 
1610         ::SelectObject(GetHdc(), hfontOld
); 
1615 // Each element of the array will be the width of the string up to and 
1616 // including the coresoponding character in text. 
1618 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const 
1620     static int maxLenText 
= -1; 
1621     static int maxWidth 
= -1; 
1624     int stlen 
= text
.Length(); 
1626     if (maxLenText 
== -1) 
1628         // Win9x and WinNT+ have different limits 
1629         int version 
= wxGetOsVersion(); 
1630         maxLenText 
= version 
== wxWINDOWS_NT 
? 65535 : 8192; 
1631         maxWidth 
=   version 
== wxWINDOWS_NT 
? INT_MAX 
: 32767; 
1635     widths
.Add(0, stlen
);  // fill the array with zeros 
1637     if (!::GetTextExtentExPoint(GetHdc(), 
1638                                 text
.c_str(),           // string to check 
1639                                 wxMin(stlen
, maxLenText
), 
1641                                 &fit
,                   // [out] count of chars 
1643                                 &widths
[0],             // array to fill 
1647         wxLogLastError(wxT("GetTextExtentExPoint")); 
1657 void wxDC::SetMapMode(int mode
) 
1659     WXMICROWIN_CHECK_HDC
 
1661     m_mappingMode 
= mode
; 
1663     if ( mode 
== wxMM_TEXT 
) 
1666         m_logicalScaleY 
= 1.0; 
1668     else // need to do some calculations 
1670         int pixel_width 
= ::GetDeviceCaps(GetHdc(), HORZRES
), 
1671             pixel_height 
= ::GetDeviceCaps(GetHdc(), VERTRES
), 
1672             mm_width 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
), 
1673             mm_height 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1675         if ( (mm_width 
== 0) || (mm_height 
== 0) ) 
1677             // we can't calculate mm2pixels[XY] then! 
1681         double mm2pixelsX 
= (double)pixel_width 
/ mm_width
, 
1682                mm2pixelsY 
= (double)pixel_height 
/ mm_height
; 
1687                 m_logicalScaleX 
= twips2mm 
* mm2pixelsX
; 
1688                 m_logicalScaleY 
= twips2mm 
* mm2pixelsY
; 
1692                 m_logicalScaleX 
= pt2mm 
* mm2pixelsX
; 
1693                 m_logicalScaleY 
= pt2mm 
* mm2pixelsY
; 
1697                 m_logicalScaleX 
= mm2pixelsX
; 
1698                 m_logicalScaleY 
= mm2pixelsY
; 
1702                 m_logicalScaleX 
= mm2pixelsX 
/ 10.0; 
1703                 m_logicalScaleY 
= mm2pixelsY 
/ 10.0; 
1707                 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); 
1711     // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of 
1712     //     cases we could do with MM_TEXT and in the remaining 0.9% with 
1713     //     MM_ISOTROPIC (TODO!) 
1715     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1717     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
1718         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
1720     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1721     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
1723     ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
); 
1724     ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
); 
1728 void wxDC::SetUserScale(double x
, double y
) 
1730     WXMICROWIN_CHECK_HDC
 
1733     if ( x 
== m_userScaleX 
&& y 
== m_userScaleY 
) 
1739     SetMapMode(m_mappingMode
); 
1743 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
) 
1745     WXMICROWIN_CHECK_HDC
 
1748     int signX 
= xLeftRight 
? 1 : -1, 
1749         signY 
= yBottomUp 
? -1 : 1; 
1751     if ( signX 
!= m_signX 
|| signY 
!= m_signY 
) 
1756         SetMapMode(m_mappingMode
); 
1761 void wxDC::SetSystemScale(double x
, double y
) 
1763     WXMICROWIN_CHECK_HDC
 
1766     if ( x 
== m_scaleX 
&& y 
== m_scaleY 
) 
1772     SetMapMode(m_mappingMode
); 
1776 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1778     WXMICROWIN_CHECK_HDC
 
1781     if ( x 
== m_logicalOriginX 
&& y 
== m_logicalOriginY 
) 
1784     m_logicalOriginX 
= x
; 
1785     m_logicalOriginY 
= y
; 
1787     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1791 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1793     WXMICROWIN_CHECK_HDC
 
1796     if ( x 
== m_deviceOriginX 
&& y 
== m_deviceOriginY 
) 
1799     m_deviceOriginX 
= x
; 
1800     m_deviceOriginY 
= y
; 
1802     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1806 // --------------------------------------------------------------------------- 
1807 // coordinates transformations 
1808 // --------------------------------------------------------------------------- 
1810 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1812     return DeviceToLogicalXRel(x 
- m_deviceOriginX
)*m_signX 
+ m_logicalOriginX
; 
1815 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1817     // axis orientation is not taken into account for conversion of a distance 
1818     return (wxCoord
)(x 
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
)); 
1821 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
1823     return DeviceToLogicalYRel(y 
- m_deviceOriginY
)*m_signY 
+ m_logicalOriginY
; 
1826 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
1828     // axis orientation is not taken into account for conversion of a distance 
1829     return (wxCoord
)( y 
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
)); 
1832 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
1834     return LogicalToDeviceXRel(x 
- m_logicalOriginX
)*m_signX 
+ m_deviceOriginX
; 
1837 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
1839     // axis orientation is not taken into account for conversion of a distance 
1840     return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
); 
1843 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
1845     return LogicalToDeviceYRel(y 
- m_logicalOriginY
)*m_signY 
+ m_deviceOriginY
; 
1848 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
1850     // axis orientation is not taken into account for conversion of a distance 
1851     return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
); 
1854 // --------------------------------------------------------------------------- 
1856 // --------------------------------------------------------------------------- 
1858 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, 
1859                   wxCoord width
, wxCoord height
, 
1860                   wxDC 
*source
, wxCoord xsrc
, wxCoord ysrc
, 
1861                   int rop
, bool useMask
, 
1862                   wxCoord xsrcMask
, wxCoord ysrcMask
) 
1864     wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") ); 
1866     WXMICROWIN_CHECK_HDC_RET(false) 
1868     const wxBitmap
& bmpSrc 
= source
->m_selectedBitmap
; 
1869     if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() ) 
1871         if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
, 
1872                       GetHdcOf(*source
), bmpSrc
) ) 
1876     wxMask 
*mask 
= NULL
; 
1879         mask 
= bmpSrc
.GetMask(); 
1881         if ( !(bmpSrc
.Ok() && mask 
&& mask
->GetMaskBitmap()) ) 
1883             // don't give assert here because this would break existing 
1884             // programs - just silently ignore useMask parameter 
1889     if (xsrcMask 
== -1 && ysrcMask 
== -1) 
1891         xsrcMask 
= xsrc
; ysrcMask 
= ysrc
; 
1894     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1895     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1896     if (m_textForegroundColour
.Ok()) 
1898         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1900     if (m_textBackgroundColour
.Ok()) 
1902         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1908         case wxXOR
:          dwRop 
= SRCINVERT
;        break; 
1909         case wxINVERT
:       dwRop 
= DSTINVERT
;        break; 
1910         case wxOR_REVERSE
:   dwRop 
= 0x00DD0228;       break; 
1911         case wxAND_REVERSE
:  dwRop 
= SRCERASE
;         break; 
1912         case wxCLEAR
:        dwRop 
= BLACKNESS
;        break; 
1913         case wxSET
:          dwRop 
= WHITENESS
;        break; 
1914         case wxOR_INVERT
:    dwRop 
= MERGEPAINT
;       break; 
1915         case wxAND
:          dwRop 
= SRCAND
;           break; 
1916         case wxOR
:           dwRop 
= SRCPAINT
;         break; 
1917         case wxEQUIV
:        dwRop 
= 0x00990066;       break; 
1918         case wxNAND
:         dwRop 
= 0x007700E6;       break; 
1919         case wxAND_INVERT
:   dwRop 
= 0x00220326;       break; 
1920         case wxCOPY
:         dwRop 
= SRCCOPY
;          break; 
1921         case wxNO_OP
:        dwRop 
= DSTCOPY
;          break; 
1922         case wxSRC_INVERT
:   dwRop 
= NOTSRCCOPY
;       break; 
1923         case wxNOR
:          dwRop 
= NOTSRCCOPY
;       break; 
1925            wxFAIL_MSG( wxT("unsupported logical function") ); 
1929     bool success 
= false; 
1934         // we want the part of the image corresponding to the mask to be 
1935         // transparent, so use "DSTCOPY" ROP for the mask points (the usual 
1936         // meaning of fg and bg is inverted which corresponds to wxWin notion 
1937         // of the mask which is also contrary to the Windows one) 
1939         // On some systems, MaskBlt succeeds yet is much much slower 
1940         // than the wxWindows fall-back implementation. So we need 
1941         // to be able to switch this on and off at runtime. 
1942 #if wxUSE_SYSTEM_OPTIONS 
1943         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1949                             xdest
, ydest
, width
, height
, 
1952                             (HBITMAP
)mask
->GetMaskBitmap(), 
1954                             MAKEROP4(dwRop
, DSTCOPY
) 
1961             // Blit bitmap with mask 
1964             HBITMAP buffer_bmap 
; 
1966 #if wxUSE_DC_CACHEING 
1967             // create a temp buffer bitmap and DCs to access it and the mask 
1968             wxDCCacheEntry
* dcCacheEntry1 
= FindDCInCache(NULL
, source
->GetHDC()); 
1969             dc_mask 
= (HDC
) dcCacheEntry1
->m_dc
; 
1971             wxDCCacheEntry
* dcCacheEntry2 
= FindDCInCache(dcCacheEntry1
, GetHDC()); 
1972             dc_buffer 
= (HDC
) dcCacheEntry2
->m_dc
; 
1974             wxDCCacheEntry
* bitmapCacheEntry 
= FindBitmapInCache(GetHDC(), 
1977             buffer_bmap 
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
; 
1978 #else // !wxUSE_DC_CACHEING 
1979             // create a temp buffer bitmap and DCs to access it and the mask 
1980             dc_mask 
= ::CreateCompatibleDC(GetHdcOf(*source
)); 
1981             dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
1982             buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
1983 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING 
1984             HGDIOBJ hOldMaskBitmap 
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap()); 
1985             HGDIOBJ hOldBufferBitmap 
= ::SelectObject(dc_buffer
, buffer_bmap
); 
1987             // copy dest to buffer 
1988             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1989                            GetHdc(), xdest
, ydest
, SRCCOPY
) ) 
1991                 wxLogLastError(wxT("BitBlt")); 
1994             // copy src to buffer using selected raster op 
1995             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1996                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) ) 
1998                 wxLogLastError(wxT("BitBlt")); 
2001             // set masked area in buffer to BLACK (pixel value 0) 
2002             COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
2003             COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
2004             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2005                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
2007                 wxLogLastError(wxT("BitBlt")); 
2010             // set unmasked area in dest to BLACK 
2011             ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
2012             ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
2013             if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
, 
2014                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
2016                 wxLogLastError(wxT("BitBlt")); 
2018             ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
2019             ::SetTextColor(GetHdc(), prevCol
); 
2021             // OR buffer to dest 
2022             success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
2023                                (int)width
, (int)height
, 
2024                                dc_buffer
, 0, 0, SRCPAINT
) != 0; 
2027                 wxLogLastError(wxT("BitBlt")); 
2030             // tidy up temporary DCs and bitmap 
2031             ::SelectObject(dc_mask
, hOldMaskBitmap
); 
2032             ::SelectObject(dc_buffer
, hOldBufferBitmap
); 
2034 #if !wxUSE_DC_CACHEING 
2036                 ::DeleteDC(dc_mask
); 
2037                 ::DeleteDC(dc_buffer
); 
2038                 ::DeleteObject(buffer_bmap
); 
2043     else // no mask, just BitBlt() it 
2045         // if we already have a DIB, draw it using StretchDIBits(), otherwise 
2046         // use StretchBlt() if available and finally fall back to BitBlt() 
2048         // FIXME: use appropriate WinCE functions 
2050         const int caps 
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
); 
2051         if ( bmpSrc
.Ok() && (caps 
& RC_STRETCHDIB
) ) 
2056             if ( ::GetObject(GetHbitmapOf(bmpSrc
), 
2058                              &ds
) == sizeof(ds
) ) 
2060                 StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2062                 // Figure out what co-ordinate system we're supposed to specify 
2064                 const LONG hDIB 
= ds
.dsBmih
.biHeight
; 
2068                     ysrc 
= hDIB 
- (ysrc 
+ height
); 
2071                 if ( ::StretchDIBits(GetHdc(), 
2077                                      (LPBITMAPINFO
)&ds
.dsBmih
, 
2080                                      ) == (int)GDI_ERROR 
) 
2082                     wxLogLastError(wxT("StretchDIBits")); 
2091         if ( !success 
&& (caps 
& RC_STRETCHBLT
) ) 
2096             StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2102                         xdest
, ydest
, width
, height
, 
2104                         xsrc
, ysrc
, width
, height
, 
2108                 wxLogLastError(_T("StretchBlt")); 
2122                         (int)width
, (int)height
, 
2128                 wxLogLastError(_T("BitBlt")); 
2137     ::SetTextColor(GetHdc(), old_textground
); 
2138     ::SetBkColor(GetHdc(), old_background
); 
2143 void wxDC::DoGetSize(int *w
, int *h
) const 
2145     WXMICROWIN_CHECK_HDC
 
2147     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2148     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2151 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
2153     WXMICROWIN_CHECK_HDC
 
2155     // if we implement it in terms of DoGetSize() instead of directly using the 
2156     // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it 
2157     // will also work for wxWindowDC and wxClientDC even though their size is 
2158     // not the same as the total size of the screen 
2159     int wPixels
, hPixels
; 
2160     DoGetSize(&wPixels
, &hPixels
); 
2164         int wTotal 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2166         wxCHECK_RET( wTotal
, _T("0 width device?") ); 
2168         *w 
= (wPixels 
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
; 
2173         int hTotal 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2175         wxCHECK_RET( hTotal
, _T("0 height device?") ); 
2177         *h 
= (hPixels 
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
; 
2181 wxSize 
wxDC::GetPPI() const 
2183     WXMICROWIN_CHECK_HDC_RET(wxSize()) 
2185     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
2186     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
2188     return wxSize(x
, y
); 
2191 // For use by wxWindows only, unless custom units are required. 
2192 void wxDC::SetLogicalScale(double x
, double y
) 
2194     WXMICROWIN_CHECK_HDC
 
2196     m_logicalScaleX 
= x
; 
2197     m_logicalScaleY 
= y
; 
2200 // ---------------------------------------------------------------------------- 
2202 // ---------------------------------------------------------------------------- 
2204 #if wxUSE_DC_CACHEING 
2207  * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will 
2208  * improve it in due course, either using arrays, or simply storing pointers to one 
2209  * entry for the bitmap, and two for the DCs. -- JACS 
2212 wxList 
wxDC::sm_bitmapCache
; 
2213 wxList 
wxDC::sm_dcCache
; 
2215 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
) 
2224 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
) 
2233 wxDCCacheEntry::~wxDCCacheEntry() 
2236         ::DeleteObject((HBITMAP
) m_bitmap
); 
2238         ::DeleteDC((HDC
) m_dc
); 
2241 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
) 
2243     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2244     wxList::compatibility_iterator node 
= sm_bitmapCache
.GetFirst(); 
2247         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2249         if (entry
->m_depth 
== depth
) 
2251             if (entry
->m_width 
< w 
|| entry
->m_height 
< h
) 
2253                 ::DeleteObject((HBITMAP
) entry
->m_bitmap
); 
2254                 entry
->m_bitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2255                 if ( !entry
->m_bitmap
) 
2257                     wxLogLastError(wxT("CreateCompatibleBitmap")); 
2259                 entry
->m_width 
= w
; entry
->m_height 
= h
; 
2265         node 
= node
->GetNext(); 
2267     WXHBITMAP hBitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2270         wxLogLastError(wxT("CreateCompatibleBitmap")); 
2272     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
); 
2273     AddToBitmapCache(entry
); 
2277 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
) 
2279     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2280     wxList::compatibility_iterator node 
= sm_dcCache
.GetFirst(); 
2283         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2285         // Don't return the same one as we already have 
2286         if (!notThis 
|| (notThis 
!= entry
)) 
2288             if (entry
->m_depth 
== depth
) 
2294         node 
= node
->GetNext(); 
2296     WXHDC hDC 
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
); 
2299         wxLogLastError(wxT("CreateCompatibleDC")); 
2301     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hDC
, depth
); 
2302     AddToDCCache(entry
); 
2306 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
) 
2308     sm_bitmapCache
.Append(entry
); 
2311 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
) 
2313     sm_dcCache
.Append(entry
); 
2316 void wxDC::ClearCache() 
2318     WX_CLEAR_LIST(wxList
, sm_dcCache
); 
2319     WX_CLEAR_LIST(wxList
, sm_bitmapCache
); 
2322 // Clean up cache at app exit 
2323 class wxDCModule 
: public wxModule
 
2326     virtual bool OnInit() { return true; } 
2327     virtual void OnExit() { wxDC::ClearCache(); } 
2330     DECLARE_DYNAMIC_CLASS(wxDCModule
) 
2333 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
) 
2335 #endif // wxUSE_DC_CACHEING 
2337 // ---------------------------------------------------------------------------- 
2338 // alpha channel support 
2339 // ---------------------------------------------------------------------------- 
2341 static bool AlphaBlt(HDC hdcDst
, 
2342                      int x
, int y
, int width
, int height
, 
2344                      const wxBitmap
& bmp
) 
2346     wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") ); 
2347     wxASSERT_MSG( hdcDst 
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") ); 
2349     // do we have AlphaBlend() and company in the headers? 
2350 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS 
2351     // yes, now try to see if we have it during run-time 
2352     typedef BOOL (WINAPI 
*AlphaBlend_t
)(HDC
,int,int,int,int, 
2353                                         HDC
,int,int,int,int, 
2356     // bitmaps can be drawn only from GUI thread so there is no need to 
2357     // protect this static variable from multiple threads 
2358     static bool s_triedToLoad 
= false; 
2359     static AlphaBlend_t pfnAlphaBlend 
= NULL
; 
2360     if ( !s_triedToLoad 
) 
2362         s_triedToLoad 
= true; 
2364         // don't give errors about the DLL being unavailable, we're 
2365         // prepared to handle this 
2368         wxDynamicLibrary 
dll(_T("msimg32.dll")); 
2369         if ( dll
.IsLoaded() ) 
2371             pfnAlphaBlend 
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend")); 
2372             if ( pfnAlphaBlend 
) 
2374                 // we must keep the DLL loaded if we want to be able to 
2375                 // call AlphaBlend() so just never unload it at all, not a 
2382     if ( pfnAlphaBlend 
) 
2385         bf
.BlendOp 
= AC_SRC_OVER
; 
2387         bf
.SourceConstantAlpha 
= 0xff; 
2388         bf
.AlphaFormat 
= AC_SRC_ALPHA
; 
2390         if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
, 
2391                            hdcSrc
, 0, 0, width
, height
, 
2394             // skip wxAlphaBlend() call below 
2398         wxLogLastError(_T("AlphaBlend")); 
2400 #endif // defined(AC_SRC_OVER) 
2402     // AlphaBlend() unavailable of failed: use our own (probably much slower) 
2404 #ifdef wxHAVE_RAW_BITMAP 
2405     wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
); 
2408 #else // !wxHAVE_RAW_BITMAP 
2409     // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose 
2410     // alpha but at least something will be shown like this) 
2412 #endif // wxHAVE_RAW_BITMAP 
2416 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable 
2417 #ifdef wxHAVE_RAW_BITMAP 
2420 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
) 
2422     // get the destination DC pixels 
2423     wxBitmap 
bmpDst(w
, h
, 32 /* force creating RGBA DIB */); 
2425     SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmpDst
)); 
2427     if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) ) 
2429         wxLogLastError(_T("BitBlt")); 
2432     // combine them with the source bitmap using alpha 
2433     wxAlphaPixelData 
dataDst(bmpDst
), 
2434                      dataSrc((wxBitmap 
&)bmpSrc
); 
2436     wxCHECK_RET( dataDst 
&& dataSrc
, 
2437                     _T("failed to get raw data in wxAlphaBlend") ); 
2439     wxAlphaPixelData::Iterator 
pDst(dataDst
), 
2442     for ( int y 
= 0; y 
< h
; y
++ ) 
2444         wxAlphaPixelData::Iterator pDstRowStart 
= pDst
, 
2445                                    pSrcRowStart 
= pSrc
; 
2447         for ( int x 
= 0; x 
< w
; x
++ ) 
2449             // note that source bitmap uses premultiplied alpha (as required by 
2450             // the real AlphaBlend) 
2451             const unsigned beta 
= 255 - pSrc
.Alpha(); 
2453             pDst
.Red() = pSrc
.Red() + (beta 
* pDst
.Red() + 127) / 255; 
2454             pDst
.Blue() = pSrc
.Blue() + (beta 
* pDst
.Blue() + 127) / 255; 
2455             pDst
.Green() = pSrc
.Green() + (beta 
* pDst
.Green() + 127) / 255; 
2461         pDst 
= pDstRowStart
; 
2462         pSrc 
= pSrcRowStart
; 
2463         pDst
.OffsetY(dataDst
, 1); 
2464         pSrc
.OffsetY(dataSrc
, 1); 
2467     // and finally blit them back to the destination DC 
2468     if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) ) 
2470         wxLogLastError(_T("BitBlt")); 
2474 #endif // #ifdef wxHAVE_RAW_BITMAP