1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/dc.cpp 
   3 // Purpose:     wxDC class for MSW port 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29     #include "wx/window.h" 
  32     #include "wx/dialog.h" 
  34     #include "wx/bitmap.h" 
  35     #include "wx/dcmemory.h" 
  38     #include "wx/dcprint.h" 
  41 #include "wx/sysopt.h" 
  42 #include "wx/module.h" 
  43 #include "wx/dynlib.h" 
  45 #ifdef wxHAVE_RAW_BITMAP 
  46 #include "wx/rawbmp.h" 
  51 #include "wx/msw/wrapcdlg.h" 
  57 #define AC_SRC_ALPHA 1 
  60 /* Quaternary raster codes */ 
  62 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) 
  65 // apparently with MicroWindows it is possible that HDC is 0 so we have to 
  66 // check for this ourselves 
  68     #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return; 
  69     #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x; 
  71     #define WXMICROWIN_CHECK_HDC 
  72     #define WXMICROWIN_CHECK_HDC_RET(x) 
  75 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
) 
  77 // --------------------------------------------------------------------------- 
  79 // --------------------------------------------------------------------------- 
  81 static const int VIEWPORT_EXTENT 
= 1000; 
  83 static const int MM_POINTS 
= 9; 
  84 static const int MM_METRIC 
= 10; 
  86 // ROPs which don't have standard names (see "Ternary Raster Operations" in the 
  87 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) 
  88 #define DSTCOPY 0x00AA0029      // a.k.a. NOP operation 
  90 // ---------------------------------------------------------------------------- 
  91 // macros for logical <-> device coords conversion 
  92 // ---------------------------------------------------------------------------- 
  95    We currently let Windows do all the translations itself so these macros are 
  96    not really needed (any more) but keep them to enhance readability of the 
  97    code by allowing to see where are the logical and where are the device 
 102     #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX) 
 103     #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY) 
 104     #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX) 
 105     #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY) 
 107     #define XLOG2DEV(x) (x) 
 108     #define YLOG2DEV(y) (y) 
 109     #define XDEV2LOG(x) (x) 
 110     #define YDEV2LOG(y) (y) 
 113 // --------------------------------------------------------------------------- 
 115 // --------------------------------------------------------------------------- 
 117 // convert degrees to radians 
 118 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
 120 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha 
 122 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed 
 123 //     to pass it to this function but as we already have it at the point 
 124 //     of call anyhow we do 
 126 // return true if we could draw the bitmap in one way or the other, false 
 128 static bool AlphaBlt(HDC hdcDst
, 
 129                      int x
, int y
, int w
, int h
, 
 130                      int srcX
, int srcY
, HDC hdcSrc
, 
 131                      const wxBitmap
& bmpSrc
); 
 133 #ifdef wxHAVE_RAW_BITMAP 
 135 // our (limited) AlphaBlend() replacement for Windows versions not providing it 
 137 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, 
 138              int srcX
, int srcY
, const wxBitmap
& bmp
); 
 140 #endif // wxHAVE_RAW_BITMAP 
 142 // ---------------------------------------------------------------------------- 
 144 // ---------------------------------------------------------------------------- 
 146 // instead of duplicating the same code which sets and then restores text 
 147 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, 
 148 // encapsulate this in a small helper class 
 150 // wxColourChanger: changes the text colours in the ctor if required and 
 151 //                  restores them in the dtor 
 152 class wxColourChanger
 
 155     wxColourChanger(wxDC
& dc
); 
 161     COLORREF m_colFgOld
, m_colBgOld
; 
 165     DECLARE_NO_COPY_CLASS(wxColourChanger
) 
 168 // this class saves the old stretch blit mode during its life time 
 169 class StretchBltModeChanger
 
 172     StretchBltModeChanger(HDC hdc
, 
 173                           int WXUNUSED_IN_WINCE(mode
)) 
 177         m_modeOld 
= ::SetStretchBltMode(m_hdc
, mode
); 
 179             wxLogLastError(_T("SetStretchBltMode")); 
 183     ~StretchBltModeChanger() 
 186         if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) ) 
 187             wxLogLastError(_T("SetStretchBltMode")); 
 196     DECLARE_NO_COPY_CLASS(StretchBltModeChanger
) 
 199 // support for dynamic loading of msimg32.dll which we use for some functions 
 203     // return the symbol with the given name if the DLL not loaded or symbol 
 205     static void *GetSymbol(const wxChar 
*name
) 
 209         if ( !ms_triedToLoad 
) 
 211             ms_triedToLoad 
= true; 
 212             ms_dll
.Load(_T("msimg32")); 
 215         return ms_dll
.IsLoaded() ? ms_dll
.GetSymbol(name
) : NULL
; 
 219     static wxDynamicLibrary ms_dll
; 
 220     static bool ms_triedToLoad
; 
 223 wxDynamicLibrary 
wxMSImg32DLL::ms_dll
; 
 224 bool wxMSImg32DLL::ms_triedToLoad 
= false; 
 226 // helper macro for getting the symbols from msimg32.dll: it supposes that a 
 227 // type "name_t" is defined and casts the returned symbol to it automatically 
 228 #define wxMSIMG32_SYMBOL(name) (name ## _t)wxMSImg32DLL::GetSymbol(_T(#name)) 
 230 // =========================================================================== 
 232 // =========================================================================== 
 234 // ---------------------------------------------------------------------------- 
 236 // ---------------------------------------------------------------------------- 
 238 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
) 
 240     const wxBrush
& brush 
= dc
.GetBrush(); 
 241     if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 243         HDC hdc 
= GetHdcOf(dc
); 
 244         m_colFgOld 
= ::GetTextColor(hdc
); 
 245         m_colBgOld 
= ::GetBkColor(hdc
); 
 247         // note that Windows convention is opposite to wxWidgets one, this is 
 248         // why text colour becomes the background one and vice versa 
 249         const wxColour
& colFg 
= dc
.GetTextForeground(); 
 252             ::SetBkColor(hdc
, colFg
.GetPixel()); 
 255         const wxColour
& colBg 
= dc
.GetTextBackground(); 
 258             ::SetTextColor(hdc
, colBg
.GetPixel()); 
 262                   dc
.GetBackgroundMode() == wxTRANSPARENT 
? TRANSPARENT
 
 265         // flag which telsl us to undo changes in the dtor 
 270         // nothing done, nothing to undo 
 275 wxColourChanger::~wxColourChanger() 
 279         // restore the colours we changed 
 280         HDC hdc 
= GetHdcOf(m_dc
); 
 282         ::SetBkMode(hdc
, TRANSPARENT
); 
 283         ::SetTextColor(hdc
, m_colFgOld
); 
 284         ::SetBkColor(hdc
, m_colBgOld
); 
 288 // --------------------------------------------------------------------------- 
 290 // --------------------------------------------------------------------------- 
 296         SelectOldObjects(m_hDC
); 
 298         // if we own the HDC, we delete it, otherwise we just release it 
 302             ::DeleteDC(GetHdc()); 
 304         else // we don't own our HDC 
 308                 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc()); 
 312                 // Must have been a wxScreenDC 
 313                 ::ReleaseDC((HWND
) NULL
, GetHdc()); 
 319 // This will select current objects out of the DC, 
 320 // which is what you have to do before deleting the 
 322 void wxDC::SelectOldObjects(WXHDC dc
) 
 328             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 330             if (m_selectedBitmap
.Ok()) 
 332                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 339             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 344             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 349             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 356             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
); 
 359 #endif // wxUSE_PALETTE 
 362     m_brush 
= wxNullBrush
; 
 365     m_palette 
= wxNullPalette
; 
 366 #endif // wxUSE_PALETTE 
 368     m_backgroundBrush 
= wxNullBrush
; 
 369     m_selectedBitmap 
= wxNullBitmap
; 
 372 // --------------------------------------------------------------------------- 
 374 // --------------------------------------------------------------------------- 
 376 void wxDC::UpdateClipBox() 
 381     ::GetClipBox(GetHdc(), &rect
); 
 383     m_clipX1 
= (wxCoord
) XDEV2LOG(rect
.left
); 
 384     m_clipY1 
= (wxCoord
) YDEV2LOG(rect
.top
); 
 385     m_clipX2 
= (wxCoord
) XDEV2LOG(rect
.right
); 
 386     m_clipY2 
= (wxCoord
) YDEV2LOG(rect
.bottom
); 
 390 wxDC::DoGetClippingBox(wxCoord 
*x
, wxCoord 
*y
, wxCoord 
*w
, wxCoord 
*h
) const 
 392     // check if we should try to retrieve the clipping region possibly not set 
 393     // by our SetClippingRegion() but preset by Windows:this can only happen 
 394     // when we're associated with an existing HDC usign SetHDC(), see there 
 395     if ( m_clipping 
&& !m_clipX1 
&& !m_clipX2 
) 
 397         wxDC 
*self 
= wxConstCast(this, wxDC
); 
 398         self
->UpdateClipBox(); 
 400         if ( !m_clipX1 
&& !m_clipX2 
) 
 401             self
->m_clipping 
= false; 
 404     wxDCBase::DoGetClippingBox(x
, y
, w
, h
); 
 407 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion() 
 408 void wxDC::SetClippingHrgn(WXHRGN hrgn
) 
 410     wxCHECK_RET( hrgn
, wxT("invalid clipping region") ); 
 414     // note that we combine the new clipping region with the existing one: this 
 415     // is compatible with what the other ports do and is the documented 
 416     // behaviour now (starting with 2.3.3) 
 417 #if defined(__WXWINCE__) 
 419     if ( !::GetClipBox(GetHdc(), &rectClip
) ) 
 422     // GetClipBox returns logical coordinates, so transform to device 
 423     rectClip
.left 
= LogicalToDeviceX(rectClip
.left
); 
 424     rectClip
.top 
= LogicalToDeviceY(rectClip
.top
); 
 425     rectClip
.right 
= LogicalToDeviceX(rectClip
.right
); 
 426     rectClip
.bottom 
= LogicalToDeviceY(rectClip
.bottom
); 
 428     HRGN hrgnDest 
= ::CreateRectRgn(0, 0, 0, 0); 
 429     HRGN hrgnClipOld 
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
, 
 430                                        rectClip
.right
, rectClip
.bottom
); 
 432     if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR 
) 
 434         ::SelectClipRgn(GetHdc(), hrgnDest
); 
 437     ::DeleteObject(hrgnClipOld
); 
 438     ::DeleteObject(hrgnDest
); 
 440     if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR 
) 
 442         wxLogLastError(_T("ExtSelectClipRgn")); 
 446 #endif // WinCE/!WinCE 
 453 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 455     // the region coords are always the device ones, so do the translation 
 458     // FIXME: possible +/-1 error here, to check! 
 459     HRGN hrgn 
= ::CreateRectRgn(LogicalToDeviceX(x
), 
 461                                 LogicalToDeviceX(x 
+ w
), 
 462                                 LogicalToDeviceY(y 
+ h
)); 
 465         wxLogLastError(_T("CreateRectRgn")); 
 469         SetClippingHrgn((WXHRGN
)hrgn
); 
 471         ::DeleteObject(hrgn
); 
 475 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 477     SetClippingHrgn(region
.GetHRGN()); 
 480 void wxDC::DestroyClippingRegion() 
 484     if (m_clipping 
&& m_hDC
) 
 487         // On a PocketPC device (not necessarily emulator), resetting 
 488         // the clip region as per the old method causes bad display 
 489         // problems. In fact setting a null region is probably OK 
 490         // on desktop WIN32 also, since the WIN32 docs imply that the user 
 491         // clipping region is independent from the paint clipping region. 
 492         ::SelectClipRgn(GetHdc(), 0); 
 494         // TODO: this should restore the previous clipping region, 
 495         //       so that OnPaint processing works correctly, and the update 
 496         //       clipping region doesn't get destroyed after the first 
 497         //       DestroyClippingRegion. 
 498         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 499         ::SelectClipRgn(GetHdc(), rgn
); 
 504     wxDCBase::DestroyClippingRegion(); 
 507 // --------------------------------------------------------------------------- 
 508 // query capabilities 
 509 // --------------------------------------------------------------------------- 
 511 bool wxDC::CanDrawBitmap() const 
 516 bool wxDC::CanGetTextExtent() const 
 518 #ifdef __WXMICROWIN__ 
 519     // TODO Extend MicroWindows' GetDeviceCaps function 
 522     // What sort of display is it? 
 523     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 525     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 529 int wxDC::GetDepth() const 
 531     WXMICROWIN_CHECK_HDC_RET(16) 
 533     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 536 // --------------------------------------------------------------------------- 
 538 // --------------------------------------------------------------------------- 
 547         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 551         // No, I think we should simply ignore this if printing on e.g. 
 553         // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 
 554         if (!m_selectedBitmap
.Ok()) 
 557         rect
.left 
= 0; rect
.top 
= 0; 
 558         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 559         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 563     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 566     DWORD colour 
= ::GetBkColor(GetHdc()); 
 567     HBRUSH brush 
= ::CreateSolidBrush(colour
); 
 568     ::FillRect(GetHdc(), &rect
, brush
); 
 569     ::DeleteObject(brush
); 
 572     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
 573         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
 575     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 577     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 578     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
 579     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 580     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 584 bool wxDC::DoFloodFill(wxCoord 
WXUNUSED_IN_WINCE(x
), 
 585                        wxCoord 
WXUNUSED_IN_WINCE(y
), 
 586                        const wxColour
& WXUNUSED_IN_WINCE(col
), 
 587                        int WXUNUSED_IN_WINCE(style
)) 
 592     WXMICROWIN_CHECK_HDC_RET(false) 
 594     bool success 
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 596                          style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 597                                                   : FLOODFILLBORDER
) ) ; 
 600         // quoting from the MSDN docs: 
 602         //      Following are some of the reasons this function might fail: 
 604         //      * The filling could not be completed. 
 605         //      * The specified point has the boundary color specified by the 
 606         //        crColor parameter (if FLOODFILLBORDER was requested). 
 607         //      * The specified point does not have the color specified by 
 608         //        crColor (if FLOODFILLSURFACE was requested) 
 609         //      * The point is outside the clipping region that is, it is not 
 610         //        visible on the device. 
 612         wxLogLastError(wxT("ExtFloodFill")); 
 615     CalcBoundingBox(x
, y
); 
 621 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour 
*col
) const 
 623     WXMICROWIN_CHECK_HDC_RET(false) 
 625     wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") ); 
 627     // get the color of the pixel 
 628     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 630     wxRGBToColour(*col
, pixelcolor
); 
 635 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
) 
 639     wxCoord x1 
= x
-VIEWPORT_EXTENT
; 
 640     wxCoord y1 
= y
-VIEWPORT_EXTENT
; 
 641     wxCoord x2 
= x
+VIEWPORT_EXTENT
; 
 642     wxCoord y2 
= y
+VIEWPORT_EXTENT
; 
 644     wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 645     wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 647     CalcBoundingBox(x1
, y1
); 
 648     CalcBoundingBox(x2
, y2
); 
 651 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 655     wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 657     CalcBoundingBox(x1
, y1
); 
 658     CalcBoundingBox(x2
, y2
); 
 661 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) 
 662 // and ending at (x2, y2) 
 663 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
, 
 664                      wxCoord x2
, wxCoord y2
, 
 665                      wxCoord xc
, wxCoord yc
) 
 668     // Slower emulation since WinCE doesn't support Pie and Arc 
 669     double r 
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) ); 
 670     double sa 
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180 
 671     if( y1
>yc 
) sa 
= -sa
; // below center 
 672     double ea 
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180; 
 673     DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea 
); 
 678     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 682     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
); 
 683     wxCoord r 
= (wxCoord
)radius
; 
 685     // treat the special case of full circle separately 
 686     if ( x1 
== x2 
&& y1 
== y2 
) 
 688         DrawEllipse(xc 
- r
, yc 
- r
, 2*r
, 2*r
); 
 692     wxCoord xx1 
= XLOG2DEV(x1
); 
 693     wxCoord yy1 
= YLOG2DEV(y1
); 
 694     wxCoord xx2 
= XLOG2DEV(x2
); 
 695     wxCoord yy2 
= YLOG2DEV(y2
); 
 696     wxCoord xxc 
= XLOG2DEV(xc
); 
 697     wxCoord yyc 
= YLOG2DEV(yc
); 
 698     wxCoord ray 
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 700     wxCoord xxx1 
= (wxCoord
) (xxc
-ray
); 
 701     wxCoord yyy1 
= (wxCoord
) (yyc
-ray
); 
 702     wxCoord xxx2 
= (wxCoord
) (xxc
+ray
); 
 703     wxCoord yyy2 
= (wxCoord
) (yyc
+ray
); 
 705     if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT 
) 
 707         // Have to add 1 to bottom-right corner of rectangle 
 708         // to make semi-circles look right (crooked line otherwise). 
 709         // Unfortunately this is not a reliable method, depends 
 710         // on the size of shape. 
 711         // TODO: figure out why this happens! 
 712         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
); 
 716         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
); 
 719     CalcBoundingBox(xc 
- r
, yc 
- r
); 
 720     CalcBoundingBox(xc 
+ r
, yc 
+ r
); 
 724 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
 725                            wxCoord width
, wxCoord height
) 
 727     // cases when we don't have DrawFrameControl() 
 728 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__) 
 729     return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
); 
 731     wxCoord x2 
= x1 
+ width
, 
 741     DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
); 
 743     DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
); 
 746     CalcBoundingBox(x1
, y1
); 
 747     CalcBoundingBox(x2
, y2
); 
 748 #endif // Microwin/Normal 
 751 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
) 
 755     COLORREF color 
= 0x00ffffff; 
 758         color 
= m_pen
.GetColour().GetPixel(); 
 761     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 763     CalcBoundingBox(x
, y
); 
 766 void wxDC::DoDrawPolygon(int n
, 
 770                          int WXUNUSED_IN_WINCE(fillStyle
)) 
 774     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 776     // Do things less efficiently if we have offsets 
 777     if (xoffset 
!= 0 || yoffset 
!= 0) 
 779         POINT 
*cpoints 
= new POINT
[n
]; 
 781         for (i 
= 0; i 
< n
; i
++) 
 783             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 784             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 786             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 789         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 791         (void)Polygon(GetHdc(), cpoints
, n
); 
 793         SetPolyFillMode(GetHdc(),prev
); 
 800         for (i 
= 0; i 
< n
; i
++) 
 801             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 804         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 806         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 808         SetPolyFillMode(GetHdc(),prev
); 
 814 wxDC::DoDrawPolyPolygon(int n
, 
 822     wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
); 
 826     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 828     for (i 
= cnt 
= 0; i 
< n
; i
++) 
 831     // Do things less efficiently if we have offsets 
 832     if (xoffset 
!= 0 || yoffset 
!= 0) 
 834         POINT 
*cpoints 
= new POINT
[cnt
]; 
 835         for (i 
= 0; i 
< cnt
; i
++) 
 837             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 838             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 840             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 843         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 845         (void)PolyPolygon(GetHdc(), cpoints
, count
, n
); 
 847         SetPolyFillMode(GetHdc(),prev
); 
 853         for (i 
= 0; i 
< cnt
; i
++) 
 854             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 857         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 859         (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
); 
 861         SetPolyFillMode(GetHdc(),prev
); 
 868 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 872     // Do things less efficiently if we have offsets 
 873     if (xoffset 
!= 0 || yoffset 
!= 0) 
 875         POINT 
*cpoints 
= new POINT
[n
]; 
 877         for (i 
= 0; i 
< n
; i
++) 
 879             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 880             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 882             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 884         (void)Polyline(GetHdc(), cpoints
, n
); 
 890         for (i 
= 0; i 
< n
; i
++) 
 891             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 893         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 897 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 901     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 903     wxCoord x2 
= x 
+ width
; 
 904     wxCoord y2 
= y 
+ height
; 
 906     if ((m_logicalFunction 
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
)) 
 909         rect
.left 
= XLOG2DEV(x
); 
 910         rect
.top 
= YLOG2DEV(y
); 
 911         rect
.right 
= XLOG2DEV(x2
); 
 912         rect
.bottom 
= YLOG2DEV(y2
); 
 913         (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() ); 
 917         // Windows draws the filled rectangles without outline (i.e. drawn with a 
 918         // transparent pen) one pixel smaller in both directions and we want them 
 919         // to have the same size regardless of which pen is used - adjust 
 921         // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. 
 922         if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 924             // Apparently not needed for WinCE (see e.g. Life! demo) 
 931         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 935     CalcBoundingBox(x
, y
); 
 936     CalcBoundingBox(x2
, y2
); 
 939 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 943     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 945     // Now, a negative radius value is interpreted to mean 
 946     // 'the proportion of the smallest X or Y dimension' 
 950         double smallest 
= (width 
< height
) ? width 
: height
; 
 951         radius 
= (- radius 
* smallest
); 
 954     wxCoord x2 
= (x
+width
); 
 955     wxCoord y2 
= (y
+height
); 
 957     // Windows draws the filled rectangles without outline (i.e. drawn with a 
 958     // transparent pen) one pixel smaller in both directions and we want them 
 959     // to have the same size regardless of which pen is used - adjust 
 960     if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 966     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 967         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 969     CalcBoundingBox(x
, y
); 
 970     CalcBoundingBox(x2
, y2
); 
 973 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 977     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 979     wxCoord x2 
= (x
+width
); 
 980     wxCoord y2 
= (y
+height
); 
 982     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 984     CalcBoundingBox(x
, y
); 
 985     CalcBoundingBox(x2
, y2
); 
 989 void wxDC::DoDrawSpline(wxList 
*points
) 
 992     // WinCE does not support ::PolyBezier so use generic version 
 993     wxDCBase::DoDrawSpline(points
); 
 995     // quadratic b-spline to cubic bezier spline conversion 
 997     // quadratic spline with control points P0,P1,P2 
 998     // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2 
1000     // bezier spline with control points B0,B1,B2,B3 
1001     // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3 
1003     // control points of bezier spline calculated from b-spline 
1005     // B1 = (2*P1 + P0)/3 
1006     // B2 = (2*P1 + P2)/3 
1009     WXMICROWIN_CHECK_HDC
 
1011     wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") ); 
1013     const size_t n_points 
= points
->GetCount(); 
1014     wxASSERT_MSG( n_points 
> 2 , wxT("incomplete list of spline points?") ); 
1016     const size_t n_bezier_points 
= n_points 
* 3 + 1; 
1017     POINT 
*lppt 
= (POINT 
*)malloc(n_bezier_points
*sizeof(POINT
)); 
1018     size_t bezier_pos 
= 0; 
1019     wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
; 
1021     wxList::compatibility_iterator node 
= points
->GetFirst(); 
1022     wxPoint 
*p 
= (wxPoint 
*)node
->GetData(); 
1023     lppt
[ bezier_pos 
].x 
= x1 
= p
->x
; 
1024     lppt
[ bezier_pos 
].y 
= y1 
= p
->y
; 
1026     lppt
[ bezier_pos 
] = lppt
[ bezier_pos
-1 ]; 
1029     node 
= node
->GetNext(); 
1030     p 
= (wxPoint 
*)node
->GetData(); 
1034     cx1 
= ( x1 
+ x2 
) / 2; 
1035     cy1 
= ( y1 
+ y2 
) / 2; 
1036     lppt
[ bezier_pos 
].x 
= XLOG2DEV(cx1
); 
1037     lppt
[ bezier_pos 
].y 
= YLOG2DEV(cy1
); 
1039     lppt
[ bezier_pos 
] = lppt
[ bezier_pos
-1 ]; 
1043     while ((node 
= node
->GetNext()) != NULL
) 
1045     while ((node 
= node
->GetNext())) 
1046 #endif // !wxUSE_STL 
1048         p 
= (wxPoint 
*)node
->GetData(); 
1053         cx4 
= (x1 
+ x2
) / 2; 
1054         cy4 
= (y1 
+ y2
) / 2; 
1055         // B0 is B3 of previous segment 
1057         lppt
[ bezier_pos 
].x 
= XLOG2DEV((x1
*2+cx1
)/3); 
1058         lppt
[ bezier_pos 
].y 
= YLOG2DEV((y1
*2+cy1
)/3); 
1061         lppt
[ bezier_pos 
].x 
= XLOG2DEV((x1
*2+cx4
)/3); 
1062         lppt
[ bezier_pos 
].y 
= YLOG2DEV((y1
*2+cy4
)/3); 
1065         lppt
[ bezier_pos 
].x 
= XLOG2DEV(cx4
); 
1066         lppt
[ bezier_pos 
].y 
= YLOG2DEV(cy4
); 
1072     lppt
[ bezier_pos 
] = lppt
[ bezier_pos
-1 ]; 
1074     lppt
[ bezier_pos 
].x 
= XLOG2DEV(x2
); 
1075     lppt
[ bezier_pos 
].y 
= YLOG2DEV(y2
); 
1077     lppt
[ bezier_pos 
] = lppt
[ bezier_pos
-1 ]; 
1080     ::PolyBezier( GetHdc(), lppt
, bezier_pos 
); 
1087 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
1088 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
1091     DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea 
); 
1094     WXMICROWIN_CHECK_HDC
 
1096     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
1101     int rx1 
= XLOG2DEV(x
+w
/2); 
1102     int ry1 
= YLOG2DEV(y
+h
/2); 
1109     rx1 
+= (int)(100.0 * abs(w
) * cos(sa
)); 
1110     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa
)); 
1111     rx2 
+= (int)(100.0 * abs(w
) * cos(ea
)); 
1112     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea
)); 
1114     // draw pie with NULL_PEN first and then outline otherwise a line is 
1115     // drawn from the start and end points to the centre 
1116     HPEN hpenOld 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
1119         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
1120                   rx1
, ry1
, rx2
, ry2
); 
1124         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
1125                   rx1
, ry1
-1, rx2
, ry2
-1); 
1128     ::SelectObject(GetHdc(), hpenOld
); 
1130     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
1131               rx1
, ry1
, rx2
, ry2
); 
1133     CalcBoundingBox(x
, y
); 
1134     CalcBoundingBox(x2
, y2
); 
1138 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
) 
1140     WXMICROWIN_CHECK_HDC
 
1142     wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") ); 
1145     ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
); 
1147     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
)); 
1150     CalcBoundingBox(x
, y
); 
1151     CalcBoundingBox(x 
+ icon
.GetWidth(), y 
+ icon
.GetHeight()); 
1154 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, wxCoord x
, wxCoord y
, bool useMask 
) 
1156     WXMICROWIN_CHECK_HDC
 
1158     wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 
1160     int width 
= bmp
.GetWidth(), 
1161         height 
= bmp
.GetHeight(); 
1163     HBITMAP hbmpMask 
= 0; 
1166     HPALETTE oldPal 
= 0; 
1167 #endif // wxUSE_PALETTE 
1169     if ( bmp
.HasAlpha() ) 
1172         SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmp
)); 
1174         if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) ) 
1180         wxMask 
*mask 
= bmp
.GetMask(); 
1182             hbmpMask 
= (HBITMAP
)mask
->GetMaskBitmap(); 
1186             // don't give assert here because this would break existing 
1187             // programs - just silently ignore useMask parameter 
1194         // use MaskBlt() with ROP which doesn't do anything to dst in the mask 
1196         // On some systems, MaskBlt succeeds yet is much much slower 
1197         // than the wxWidgets fall-back implementation. So we need 
1198         // to be able to switch this on and off at runtime. 
1200 #if wxUSE_SYSTEM_OPTIONS 
1201         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1205             HDC hdcMem 
= ::CreateCompatibleDC(GetHdc()); 
1206             HGDIOBJ hOldBitmap 
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
)); 
1208             wxPalette 
*pal 
= bmp
.GetPalette(); 
1209             if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1211                 oldPal 
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
); 
1212                 ::RealizePalette(hdcMem
); 
1214 #endif // wxUSE_PALETTE 
1216             ok 
= ::MaskBlt(cdc
, x
, y
, width
, height
, 
1219                             MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0; 
1223                 ::SelectPalette(hdcMem
, oldPal
, FALSE
); 
1224 #endif // wxUSE_PALETTE 
1226             ::SelectObject(hdcMem
, hOldBitmap
); 
1233             // Rather than reproduce wxDC::Blit, let's do it at the wxWin API 
1236             memDC
.SelectObject(bmp
); 
1238             Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
); 
1240             memDC
.SelectObject(wxNullBitmap
); 
1243     else // no mask, just use BitBlt() 
1246         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
1247         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
1249         wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") ); 
1251         COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1252         COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1253         if (m_textForegroundColour
.Ok()) 
1255             ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1257         if (m_textBackgroundColour
.Ok()) 
1259             ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1263         wxPalette 
*pal 
= bmp
.GetPalette(); 
1264         if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1266             oldPal 
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
); 
1267             ::RealizePalette(memdc
); 
1269 #endif // wxUSE_PALETTE 
1271         HGDIOBJ hOldBitmap 
= ::SelectObject( memdc
, hbitmap 
); 
1272         ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
); 
1276             ::SelectPalette(memdc
, oldPal
, FALSE
); 
1277 #endif // wxUSE_PALETTE 
1279         ::SelectObject( memdc
, hOldBitmap 
); 
1280         ::DeleteDC( memdc 
); 
1282         ::SetTextColor(GetHdc(), old_textground
); 
1283         ::SetBkColor(GetHdc(), old_background
); 
1287 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1289     WXMICROWIN_CHECK_HDC
 
1291     DrawAnyText(text
, x
, y
); 
1293     // update the bounding box 
1294     CalcBoundingBox(x
, y
); 
1297     GetTextExtent(text
, &w
, &h
); 
1298     CalcBoundingBox(x 
+ w
, y 
+ h
); 
1301 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1303     WXMICROWIN_CHECK_HDC
 
1305     // prepare for drawing the text 
1306     if ( m_textForegroundColour
.Ok() ) 
1307         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
1309     DWORD old_background 
= 0; 
1310     if ( m_textBackgroundColour
.Ok() ) 
1312         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1315     SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
1319     if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
, 
1320                    text
.c_str(), text
.length(), NULL
) == 0 ) 
1322         wxLogLastError(wxT("TextOut")); 
1325     if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
1326                    text
.c_str(), text
.length()) == 0 ) 
1328         wxLogLastError(wxT("TextOut")); 
1332     // restore the old parameters (text foreground colour may be left because 
1333     // it never is set to anything else, but background should remain 
1334     // transparent even if we just drew an opaque string) 
1335     if ( m_textBackgroundColour
.Ok() ) 
1336         (void)SetBkColor(GetHdc(), old_background
); 
1338     SetBkMode(GetHdc(), TRANSPARENT
); 
1341 void wxDC::DoDrawRotatedText(const wxString
& text
, 
1342                              wxCoord x
, wxCoord y
, 
1345     WXMICROWIN_CHECK_HDC
 
1347     // we test that we have some font because otherwise we should still use the 
1348     // "else" part below to avoid that DrawRotatedText(angle = 180) and 
1349     // DrawRotatedText(angle = 0) use different fonts (we can't use the default 
1350     // font for drawing rotated fonts unfortunately) 
1351     if ( (angle 
== 0.0) && m_font
.Ok() ) 
1353         DoDrawText(text
, x
, y
); 
1355 #ifndef __WXMICROWIN__ 
1358         // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) 
1359         //     because it's not TrueType and so can't have non zero 
1360         //     orientation/escapement under Win9x 
1361         wxFont font 
= m_font
.Ok() ? m_font 
: *wxSWISS_FONT
; 
1362         HFONT hfont 
= (HFONT
)font
.GetResourceHandle(); 
1364         if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 ) 
1366             wxLogLastError(wxT("GetObject(hfont)")); 
1369         // GDI wants the angle in tenth of degree 
1370         long angle10 
= (long)(angle 
* 10); 
1371         lf
.lfEscapement 
= angle10
; 
1372         lf
. lfOrientation 
= angle10
; 
1374         hfont 
= ::CreateFontIndirect(&lf
); 
1377             wxLogLastError(wxT("CreateFont")); 
1381             HFONT hfontOld 
= (HFONT
)::SelectObject(GetHdc(), hfont
); 
1383             DrawAnyText(text
, x
, y
); 
1385             (void)::SelectObject(GetHdc(), hfontOld
); 
1386             (void)::DeleteObject(hfont
); 
1389         // call the bounding box by adding all four vertices of the rectangle 
1390         // containing the text to it (simpler and probably not slower than 
1391         // determining which of them is really topmost/leftmost/...) 
1393         GetTextExtent(text
, &w
, &h
); 
1395         double rad 
= DegToRad(angle
); 
1397         // "upper left" and "upper right" 
1398         CalcBoundingBox(x
, y
); 
1399         CalcBoundingBox(x 
+ wxCoord(w
*cos(rad
)), y 
- wxCoord(w
*sin(rad
))); 
1401         // "bottom left" and "bottom right" 
1402         x 
+= (wxCoord
)(h
*sin(rad
)); 
1403         y 
+= (wxCoord
)(h
*cos(rad
)); 
1404         CalcBoundingBox(x
, y
); 
1405         CalcBoundingBox(x 
+ wxCoord(w
*cos(rad
)), y 
- wxCoord(w
*sin(rad
))); 
1410 // --------------------------------------------------------------------------- 
1412 // --------------------------------------------------------------------------- 
1416 void wxDC::DoSelectPalette(bool realize
) 
1418     WXMICROWIN_CHECK_HDC
 
1420     // Set the old object temporarily, in case the assignment deletes an object 
1421     // that's not yet selected out. 
1424         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
); 
1428     if ( m_palette
.Ok() ) 
1430         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), 
1431                                           GetHpaletteOf(m_palette
), 
1434             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
1437             ::RealizePalette(GetHdc()); 
1441 void wxDC::SetPalette(const wxPalette
& palette
) 
1445         m_palette 
= palette
; 
1446         DoSelectPalette(true); 
1450 void wxDC::InitializePalette() 
1452     if ( wxDisplayDepth() <= 8 ) 
1454         // look for any window or parent that has a custom palette. If any has 
1455         // one then we need to use it in drawing operations 
1456         wxWindow 
*win 
= m_canvas
->GetAncestorWithCustomPalette(); 
1458         m_hasCustomPalette 
= win 
&& win
->HasCustomPalette(); 
1459         if ( m_hasCustomPalette 
) 
1461             m_palette 
= win
->GetPalette(); 
1463             // turn on MSW translation for this palette 
1469 #endif // wxUSE_PALETTE 
1471 // SetFont/Pen/Brush() really ask to be implemented as a single template 
1472 // function... but doing it is not worth breaking OpenWatcom build <sigh> 
1474 void wxDC::SetFont(const wxFont
& font
) 
1476     WXMICROWIN_CHECK_HDC
 
1478     if ( font 
== m_font 
) 
1483         HGDIOBJ hfont 
= ::SelectObject(GetHdc(), GetHfontOf(font
)); 
1484         if ( hfont 
== HGDI_ERROR 
) 
1486             wxLogLastError(_T("SelectObject(font)")); 
1491                 m_oldFont 
= (WXHFONT
)hfont
; 
1496     else // invalid font, reset the current font 
1500             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR 
) 
1502                 wxLogLastError(_T("SelectObject(old font)")); 
1508         m_font 
= wxNullFont
; 
1512 void wxDC::SetPen(const wxPen
& pen
) 
1514     WXMICROWIN_CHECK_HDC
 
1521         HGDIOBJ hpen 
= ::SelectObject(GetHdc(), GetHpenOf(pen
)); 
1522         if ( hpen 
== HGDI_ERROR 
) 
1524             wxLogLastError(_T("SelectObject(pen)")); 
1529                 m_oldPen 
= (WXHPEN
)hpen
; 
1534     else // invalid pen, reset the current pen 
1538             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR 
) 
1540                 wxLogLastError(_T("SelectObject(old pen)")); 
1550 void wxDC::SetBrush(const wxBrush
& brush
) 
1552     WXMICROWIN_CHECK_HDC
 
1554     if ( brush 
== m_brush 
) 
1559         // we must make sure the brush is aligned with the logical coordinates 
1560         // before selecting it 
1561         wxBitmap 
*stipple 
= brush
.GetStipple(); 
1562         if ( stipple 
&& stipple
->Ok() ) 
1564             if ( !::SetBrushOrgEx
 
1567                         m_deviceOriginX 
% stipple
->GetWidth(), 
1568                         m_deviceOriginY 
% stipple
->GetHeight(), 
1569                         NULL                    
// [out] previous brush origin 
1572                 wxLogLastError(_T("SetBrushOrgEx()")); 
1576         HGDIOBJ hbrush 
= ::SelectObject(GetHdc(), GetHbrushOf(brush
)); 
1577         if ( hbrush 
== HGDI_ERROR 
) 
1579             wxLogLastError(_T("SelectObject(brush)")); 
1584                 m_oldBrush 
= (WXHBRUSH
)hbrush
; 
1589     else // invalid brush, reset the current brush 
1593             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR 
) 
1595                 wxLogLastError(_T("SelectObject(old brush)")); 
1601         m_brush 
= wxNullBrush
; 
1605 void wxDC::SetBackground(const wxBrush
& brush
) 
1607     WXMICROWIN_CHECK_HDC
 
1609     m_backgroundBrush 
= brush
; 
1611     if ( m_backgroundBrush
.Ok() ) 
1613         (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel()); 
1617 void wxDC::SetBackgroundMode(int mode
) 
1619     WXMICROWIN_CHECK_HDC
 
1621     m_backgroundMode 
= mode
; 
1623     // SetBackgroundColour now only refers to text background 
1624     // and m_backgroundMode is used there 
1627 void wxDC::SetLogicalFunction(int function
) 
1629     WXMICROWIN_CHECK_HDC
 
1631     m_logicalFunction 
= function
; 
1636 void wxDC::SetRop(WXHDC dc
) 
1638     if ( !dc 
|| m_logicalFunction 
< 0 ) 
1643     switch (m_logicalFunction
) 
1645         case wxCLEAR
:        rop 
= R2_BLACK
;         break; 
1646         case wxXOR
:          rop 
= R2_XORPEN
;        break; 
1647         case wxINVERT
:       rop 
= R2_NOT
;           break; 
1648         case wxOR_REVERSE
:   rop 
= R2_MERGEPENNOT
;   break; 
1649         case wxAND_REVERSE
:  rop 
= R2_MASKPENNOT
;    break; 
1650         case wxCOPY
:         rop 
= R2_COPYPEN
;       break; 
1651         case wxAND
:          rop 
= R2_MASKPEN
;       break; 
1652         case wxAND_INVERT
:   rop 
= R2_MASKNOTPEN
;    break; 
1653         case wxNO_OP
:        rop 
= R2_NOP
;           break; 
1654         case wxNOR
:          rop 
= R2_NOTMERGEPEN
;   break; 
1655         case wxEQUIV
:        rop 
= R2_NOTXORPEN
;     break; 
1656         case wxSRC_INVERT
:   rop 
= R2_NOTCOPYPEN
;    break; 
1657         case wxOR_INVERT
:    rop 
= R2_MERGENOTPEN
;   break; 
1658         case wxNAND
:         rop 
= R2_NOTMASKPEN
;    break; 
1659         case wxOR
:           rop 
= R2_MERGEPEN
;      break; 
1660         case wxSET
:          rop 
= R2_WHITE
;         break; 
1663            wxFAIL_MSG( wxT("unsupported logical function") ); 
1667     SetROP2(GetHdc(), rop
); 
1670 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
)) 
1672     // We might be previewing, so return true to let it continue. 
1680 void wxDC::StartPage() 
1684 void wxDC::EndPage() 
1688 // --------------------------------------------------------------------------- 
1690 // --------------------------------------------------------------------------- 
1692 wxCoord 
wxDC::GetCharHeight() const 
1694     WXMICROWIN_CHECK_HDC_RET(0) 
1696     TEXTMETRIC lpTextMetric
; 
1698     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1700     return lpTextMetric
.tmHeight
; 
1703 wxCoord 
wxDC::GetCharWidth() const 
1705     WXMICROWIN_CHECK_HDC_RET(0) 
1707     TEXTMETRIC lpTextMetric
; 
1709     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1711     return lpTextMetric
.tmAveCharWidth
; 
1714 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord 
*x
, wxCoord 
*y
, 
1715                            wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1718 #ifdef __WXMICROWIN__ 
1723         if (descent
) *descent 
= 0; 
1724         if (externalLeading
) *externalLeading 
= 0; 
1727 #endif // __WXMICROWIN__ 
1732         wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") ); 
1734         hfontOld 
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
)); 
1736     else // don't change the font 
1742     const size_t len 
= string
.length(); 
1743     if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) ) 
1745         wxLogLastError(_T("GetTextExtentPoint32()")); 
1748 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) 
1749     // the result computed by GetTextExtentPoint32() may be too small as it 
1750     // accounts for under/overhang of the first/last character while we want 
1751     // just the bounding rect for this string so adjust the width as needed 
1752     // (using API not available in 2002 SDKs of WinCE) 
1756         const wxChar chFirst 
= *string
.begin(); 
1757         if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) ) 
1759             if ( width
.abcA 
< 0 ) 
1760                 sizeRect
.cx 
-= width
.abcA
; 
1764                 const wxChar chLast 
= *string
.rbegin(); 
1765                 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
); 
1767             //else: we already have the width of the last character 
1769             if ( width
.abcC 
< 0 ) 
1770                 sizeRect
.cx 
-= width
.abcC
; 
1772         //else: GetCharABCWidths() failed, not a TrueType font? 
1774 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) 
1777     ::GetTextMetrics(GetHdc(), &tm
); 
1784         *descent 
= tm
.tmDescent
; 
1785     if (externalLeading
) 
1786         *externalLeading 
= tm
.tmExternalLeading
; 
1790         ::SelectObject(GetHdc(), hfontOld
); 
1795 // Each element of the array will be the width of the string up to and 
1796 // including the coresoponding character in text. 
1798 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const 
1800     static int maxLenText 
= -1; 
1801     static int maxWidth 
= -1; 
1804     int stlen 
= text
.length(); 
1806     if (maxLenText 
== -1) 
1808         // Win9x and WinNT+ have different limits 
1809         int version 
= wxGetOsVersion(); 
1810         maxLenText 
= version 
== wxWINDOWS_NT 
? 65535 : 8192; 
1811         maxWidth 
=   version 
== wxWINDOWS_NT 
? INT_MAX 
: 32767; 
1815     widths
.Add(0, stlen
);  // fill the array with zeros 
1819     if (!::GetTextExtentExPoint(GetHdc(), 
1820                                 text
.c_str(),           // string to check 
1821                                 wxMin(stlen
, maxLenText
), 
1823                                 &fit
,                   // [out] count of chars 
1825                                 &widths
[0],             // array to fill 
1829         wxLogLastError(wxT("GetTextExtentExPoint")); 
1839 void wxDC::SetMapMode(int mode
) 
1841     WXMICROWIN_CHECK_HDC
 
1843     m_mappingMode 
= mode
; 
1845     if ( mode 
== wxMM_TEXT 
) 
1848         m_logicalScaleY 
= 1.0; 
1850     else // need to do some calculations 
1852         int pixel_width 
= ::GetDeviceCaps(GetHdc(), HORZRES
), 
1853             pixel_height 
= ::GetDeviceCaps(GetHdc(), VERTRES
), 
1854             mm_width 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
), 
1855             mm_height 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1857         if ( (mm_width 
== 0) || (mm_height 
== 0) ) 
1859             // we can't calculate mm2pixels[XY] then! 
1863         double mm2pixelsX 
= (double)pixel_width 
/ mm_width
, 
1864                mm2pixelsY 
= (double)pixel_height 
/ mm_height
; 
1869                 m_logicalScaleX 
= twips2mm 
* mm2pixelsX
; 
1870                 m_logicalScaleY 
= twips2mm 
* mm2pixelsY
; 
1874                 m_logicalScaleX 
= pt2mm 
* mm2pixelsX
; 
1875                 m_logicalScaleY 
= pt2mm 
* mm2pixelsY
; 
1879                 m_logicalScaleX 
= mm2pixelsX
; 
1880                 m_logicalScaleY 
= mm2pixelsY
; 
1884                 m_logicalScaleX 
= mm2pixelsX 
/ 10.0; 
1885                 m_logicalScaleY 
= mm2pixelsY 
/ 10.0; 
1889                 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); 
1893     // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of 
1894     //     cases we could do with MM_TEXT and in the remaining 0.9% with 
1895     //     MM_ISOTROPIC (TODO!) 
1897     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1899     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
1900         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
1902     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1903     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
1905     ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
); 
1906     ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
); 
1910 void wxDC::SetUserScale(double x
, double y
) 
1912     WXMICROWIN_CHECK_HDC
 
1914     if ( x 
== m_userScaleX 
&& y 
== m_userScaleY 
) 
1920     this->SetMapMode(m_mappingMode
); 
1923 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
), 
1924                               bool WXUNUSED_IN_WINCE(yBottomUp
)) 
1926     WXMICROWIN_CHECK_HDC
 
1929     int signX 
= xLeftRight 
? 1 : -1, 
1930         signY 
= yBottomUp 
? -1 : 1; 
1932     if ( signX 
!= m_signX 
|| signY 
!= m_signY 
) 
1937         SetMapMode(m_mappingMode
); 
1942 void wxDC::SetSystemScale(double x
, double y
) 
1944     WXMICROWIN_CHECK_HDC
 
1946     if ( x 
== m_scaleX 
&& y 
== m_scaleY 
) 
1953     SetMapMode(m_mappingMode
); 
1957 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1959     WXMICROWIN_CHECK_HDC
 
1961     if ( x 
== m_logicalOriginX 
&& y 
== m_logicalOriginY 
) 
1964     m_logicalOriginX 
= x
; 
1965     m_logicalOriginY 
= y
; 
1968     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1972 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1974     WXMICROWIN_CHECK_HDC
 
1976     if ( x 
== m_deviceOriginX 
&& y 
== m_deviceOriginY 
) 
1979     m_deviceOriginX 
= x
; 
1980     m_deviceOriginY 
= y
; 
1982     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1985 // --------------------------------------------------------------------------- 
1986 // coordinates transformations 
1987 // --------------------------------------------------------------------------- 
1989 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1991     return DeviceToLogicalXRel(x 
- m_deviceOriginX
)*m_signX 
+ m_logicalOriginX
; 
1994 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1996     // axis orientation is not taken into account for conversion of a distance 
1997     return (wxCoord
)(x 
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
)); 
2000 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
2002     return DeviceToLogicalYRel(y 
- m_deviceOriginY
)*m_signY 
+ m_logicalOriginY
; 
2005 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
2007     // axis orientation is not taken into account for conversion of a distance 
2008     return (wxCoord
)( y 
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
)); 
2011 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
2013     return LogicalToDeviceXRel(x 
- m_logicalOriginX
)*m_signX 
+ m_deviceOriginX
; 
2016 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
2018     // axis orientation is not taken into account for conversion of a distance 
2019     return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
); 
2022 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
2024     return LogicalToDeviceYRel(y 
- m_logicalOriginY
)*m_signY 
+ m_deviceOriginY
; 
2027 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
2029     // axis orientation is not taken into account for conversion of a distance 
2030     return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
); 
2033 // --------------------------------------------------------------------------- 
2035 // --------------------------------------------------------------------------- 
2037 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, 
2038                   wxCoord width
, wxCoord height
, 
2039                   wxDC 
*source
, wxCoord xsrc
, wxCoord ysrc
, 
2040                   int rop
, bool useMask
, 
2041                   wxCoord xsrcMask
, wxCoord ysrcMask
) 
2043     wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") ); 
2045     WXMICROWIN_CHECK_HDC_RET(false) 
2047     // if either the source or destination has alpha channel, we must use 
2048     // AlphaBlt() as other function don't handle it correctly 
2049     const wxBitmap
& bmpSrc 
= source
->m_selectedBitmap
; 
2050     if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() || 
2051             (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) ) 
2053         if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
, 
2054                       xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) ) 
2058     wxMask 
*mask 
= NULL
; 
2061         mask 
= bmpSrc
.GetMask(); 
2063         if ( !(bmpSrc
.Ok() && mask 
&& mask
->GetMaskBitmap()) ) 
2065             // don't give assert here because this would break existing 
2066             // programs - just silently ignore useMask parameter 
2071     if (xsrcMask 
== -1 && ysrcMask 
== -1) 
2073         xsrcMask 
= xsrc
; ysrcMask 
= ysrc
; 
2076     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
2077     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
2078     if (m_textForegroundColour
.Ok()) 
2080         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
2082     if (m_textBackgroundColour
.Ok()) 
2084         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
2090         case wxXOR
:          dwRop 
= SRCINVERT
;        break; 
2091         case wxINVERT
:       dwRop 
= DSTINVERT
;        break; 
2092         case wxOR_REVERSE
:   dwRop 
= 0x00DD0228;       break; 
2093         case wxAND_REVERSE
:  dwRop 
= SRCERASE
;         break; 
2094         case wxCLEAR
:        dwRop 
= BLACKNESS
;        break; 
2095         case wxSET
:          dwRop 
= WHITENESS
;        break; 
2096         case wxOR_INVERT
:    dwRop 
= MERGEPAINT
;       break; 
2097         case wxAND
:          dwRop 
= SRCAND
;           break; 
2098         case wxOR
:           dwRop 
= SRCPAINT
;         break; 
2099         case wxEQUIV
:        dwRop 
= 0x00990066;       break; 
2100         case wxNAND
:         dwRop 
= 0x007700E6;       break; 
2101         case wxAND_INVERT
:   dwRop 
= 0x00220326;       break; 
2102         case wxCOPY
:         dwRop 
= SRCCOPY
;          break; 
2103         case wxNO_OP
:        dwRop 
= DSTCOPY
;          break; 
2104         case wxSRC_INVERT
:   dwRop 
= NOTSRCCOPY
;       break; 
2105         case wxNOR
:          dwRop 
= NOTSRCCOPY
;       break; 
2107            wxFAIL_MSG( wxT("unsupported logical function") ); 
2111     bool success 
= false; 
2116         // we want the part of the image corresponding to the mask to be 
2117         // transparent, so use "DSTCOPY" ROP for the mask points (the usual 
2118         // meaning of fg and bg is inverted which corresponds to wxWin notion 
2119         // of the mask which is also contrary to the Windows one) 
2121         // On some systems, MaskBlt succeeds yet is much much slower 
2122         // than the wxWidgets fall-back implementation. So we need 
2123         // to be able to switch this on and off at runtime. 
2124 #if wxUSE_SYSTEM_OPTIONS 
2125         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
2131                             xdest
, ydest
, width
, height
, 
2134                             (HBITMAP
)mask
->GetMaskBitmap(), 
2136                             MAKEROP4(dwRop
, DSTCOPY
) 
2143             // Blit bitmap with mask 
2146             HBITMAP buffer_bmap 
; 
2148 #if wxUSE_DC_CACHEING 
2149             // create a temp buffer bitmap and DCs to access it and the mask 
2150             wxDCCacheEntry
* dcCacheEntry1 
= FindDCInCache(NULL
, source
->GetHDC()); 
2151             dc_mask 
= (HDC
) dcCacheEntry1
->m_dc
; 
2153             wxDCCacheEntry
* dcCacheEntry2 
= FindDCInCache(dcCacheEntry1
, GetHDC()); 
2154             dc_buffer 
= (HDC
) dcCacheEntry2
->m_dc
; 
2156             wxDCCacheEntry
* bitmapCacheEntry 
= FindBitmapInCache(GetHDC(), 
2159             buffer_bmap 
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
; 
2160 #else // !wxUSE_DC_CACHEING 
2161             // create a temp buffer bitmap and DCs to access it and the mask 
2162             dc_mask 
= ::CreateCompatibleDC(GetHdcOf(*source
)); 
2163             dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
2164             buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
2165 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING 
2166             HGDIOBJ hOldMaskBitmap 
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap()); 
2167             HGDIOBJ hOldBufferBitmap 
= ::SelectObject(dc_buffer
, buffer_bmap
); 
2169             // copy dest to buffer 
2170             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2171                            GetHdc(), xdest
, ydest
, SRCCOPY
) ) 
2173                 wxLogLastError(wxT("BitBlt")); 
2176             // copy src to buffer using selected raster op 
2177             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2178                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) ) 
2180                 wxLogLastError(wxT("BitBlt")); 
2183             // set masked area in buffer to BLACK (pixel value 0) 
2184             COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
2185             COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
2186             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2187                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
2189                 wxLogLastError(wxT("BitBlt")); 
2192             // set unmasked area in dest to BLACK 
2193             ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
2194             ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
2195             if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
, 
2196                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
2198                 wxLogLastError(wxT("BitBlt")); 
2200             ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
2201             ::SetTextColor(GetHdc(), prevCol
); 
2203             // OR buffer to dest 
2204             success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
2205                                (int)width
, (int)height
, 
2206                                dc_buffer
, 0, 0, SRCPAINT
) != 0; 
2209                 wxLogLastError(wxT("BitBlt")); 
2212             // tidy up temporary DCs and bitmap 
2213             ::SelectObject(dc_mask
, hOldMaskBitmap
); 
2214             ::SelectObject(dc_buffer
, hOldBufferBitmap
); 
2216 #if !wxUSE_DC_CACHEING 
2218                 ::DeleteDC(dc_mask
); 
2219                 ::DeleteDC(dc_buffer
); 
2220                 ::DeleteObject(buffer_bmap
); 
2225     else // no mask, just BitBlt() it 
2227         // if we already have a DIB, draw it using StretchDIBits(), otherwise 
2228         // use StretchBlt() if available and finally fall back to BitBlt() 
2230         // FIXME: use appropriate WinCE functions 
2232         const int caps 
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
); 
2233         if ( bmpSrc
.Ok() && (caps 
& RC_STRETCHDIB
) ) 
2238             if ( ::GetObject(GetHbitmapOf(bmpSrc
), 
2240                              &ds
) == sizeof(ds
) ) 
2242                 StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2244                 // Figure out what co-ordinate system we're supposed to specify 
2246                 const LONG hDIB 
= ds
.dsBmih
.biHeight
; 
2250                     ysrc 
= hDIB 
- (ysrc 
+ height
); 
2253                 if ( ::StretchDIBits(GetHdc(), 
2259                                      (LPBITMAPINFO
)&ds
.dsBmih
, 
2262                                      ) == (int)GDI_ERROR 
) 
2264                     // On Win9x this API fails most (all?) of the time, so 
2265                     // logging it becomes quite distracting.  Since it falls 
2266                     // back to the code below this is not really serious, so 
2268                     //wxLogLastError(wxT("StretchDIBits")); 
2277         if ( !success 
&& (caps 
& RC_STRETCHBLT
) ) 
2282             StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2288                         xdest
, ydest
, width
, height
, 
2290                         xsrc
, ysrc
, width
, height
, 
2294                 wxLogLastError(_T("StretchBlt")); 
2308                         (int)width
, (int)height
, 
2314                 wxLogLastError(_T("BitBlt")); 
2323     ::SetTextColor(GetHdc(), old_textground
); 
2324     ::SetBkColor(GetHdc(), old_background
); 
2329 void wxDC::GetDeviceSize(int *width
, int *height
) const 
2331     WXMICROWIN_CHECK_HDC
 
2334         *width 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2336         *height 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2339 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
2341     WXMICROWIN_CHECK_HDC
 
2343     // if we implement it in terms of DoGetSize() instead of directly using the 
2344     // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it 
2345     // will also work for wxWindowDC and wxClientDC even though their size is 
2346     // not the same as the total size of the screen 
2347     int wPixels
, hPixels
; 
2348     DoGetSize(&wPixels
, &hPixels
); 
2352         int wTotal 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2354         wxCHECK_RET( wTotal
, _T("0 width device?") ); 
2356         *w 
= (wPixels 
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
; 
2361         int hTotal 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2363         wxCHECK_RET( hTotal
, _T("0 height device?") ); 
2365         *h 
= (hPixels 
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
; 
2369 wxSize 
wxDC::GetPPI() const 
2371     WXMICROWIN_CHECK_HDC_RET(wxSize(0,0)) 
2373     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
2374     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
2376     return wxSize(x
, y
); 
2379 // For use by wxWidgets only, unless custom units are required. 
2380 void wxDC::SetLogicalScale(double x
, double y
) 
2382     WXMICROWIN_CHECK_HDC
 
2384     m_logicalScaleX 
= x
; 
2385     m_logicalScaleY 
= y
; 
2388 // ---------------------------------------------------------------------------- 
2390 // ---------------------------------------------------------------------------- 
2392 #if wxUSE_DC_CACHEING 
2395  * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will 
2396  * improve it in due course, either using arrays, or simply storing pointers to one 
2397  * entry for the bitmap, and two for the DCs. -- JACS 
2400 wxList 
wxDC::sm_bitmapCache
; 
2401 wxList 
wxDC::sm_dcCache
; 
2403 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
) 
2412 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
) 
2421 wxDCCacheEntry::~wxDCCacheEntry() 
2424         ::DeleteObject((HBITMAP
) m_bitmap
); 
2426         ::DeleteDC((HDC
) m_dc
); 
2429 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
) 
2431     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2432     wxList::compatibility_iterator node 
= sm_bitmapCache
.GetFirst(); 
2435         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2437         if (entry
->m_depth 
== depth
) 
2439             if (entry
->m_width 
< w 
|| entry
->m_height 
< h
) 
2441                 ::DeleteObject((HBITMAP
) entry
->m_bitmap
); 
2442                 entry
->m_bitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2443                 if ( !entry
->m_bitmap
) 
2445                     wxLogLastError(wxT("CreateCompatibleBitmap")); 
2447                 entry
->m_width 
= w
; entry
->m_height 
= h
; 
2453         node 
= node
->GetNext(); 
2455     WXHBITMAP hBitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2458         wxLogLastError(wxT("CreateCompatibleBitmap")); 
2460     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
); 
2461     AddToBitmapCache(entry
); 
2465 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
) 
2467     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2468     wxList::compatibility_iterator node 
= sm_dcCache
.GetFirst(); 
2471         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2473         // Don't return the same one as we already have 
2474         if (!notThis 
|| (notThis 
!= entry
)) 
2476             if (entry
->m_depth 
== depth
) 
2482         node 
= node
->GetNext(); 
2484     WXHDC hDC 
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
); 
2487         wxLogLastError(wxT("CreateCompatibleDC")); 
2489     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hDC
, depth
); 
2490     AddToDCCache(entry
); 
2494 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
) 
2496     sm_bitmapCache
.Append(entry
); 
2499 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
) 
2501     sm_dcCache
.Append(entry
); 
2504 void wxDC::ClearCache() 
2506     WX_CLEAR_LIST(wxList
, sm_dcCache
); 
2507     WX_CLEAR_LIST(wxList
, sm_bitmapCache
); 
2510 // Clean up cache at app exit 
2511 class wxDCModule 
: public wxModule
 
2514     virtual bool OnInit() { return true; } 
2515     virtual void OnExit() { wxDC::ClearCache(); } 
2518     DECLARE_DYNAMIC_CLASS(wxDCModule
) 
2521 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
) 
2523 #endif // wxUSE_DC_CACHEING 
2525 // ---------------------------------------------------------------------------- 
2526 // alpha channel support 
2527 // ---------------------------------------------------------------------------- 
2529 static bool AlphaBlt(HDC hdcDst
, 
2530                      int x
, int y
, int width
, int height
, 
2531                      int srcX
, int srcY
, HDC hdcSrc
, 
2532                      const wxBitmap
& bmp
) 
2534     wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") ); 
2535     wxASSERT_MSG( hdcDst 
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") ); 
2537     // do we have AlphaBlend() and company in the headers? 
2538 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS 
2539     // yes, now try to see if we have it during run-time 
2540     typedef BOOL (WINAPI 
*AlphaBlend_t
)(HDC
,int,int,int,int, 
2541                                         HDC
,int,int,int,int, 
2544     static AlphaBlend_t pfnAlphaBlend 
= wxMSIMG32_SYMBOL(AlphaBlend
); 
2545     if ( pfnAlphaBlend 
) 
2548         bf
.BlendOp 
= AC_SRC_OVER
; 
2550         bf
.SourceConstantAlpha 
= 0xff; 
2551         bf
.AlphaFormat 
= AC_SRC_ALPHA
; 
2553         if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
, 
2554                            hdcSrc
, srcX
, srcY
, width
, height
, 
2557             // skip wxAlphaBlend() call below 
2561         wxLogLastError(_T("AlphaBlend")); 
2564     wxUnusedVar(hdcSrc
); 
2565 #endif // defined(AC_SRC_OVER) 
2567     // AlphaBlend() unavailable of failed: use our own (probably much slower) 
2569 #ifdef wxHAVE_RAW_BITMAP 
2570     wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
); 
2573 #else // !wxHAVE_RAW_BITMAP 
2574     // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose 
2575     // alpha but at least something will be shown like this) 
2578 #endif // wxHAVE_RAW_BITMAP 
2582 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable 
2583 #ifdef wxHAVE_RAW_BITMAP 
2586 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, 
2588              int srcX
, int srcY
, const wxBitmap
& bmpSrc
) 
2590     // get the destination DC pixels 
2591     wxBitmap 
bmpDst(w
, h
, 32 /* force creating RGBA DIB */); 
2593     SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmpDst
)); 
2595     if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) ) 
2597         wxLogLastError(_T("BitBlt")); 
2600     // combine them with the source bitmap using alpha 
2601     wxAlphaPixelData 
dataDst(bmpDst
), 
2602                      dataSrc((wxBitmap 
&)bmpSrc
); 
2604     wxCHECK_RET( dataDst 
&& dataSrc
, 
2605                     _T("failed to get raw data in wxAlphaBlend") ); 
2607     wxAlphaPixelData::Iterator 
pDst(dataDst
), 
2610     pSrc
.Offset(dataSrc
, srcX
, srcY
); 
2612     for ( int y 
= 0; y 
< h
; y
++ ) 
2614         wxAlphaPixelData::Iterator pDstRowStart 
= pDst
, 
2615                                    pSrcRowStart 
= pSrc
; 
2617         for ( int x 
= 0; x 
< w
; x
++ ) 
2619             // note that source bitmap uses premultiplied alpha (as required by 
2620             // the real AlphaBlend) 
2621             const unsigned beta 
= 255 - pSrc
.Alpha(); 
2623             pDst
.Red() = pSrc
.Red() + (beta 
* pDst
.Red() + 127) / 255; 
2624             pDst
.Blue() = pSrc
.Blue() + (beta 
* pDst
.Blue() + 127) / 255; 
2625             pDst
.Green() = pSrc
.Green() + (beta 
* pDst
.Green() + 127) / 255; 
2631         pDst 
= pDstRowStart
; 
2632         pSrc 
= pSrcRowStart
; 
2633         pDst
.OffsetY(dataDst
, 1); 
2634         pSrc
.OffsetY(dataSrc
, 1); 
2637     // and finally blit them back to the destination DC 
2638     if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) ) 
2640         wxLogLastError(_T("BitBlt")); 
2644 #endif // #ifdef wxHAVE_RAW_BITMAP 
2646 void wxDC::DoGradientFillLinear (const wxRect
& rect
, 
2647                                  const wxColour
& initialColour
, 
2648                                  const wxColour
& destColour
, 
2649                                  wxDirection nDirection
) 
2651     // use native function if we have compile-time support it and can load it 
2652     // during run-time (linking to it statically would make the program 
2653     // unusable on earlier Windows versions) 
2654 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS 
2656         (WINAPI 
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
); 
2657     static GradientFill_t pfnGradientFill 
= wxMSIMG32_SYMBOL(GradientFill
); 
2659     if ( pfnGradientFill 
) 
2661         GRADIENT_RECT grect
; 
2662         grect
.UpperLeft 
= 0; 
2663         grect
.LowerRight 
= 1; 
2665         // invert colours direction if not filling from left-to-right or 
2667         int firstVertex 
= nDirection 
== wxNORTH 
|| nDirection 
== wxWEST 
? 1 : 0; 
2669         // one vertex for upper left and one for upper-right 
2670         TRIVERTEX vertices
[2]; 
2672         vertices
[0].x 
= rect
.GetLeft(); 
2673         vertices
[0].y 
= rect
.GetTop(); 
2674         vertices
[1].x 
= rect
.GetRight(); 
2675         vertices
[1].y 
= rect
.GetBottom(); 
2677         vertices
[firstVertex
].Red 
= (COLOR16
)(initialColour
.Red() << 8); 
2678         vertices
[firstVertex
].Green 
= (COLOR16
)(initialColour
.Green() << 8); 
2679         vertices
[firstVertex
].Blue 
= (COLOR16
)(initialColour
.Blue() << 8); 
2680         vertices
[firstVertex
].Alpha 
= 0; 
2681         vertices
[1 - firstVertex
].Red 
= (COLOR16
)(destColour
.Red() << 8); 
2682         vertices
[1 - firstVertex
].Green 
= (COLOR16
)(destColour
.Green() << 8); 
2683         vertices
[1 - firstVertex
].Blue 
= (COLOR16
)(destColour
.Blue() << 8); 
2684         vertices
[1 - firstVertex
].Alpha 
= 0; 
2686         if ( (*pfnGradientFill
) 
2693                 nDirection 
== wxWEST 
|| nDirection 
== wxEAST
 
2694                     ? GRADIENT_FILL_RECT_H
 
2695                     : GRADIENT_FILL_RECT_V
 
2698             // skip call of the base class version below 
2702         wxLogLastError(_T("GradientFill")); 
2704 #endif // wxUSE_DYNLIB_CLASS 
2706     wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);