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> 
  44 #include "wx/msw/missing.h" // needs to be before #include <commdlg.h> 
  46 #include "wx/sysopt.h" 
  47 #include "wx/dcprint.h" 
  48 #include "wx/module.h" 
  49 #include "wx/dynload.h" 
  51 #ifdef wxHAVE_RAW_BITMAP 
  52 #include "wx/rawbmp.h" 
  58 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__) 
  67 #define AC_SRC_ALPHA 1 
  70 /* Quaternary raster codes */ 
  72 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) 
  75 // apparently with MicroWindows it is possible that HDC is 0 so we have to 
  76 // check for this ourselves 
  78     #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return; 
  79     #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x; 
  81     #define WXMICROWIN_CHECK_HDC 
  82     #define WXMICROWIN_CHECK_HDC_RET(x) 
  85 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
) 
  87 // --------------------------------------------------------------------------- 
  89 // --------------------------------------------------------------------------- 
  91 static const int VIEWPORT_EXTENT 
= 1000; 
  93 static const int MM_POINTS 
= 9; 
  94 static const int MM_METRIC 
= 10; 
  96 // usually this is defined in math.h 
  98     static const double M_PI 
= 3.14159265358979323846; 
 101 // ROPs which don't have standard names (see "Ternary Raster Operations" in the 
 102 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) 
 103 #define DSTCOPY 0x00AA0029      // a.k.a. NOP operation 
 105 // ---------------------------------------------------------------------------- 
 106 // macros for logical <-> device coords conversion 
 107 // ---------------------------------------------------------------------------- 
 110    We currently let Windows do all the translations itself so these macros are 
 111    not really needed (any more) but keep them to enhance readability of the 
 112    code by allowing to see where are the logical and where are the device 
 117 #define XLOG2DEV(x) (x) 
 118 #define YLOG2DEV(y) (y) 
 121 #define XDEV2LOG(x) (x) 
 122 #define YDEV2LOG(y) (y) 
 124 // --------------------------------------------------------------------------- 
 126 // --------------------------------------------------------------------------- 
 128 // convert degrees to radians 
 129 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
 131 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha 
 133 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed 
 134 //     to pass it to this function but as we already have it at the point 
 135 //     of call anyhow we do 
 137 // return true if we could draw the bitmap in one way or the other, false 
 139 static bool AlphaBlt(HDC hdcDst
, 
 140                      int x
, int y
, int w
, int h
, 
 142                      const wxBitmap
& bmpSrc
); 
 144 #ifdef wxHAVE_RAW_BITMAP 
 145 // our (limited) AlphaBlend() replacement 
 147 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
); 
 150 // ---------------------------------------------------------------------------- 
 152 // ---------------------------------------------------------------------------- 
 154 // instead of duplicating the same code which sets and then restores text 
 155 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, 
 156 // encapsulate this in a small helper class 
 158 // wxColourChanger: changes the text colours in the ctor if required and 
 159 //                  restores them in the dtor 
 160 class wxColourChanger
 
 163     wxColourChanger(wxDC
& dc
); 
 169     COLORREF m_colFgOld
, m_colBgOld
; 
 173     DECLARE_NO_COPY_CLASS(wxColourChanger
) 
 176 // this class saves the old stretch blit mode during its life time 
 177 class StretchBltModeChanger
 
 180     StretchBltModeChanger(HDC hdc
, int mode
) 
 184         m_modeOld 
= ::SetStretchBltMode(m_hdc
, mode
); 
 186             wxLogLastError(_T("SetStretchBltMode")); 
 190     ~StretchBltModeChanger() 
 193         if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) ) 
 194             wxLogLastError(_T("SetStretchBltMode")); 
 203     DECLARE_NO_COPY_CLASS(StretchBltModeChanger
) 
 206 // =========================================================================== 
 208 // =========================================================================== 
 210 // ---------------------------------------------------------------------------- 
 212 // ---------------------------------------------------------------------------- 
 214 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
) 
 216     const wxBrush
& brush 
= dc
.GetBrush(); 
 217     if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 219         HDC hdc 
= GetHdcOf(dc
); 
 220         m_colFgOld 
= ::GetTextColor(hdc
); 
 221         m_colBgOld 
= ::GetBkColor(hdc
); 
 223         // note that Windows convention is opposite to wxWindows one, this is 
 224         // why text colour becomes the background one and vice versa 
 225         const wxColour
& colFg 
= dc
.GetTextForeground(); 
 228             ::SetBkColor(hdc
, colFg
.GetPixel()); 
 231         const wxColour
& colBg 
= dc
.GetTextBackground(); 
 234             ::SetTextColor(hdc
, colBg
.GetPixel()); 
 238                   dc
.GetBackgroundMode() == wxTRANSPARENT 
? TRANSPARENT
 
 241         // flag which telsl us to undo changes in the dtor 
 246         // nothing done, nothing to undo 
 251 wxColourChanger::~wxColourChanger() 
 255         // restore the colours we changed 
 256         HDC hdc 
= GetHdcOf(m_dc
); 
 258         ::SetBkMode(hdc
, TRANSPARENT
); 
 259         ::SetTextColor(hdc
, m_colFgOld
); 
 260         ::SetBkColor(hdc
, m_colBgOld
); 
 264 // --------------------------------------------------------------------------- 
 266 // --------------------------------------------------------------------------- 
 268 // Default constructor 
 279 #endif // wxUSE_PALETTE 
 289         SelectOldObjects(m_hDC
); 
 291         // if we own the HDC, we delete it, otherwise we just release it 
 295             ::DeleteDC(GetHdc()); 
 297         else // we don't own our HDC 
 301                 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc()); 
 305                 // Must have been a wxScreenDC 
 306                 ::ReleaseDC((HWND
) NULL
, GetHdc()); 
 312 // This will select current objects out of the DC, 
 313 // which is what you have to do before deleting the 
 315 void wxDC::SelectOldObjects(WXHDC dc
) 
 321             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 323             if (m_selectedBitmap
.Ok()) 
 325                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 332             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 337             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 342             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 349             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
); 
 352 #endif // wxUSE_PALETTE 
 355     m_brush 
= wxNullBrush
; 
 358     m_palette 
= wxNullPalette
; 
 359 #endif // wxUSE_PALETTE 
 361     m_backgroundBrush 
= wxNullBrush
; 
 362     m_selectedBitmap 
= wxNullBitmap
; 
 365 // --------------------------------------------------------------------------- 
 367 // --------------------------------------------------------------------------- 
 369 void wxDC::UpdateClipBox() 
 374     ::GetClipBox(GetHdc(), &rect
); 
 376     m_clipX1 
= (wxCoord
) XDEV2LOG(rect
.left
); 
 377     m_clipY1 
= (wxCoord
) YDEV2LOG(rect
.top
); 
 378     m_clipX2 
= (wxCoord
) XDEV2LOG(rect
.right
); 
 379     m_clipY2 
= (wxCoord
) YDEV2LOG(rect
.bottom
); 
 382 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion() 
 383 void wxDC::SetClippingHrgn(WXHRGN hrgn
) 
 385     wxCHECK_RET( hrgn
, wxT("invalid clipping region") ); 
 389     // note that we combine the new clipping region with the existing one: this 
 390     // is compatible with what the other ports do and is the documented 
 391     // behaviour now (starting with 2.3.3) 
 392 #if defined(__WXWINCE__) 
 394     if ( !::GetClipBox(GetHdc(), &rectClip
) ) 
 397     HRGN hrgnDest 
= ::CreateRectRgn(0, 0, 0, 0); 
 398     HRGN hrgnClipOld 
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
, 
 399                                        rectClip
.right
, rectClip
.bottom
); 
 401     if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR 
) 
 403         ::SelectClipRgn(GetHdc(), hrgnDest
); 
 406     ::DeleteObject(hrgnClipOld
); 
 407     ::DeleteObject(hrgnDest
); 
 409     if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR 
) 
 411         wxLogLastError(_T("ExtSelectClipRgn")); 
 415 #endif // WinCE/!WinCE 
 422 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 424     // the region coords are always the device ones, so do the translation 
 427     // FIXME: possible +/-1 error here, to check! 
 428     HRGN hrgn 
= ::CreateRectRgn(LogicalToDeviceX(x
), 
 430                                 LogicalToDeviceX(x 
+ w
), 
 431                                 LogicalToDeviceY(y 
+ h
)); 
 434         wxLogLastError(_T("CreateRectRgn")); 
 438         SetClippingHrgn((WXHRGN
)hrgn
); 
 440         ::DeleteObject(hrgn
); 
 444 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 446     SetClippingHrgn(region
.GetHRGN()); 
 449 void wxDC::DestroyClippingRegion() 
 453     if (m_clipping 
&& m_hDC
) 
 455         // TODO: this should restore the previous clipping region, 
 456         //       so that OnPaint processing works correctly, and the update 
 457         //       clipping region doesn't get destroyed after the first 
 458         //       DestroyClippingRegion. 
 459         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 460         ::SelectClipRgn(GetHdc(), rgn
); 
 467 // --------------------------------------------------------------------------- 
 468 // query capabilities 
 469 // --------------------------------------------------------------------------- 
 471 bool wxDC::CanDrawBitmap() const 
 476 bool wxDC::CanGetTextExtent() const 
 478 #ifdef __WXMICROWIN__ 
 479     // TODO Extend MicroWindows' GetDeviceCaps function 
 482     // What sort of display is it? 
 483     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 485     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 489 int wxDC::GetDepth() const 
 491     WXMICROWIN_CHECK_HDC_RET(16) 
 493     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 496 // --------------------------------------------------------------------------- 
 498 // --------------------------------------------------------------------------- 
 507         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 511         // No, I think we should simply ignore this if printing on e.g. 
 513         // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 
 514         if (!m_selectedBitmap
.Ok()) 
 517         rect
.left 
= 0; rect
.top 
= 0; 
 518         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 519         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 523     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 526     DWORD colour 
= ::GetBkColor(GetHdc()); 
 527     HBRUSH brush 
= ::CreateSolidBrush(colour
); 
 528     ::FillRect(GetHdc(), &rect
, brush
); 
 529     ::DeleteObject(brush
); 
 531     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
 532         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
 535     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 537     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 538     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
 539     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 540     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 544 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
) 
 550     WXMICROWIN_CHECK_HDC_RET(false) 
 552     bool success 
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 554                          style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 555                                                   : FLOODFILLBORDER
) ) ; 
 558         // quoting from the MSDN docs: 
 560         //      Following are some of the reasons this function might fail: 
 562         //      * The filling could not be completed. 
 563         //      * The specified point has the boundary color specified by the 
 564         //        crColor parameter (if FLOODFILLBORDER was requested). 
 565         //      * The specified point does not have the color specified by 
 566         //        crColor (if FLOODFILLSURFACE was requested) 
 567         //      * The point is outside the clipping region that is, it is not 
 568         //        visible on the device. 
 570         wxLogLastError(wxT("ExtFloodFill")); 
 573     CalcBoundingBox(x
, y
); 
 579 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour 
*col
) const 
 581     WXMICROWIN_CHECK_HDC_RET(false) 
 583     wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") ); 
 585     // get the color of the pixel 
 586     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 588     wxRGBToColour(*col
, pixelcolor
); 
 593 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
) 
 597     wxCoord x1 
= x
-VIEWPORT_EXTENT
; 
 598     wxCoord y1 
= y
-VIEWPORT_EXTENT
; 
 599     wxCoord x2 
= x
+VIEWPORT_EXTENT
; 
 600     wxCoord y2 
= y
+VIEWPORT_EXTENT
; 
 602     wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 603     wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 605     CalcBoundingBox(x1
, y1
); 
 606     CalcBoundingBox(x2
, y2
); 
 609 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 613     wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 615     CalcBoundingBox(x1
, y1
); 
 616     CalcBoundingBox(x2
, y2
); 
 619 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) 
 620 // and ending at (x2, y2) 
 621 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
, 
 622                      wxCoord x2
, wxCoord y2
, 
 623                      wxCoord xc
, wxCoord yc
) 
 626     // Slower emulation since WinCE doesn't support Pie and Arc 
 627     double r 
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) ); 
 628     double sa 
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180 
 629     if( y1
>yc 
) sa 
= -sa
; // below center 
 630     double ea 
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180; 
 631     DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea 
); 
 636     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 640     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
); 
 641     wxCoord r 
= (wxCoord
)radius
; 
 643     // treat the special case of full circle separately 
 644     if ( x1 
== x2 
&& y1 
== y2 
) 
 646         DrawEllipse(xc 
- r
, yc 
- r
, 2*r
, 2*r
); 
 650     wxCoord xx1 
= XLOG2DEV(x1
); 
 651     wxCoord yy1 
= YLOG2DEV(y1
); 
 652     wxCoord xx2 
= XLOG2DEV(x2
); 
 653     wxCoord yy2 
= YLOG2DEV(y2
); 
 654     wxCoord xxc 
= XLOG2DEV(xc
); 
 655     wxCoord yyc 
= YLOG2DEV(yc
); 
 656     wxCoord ray 
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 658     wxCoord xxx1 
= (wxCoord
) (xxc
-ray
); 
 659     wxCoord yyy1 
= (wxCoord
) (yyc
-ray
); 
 660     wxCoord xxx2 
= (wxCoord
) (xxc
+ray
); 
 661     wxCoord yyy2 
= (wxCoord
) (yyc
+ray
); 
 663     if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT 
) 
 665         // Have to add 1 to bottom-right corner of rectangle 
 666         // to make semi-circles look right (crooked line otherwise). 
 667         // Unfortunately this is not a reliable method, depends 
 668         // on the size of shape. 
 669         // TODO: figure out why this happens! 
 670         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
); 
 674         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
); 
 677     CalcBoundingBox(xc 
- r
, yc 
- r
); 
 678     CalcBoundingBox(xc 
+ r
, yc 
+ r
); 
 682 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
 683                            wxCoord width
, wxCoord height
) 
 687     wxCoord x2 
= x1 
+ width
, 
 690 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__) 
 698     DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
); 
 700     DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
); 
 702 #else // Symantec-MicroWin 
 704     HPEN blackPen 
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0)); 
 705     HPEN whiteBrush 
= (HPEN
)::GetStockObject(WHITE_BRUSH
); 
 706     HPEN hPenOld 
= (HPEN
)::SelectObject(GetHdc(), blackPen
); 
 707     HPEN hBrushOld 
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
); 
 708     ::SetROP2(GetHdc(), R2_COPYPEN
); 
 709     Rectangle(GetHdc(), x1
, y1
, x2
, y2
); 
 710     MoveToEx(GetHdc(), x1
, y1
, NULL
); 
 711     LineTo(GetHdc(), x2
, y2
); 
 712     MoveToEx(GetHdc(), x2
, y1
, NULL
); 
 713     LineTo(GetHdc(), x1
, y2
); 
 714     ::SelectObject(GetHdc(), hPenOld
); 
 715     ::SelectObject(GetHdc(), hBrushOld
); 
 716     ::DeleteObject(blackPen
); 
 717 #endif // Win32/Symantec-MicroWin 
 719     CalcBoundingBox(x1
, y1
); 
 720     CalcBoundingBox(x2
, y2
); 
 723 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
) 
 727     COLORREF color 
= 0x00ffffff; 
 730         color 
= m_pen
.GetColour().GetPixel(); 
 733     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 735     CalcBoundingBox(x
, y
); 
 738 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
) 
 742     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 744     // Do things less efficiently if we have offsets 
 745     if (xoffset 
!= 0 || yoffset 
!= 0) 
 747         POINT 
*cpoints 
= new POINT
[n
]; 
 749         for (i 
= 0; i 
< n
; i
++) 
 751             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 752             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 754             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 757         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 759         (void)Polygon(GetHdc(), cpoints
, n
); 
 761         SetPolyFillMode(GetHdc(),prev
); 
 768         for (i 
= 0; i 
< n
; i
++) 
 769             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 772         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 774         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 776         SetPolyFillMode(GetHdc(),prev
); 
 782 wxDC::DoDrawPolyPolygon(int n
, 
 790     wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
); 
 794     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 796     for (i 
= cnt 
= 0; i 
< n
; i
++) 
 799     // Do things less efficiently if we have offsets 
 800     if (xoffset 
!= 0 || yoffset 
!= 0) 
 802         POINT 
*cpoints 
= new POINT
[cnt
]; 
 803         for (i 
= 0; i 
< cnt
; i
++) 
 805             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 806             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 808             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 811         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 813         (void)PolyPolygon(GetHdc(), cpoints
, count
, n
); 
 815         SetPolyFillMode(GetHdc(),prev
); 
 821         for (i 
= 0; i 
< cnt
; i
++) 
 822             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 825         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 827         (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
); 
 829         SetPolyFillMode(GetHdc(),prev
); 
 836 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 840     // Do things less efficiently if we have offsets 
 841     if (xoffset 
!= 0 || yoffset 
!= 0) 
 843         POINT 
*cpoints 
= new POINT
[n
]; 
 845         for (i 
= 0; i 
< n
; i
++) 
 847             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 848             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 850             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 852         (void)Polyline(GetHdc(), cpoints
, n
); 
 858         for (i 
= 0; i 
< n
; i
++) 
 859             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 861         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 865 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 869     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 871     wxCoord x2 
= x 
+ width
; 
 872     wxCoord y2 
= y 
+ height
; 
 874     if ((m_logicalFunction 
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
)) 
 877         rect
.left 
= XLOG2DEV(x
); 
 878         rect
.top 
= YLOG2DEV(y
); 
 879         rect
.right 
= XLOG2DEV(x2
); 
 880         rect
.bottom 
= YLOG2DEV(y2
); 
 881         (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() ); 
 885         // Windows draws the filled rectangles without outline (i.e. drawn with a 
 886         // transparent pen) one pixel smaller in both directions and we want them 
 887         // to have the same size regardless of which pen is used - adjust 
 889         // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. 
 890         if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 896         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 900     CalcBoundingBox(x
, y
); 
 901     CalcBoundingBox(x2
, y2
); 
 904 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 908     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 910     // Now, a negative radius value is interpreted to mean 
 911     // 'the proportion of the smallest X or Y dimension' 
 915         double smallest 
= (width 
< height
) ? width 
: height
; 
 916         radius 
= (- radius 
* smallest
); 
 919     wxCoord x2 
= (x
+width
); 
 920     wxCoord y2 
= (y
+height
); 
 922     // Windows draws the filled rectangles without outline (i.e. drawn with a 
 923     // transparent pen) one pixel smaller in both directions and we want them 
 924     // to have the same size regardless of which pen is used - adjust 
 925     if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 931     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 932         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 934     CalcBoundingBox(x
, y
); 
 935     CalcBoundingBox(x2
, y2
); 
 938 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 942     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 944     wxCoord x2 
= (x
+width
); 
 945     wxCoord y2 
= (y
+height
); 
 947     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 949     CalcBoundingBox(x
, y
); 
 950     CalcBoundingBox(x2
, y2
); 
 953 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
 954 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 957     DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea 
); 
 962     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 967     int rx1 
= XLOG2DEV(x
+w
/2); 
 968     int ry1 
= YLOG2DEV(y
+h
/2); 
 975     rx1 
+= (int)(100.0 * abs(w
) * cos(sa
)); 
 976     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa
)); 
 977     rx2 
+= (int)(100.0 * abs(w
) * cos(ea
)); 
 978     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea
)); 
 980     // draw pie with NULL_PEN first and then outline otherwise a line is 
 981     // drawn from the start and end points to the centre 
 982     HPEN hpenOld 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 985         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
 990         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
 991                   rx1
, ry1
-1, rx2
, ry2
-1); 
 994     ::SelectObject(GetHdc(), hpenOld
); 
 996     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
 999     CalcBoundingBox(x
, y
); 
1000     CalcBoundingBox(x2
, y2
); 
1004 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
) 
1006     WXMICROWIN_CHECK_HDC
 
1008     wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") ); 
1011     ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
); 
1013     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
)); 
1016     CalcBoundingBox(x
, y
); 
1017     CalcBoundingBox(x 
+ icon
.GetWidth(), y 
+ icon
.GetHeight()); 
1020 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, wxCoord x
, wxCoord y
, bool useMask 
) 
1022     WXMICROWIN_CHECK_HDC
 
1024     wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 
1026     int width 
= bmp
.GetWidth(), 
1027         height 
= bmp
.GetHeight(); 
1029     HBITMAP hbmpMask 
= 0; 
1032     HPALETTE oldPal 
= 0; 
1033 #endif // wxUSE_PALETTE 
1035     if ( bmp
.HasAlpha() ) 
1038         SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmp
)); 
1040         if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) ) 
1046         wxMask 
*mask 
= bmp
.GetMask(); 
1048             hbmpMask 
= (HBITMAP
)mask
->GetMaskBitmap(); 
1052             // don't give assert here because this would break existing 
1053             // programs - just silently ignore useMask parameter 
1060         // use MaskBlt() with ROP which doesn't do anything to dst in the mask 
1062         // On some systems, MaskBlt succeeds yet is much much slower 
1063         // than the wxWindows fall-back implementation. So we need 
1064         // to be able to switch this on and off at runtime. 
1066 #if wxUSE_SYSTEM_OPTIONS 
1067         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1071             HDC hdcMem 
= ::CreateCompatibleDC(GetHdc()); 
1072             HGDIOBJ hOldBitmap 
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
)); 
1074             wxPalette 
*pal 
= bmp
.GetPalette(); 
1075             if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1077                 oldPal 
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
); 
1078                 ::RealizePalette(hdcMem
); 
1080 #endif // wxUSE_PALETTE 
1082             ok 
= ::MaskBlt(cdc
, x
, y
, width
, height
, 
1085                             MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0; 
1089                 ::SelectPalette(hdcMem
, oldPal
, FALSE
); 
1090 #endif // wxUSE_PALETTE 
1092             ::SelectObject(hdcMem
, hOldBitmap
); 
1099             // Rather than reproduce wxDC::Blit, let's do it at the wxWin API 
1102             memDC
.SelectObject(bmp
); 
1104             Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
); 
1106             memDC
.SelectObject(wxNullBitmap
); 
1109     else // no mask, just use BitBlt() 
1112         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
1113         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
1115         wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") ); 
1117         COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1118         COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1119         if (m_textForegroundColour
.Ok()) 
1121             ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1123         if (m_textBackgroundColour
.Ok()) 
1125             ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1129         wxPalette 
*pal 
= bmp
.GetPalette(); 
1130         if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1132             oldPal 
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
); 
1133             ::RealizePalette(memdc
); 
1135 #endif // wxUSE_PALETTE 
1137         HGDIOBJ hOldBitmap 
= ::SelectObject( memdc
, hbitmap 
); 
1138         ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
); 
1142             ::SelectPalette(memdc
, oldPal
, FALSE
); 
1143 #endif // wxUSE_PALETTE 
1145         ::SelectObject( memdc
, hOldBitmap 
); 
1146         ::DeleteDC( memdc 
); 
1148         ::SetTextColor(GetHdc(), old_textground
); 
1149         ::SetBkColor(GetHdc(), old_background
); 
1153 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1155     WXMICROWIN_CHECK_HDC
 
1157     DrawAnyText(text
, x
, y
); 
1159     // update the bounding box 
1160     CalcBoundingBox(x
, y
); 
1163     GetTextExtent(text
, &w
, &h
); 
1164     CalcBoundingBox(x 
+ w
, y 
+ h
); 
1167 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1169     WXMICROWIN_CHECK_HDC
 
1171     // prepare for drawing the text 
1172     if ( m_textForegroundColour
.Ok() ) 
1173         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
1175     DWORD old_background 
= 0; 
1176     if ( m_textBackgroundColour
.Ok() ) 
1178         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1181     SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
1185     if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
, 
1186                    text
.c_str(), text
.length(), NULL
) == 0 ) 
1188         wxLogLastError(wxT("TextOut")); 
1191     if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
1192                    text
.c_str(), text
.length()) == 0 ) 
1194         wxLogLastError(wxT("TextOut")); 
1198     // restore the old parameters (text foreground colour may be left because 
1199     // it never is set to anything else, but background should remain 
1200     // transparent even if we just drew an opaque string) 
1201     if ( m_textBackgroundColour
.Ok() ) 
1202         (void)SetBkColor(GetHdc(), old_background
); 
1204     SetBkMode(GetHdc(), TRANSPARENT
); 
1207 void wxDC::DoDrawRotatedText(const wxString
& text
, 
1208                              wxCoord x
, wxCoord y
, 
1211     WXMICROWIN_CHECK_HDC
 
1213     // we test that we have some font because otherwise we should still use the 
1214     // "else" part below to avoid that DrawRotatedText(angle = 180) and 
1215     // DrawRotatedText(angle = 0) use different fonts (we can't use the default 
1216     // font for drawing rotated fonts unfortunately) 
1217     if ( (angle 
== 0.0) && m_font
.Ok() ) 
1219         DoDrawText(text
, x
, y
); 
1221 #ifndef __WXMICROWIN__ 
1224         // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) 
1225         //     because it's not TrueType and so can't have non zero 
1226         //     orientation/escapement under Win9x 
1227         wxFont font 
= m_font
.Ok() ? m_font 
: *wxSWISS_FONT
; 
1228         HFONT hfont 
= (HFONT
)font
.GetResourceHandle(); 
1230         if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 ) 
1232             wxLogLastError(wxT("GetObject(hfont)")); 
1235         // GDI wants the angle in tenth of degree 
1236         long angle10 
= (long)(angle 
* 10); 
1237         lf
.lfEscapement 
= angle10
; 
1238         lf
. lfOrientation 
= angle10
; 
1240         hfont 
= ::CreateFontIndirect(&lf
); 
1243             wxLogLastError(wxT("CreateFont")); 
1247             HFONT hfontOld 
= (HFONT
)::SelectObject(GetHdc(), hfont
); 
1249             DrawAnyText(text
, x
, y
); 
1251             (void)::SelectObject(GetHdc(), hfontOld
); 
1252             (void)::DeleteObject(hfont
); 
1255         // call the bounding box by adding all four vertices of the rectangle 
1256         // containing the text to it (simpler and probably not slower than 
1257         // determining which of them is really topmost/leftmost/...) 
1259         GetTextExtent(text
, &w
, &h
); 
1261         double rad 
= DegToRad(angle
); 
1263         // "upper left" and "upper right" 
1264         CalcBoundingBox(x
, y
); 
1265         CalcBoundingBox(x 
+ wxCoord(w
*cos(rad
)), y 
- wxCoord(h
*sin(rad
))); 
1267         // "bottom left" and "bottom right" 
1268         x 
+= (wxCoord
)(h
*sin(rad
)); 
1269         y 
+= (wxCoord
)(h
*cos(rad
)); 
1270         CalcBoundingBox(x
, y
); 
1271         CalcBoundingBox(x 
+ wxCoord(h
*sin(rad
)), y 
+ wxCoord(h
*cos(rad
))); 
1276 // --------------------------------------------------------------------------- 
1278 // --------------------------------------------------------------------------- 
1282 void wxDC::DoSelectPalette(bool realize
) 
1284     WXMICROWIN_CHECK_HDC
 
1286     // Set the old object temporarily, in case the assignment deletes an object 
1287     // that's not yet selected out. 
1290         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
); 
1294     if ( m_palette
.Ok() ) 
1296         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), 
1297                                           GetHpaletteOf(m_palette
), 
1300             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
1303             ::RealizePalette(GetHdc()); 
1307 void wxDC::SetPalette(const wxPalette
& palette
) 
1311         m_palette 
= palette
; 
1312         DoSelectPalette(true); 
1316 void wxDC::InitializePalette() 
1318     if ( wxDisplayDepth() <= 8 ) 
1320         // look for any window or parent that has a custom palette. If any has 
1321         // one then we need to use it in drawing operations 
1322         wxWindow 
*win 
= m_canvas
->GetAncestorWithCustomPalette(); 
1324         m_hasCustomPalette 
= win 
&& win
->HasCustomPalette(); 
1325         if ( m_hasCustomPalette 
) 
1327             m_palette 
= win
->GetPalette(); 
1329             // turn on MSW translation for this palette 
1335 #endif // wxUSE_PALETTE 
1337 // SetFont/Pen/Brush() really ask to be implemented as a single template 
1338 // function... but doing it is not worth breaking OpenWatcom build <sigh> 
1340 void wxDC::SetFont(const wxFont
& font
) 
1342     WXMICROWIN_CHECK_HDC
 
1344     if ( font 
== m_font 
) 
1349         HGDIOBJ hfont 
= ::SelectObject(GetHdc(), GetHfontOf(font
)); 
1350         if ( hfont 
== HGDI_ERROR 
) 
1352             wxLogLastError(_T("SelectObject(font)")); 
1357                 m_oldFont 
= (WXHPEN
)hfont
; 
1362     else // invalid font, reset the current font 
1366             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR 
) 
1368                 wxLogLastError(_T("SelectObject(old font)")); 
1374         m_font 
= wxNullFont
; 
1378 void wxDC::SetPen(const wxPen
& pen
) 
1380     WXMICROWIN_CHECK_HDC
 
1387         HGDIOBJ hpen 
= ::SelectObject(GetHdc(), GetHpenOf(pen
)); 
1388         if ( hpen 
== HGDI_ERROR 
) 
1390             wxLogLastError(_T("SelectObject(pen)")); 
1395                 m_oldPen 
= (WXHPEN
)hpen
; 
1400     else // invalid pen, reset the current pen 
1404             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR 
) 
1406                 wxLogLastError(_T("SelectObject(old pen)")); 
1416 void wxDC::SetBrush(const wxBrush
& brush
) 
1418     WXMICROWIN_CHECK_HDC
 
1420     if ( brush 
== m_brush 
) 
1425         // we must make sure the brush is aligned with the logical coordinates 
1426         // before selecting it 
1427         wxBitmap 
*stipple 
= brush
.GetStipple(); 
1428         if ( stipple 
&& stipple
->Ok() ) 
1430             if ( !::SetBrushOrgEx
 
1433                         m_deviceOriginX 
% stipple
->GetWidth(), 
1434                         m_deviceOriginY 
% stipple
->GetHeight(), 
1435                         NULL                    
// [out] previous brush origin 
1438                 wxLogLastError(_T("SetBrushOrgEx()")); 
1442         HGDIOBJ hbrush 
= ::SelectObject(GetHdc(), GetHbrushOf(brush
)); 
1443         if ( hbrush 
== HGDI_ERROR 
) 
1445             wxLogLastError(_T("SelectObject(brush)")); 
1450                 m_oldBrush 
= (WXHPEN
)hbrush
; 
1455     else // invalid brush, reset the current brush 
1459             if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR 
) 
1461                 wxLogLastError(_T("SelectObject(old brush)")); 
1467         m_brush 
= wxNullBrush
; 
1471 void wxDC::SetBackground(const wxBrush
& brush
) 
1473     WXMICROWIN_CHECK_HDC
 
1475     m_backgroundBrush 
= brush
; 
1477     if ( m_backgroundBrush
.Ok() ) 
1479         (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel()); 
1483 void wxDC::SetBackgroundMode(int mode
) 
1485     WXMICROWIN_CHECK_HDC
 
1487     m_backgroundMode 
= mode
; 
1489     // SetBackgroundColour now only refers to text background 
1490     // and m_backgroundMode is used there 
1493 void wxDC::SetLogicalFunction(int function
) 
1495     WXMICROWIN_CHECK_HDC
 
1497     m_logicalFunction 
= function
; 
1502 void wxDC::SetRop(WXHDC dc
) 
1504     if ( !dc 
|| m_logicalFunction 
< 0 ) 
1509     switch (m_logicalFunction
) 
1511         case wxCLEAR
:        rop 
= R2_BLACK
;         break; 
1512         case wxXOR
:          rop 
= R2_XORPEN
;        break; 
1513         case wxINVERT
:       rop 
= R2_NOT
;           break; 
1514         case wxOR_REVERSE
:   rop 
= R2_MERGEPENNOT
;   break; 
1515         case wxAND_REVERSE
:  rop 
= R2_MASKPENNOT
;    break; 
1516         case wxCOPY
:         rop 
= R2_COPYPEN
;       break; 
1517         case wxAND
:          rop 
= R2_MASKPEN
;       break; 
1518         case wxAND_INVERT
:   rop 
= R2_MASKNOTPEN
;    break; 
1519         case wxNO_OP
:        rop 
= R2_NOP
;           break; 
1520         case wxNOR
:          rop 
= R2_NOTMERGEPEN
;   break; 
1521         case wxEQUIV
:        rop 
= R2_NOTXORPEN
;     break; 
1522         case wxSRC_INVERT
:   rop 
= R2_NOTCOPYPEN
;    break; 
1523         case wxOR_INVERT
:    rop 
= R2_MERGENOTPEN
;   break; 
1524         case wxNAND
:         rop 
= R2_NOTMASKPEN
;    break; 
1525         case wxOR
:           rop 
= R2_MERGEPEN
;      break; 
1526         case wxSET
:          rop 
= R2_WHITE
;         break; 
1529            wxFAIL_MSG( wxT("unsupported logical function") ); 
1533     SetROP2(GetHdc(), rop
); 
1536 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
)) 
1538     // We might be previewing, so return true to let it continue. 
1546 void wxDC::StartPage() 
1550 void wxDC::EndPage() 
1554 // --------------------------------------------------------------------------- 
1556 // --------------------------------------------------------------------------- 
1558 wxCoord 
wxDC::GetCharHeight() const 
1560     WXMICROWIN_CHECK_HDC_RET(0) 
1562     TEXTMETRIC lpTextMetric
; 
1564     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1566     return lpTextMetric
.tmHeight
; 
1569 wxCoord 
wxDC::GetCharWidth() const 
1571     WXMICROWIN_CHECK_HDC_RET(0) 
1573     TEXTMETRIC lpTextMetric
; 
1575     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1577     return lpTextMetric
.tmAveCharWidth
; 
1580 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord 
*x
, wxCoord 
*y
, 
1581                            wxCoord 
*descent
, wxCoord 
*externalLeading
, 
1584 #ifdef __WXMICROWIN__ 
1589         if (descent
) *descent 
= 0; 
1590         if (externalLeading
) *externalLeading 
= 0; 
1593 #endif // __WXMICROWIN__ 
1598         wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") ); 
1600         hfontOld 
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
)); 
1602     else // don't change the font 
1610     GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
); 
1611     GetTextMetrics(GetHdc(), &tm
); 
1618         *descent 
= tm
.tmDescent
; 
1619     if (externalLeading
) 
1620         *externalLeading 
= tm
.tmExternalLeading
; 
1624         ::SelectObject(GetHdc(), hfontOld
); 
1629 // Each element of the array will be the width of the string up to and 
1630 // including the coresoponding character in text. 
1632 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const 
1634     static int maxLenText 
= -1; 
1635     static int maxWidth 
= -1; 
1638     int stlen 
= text
.Length(); 
1640     if (maxLenText 
== -1) 
1642         // Win9x and WinNT+ have different limits 
1643         int version 
= wxGetOsVersion(); 
1644         maxLenText 
= version 
== wxWINDOWS_NT 
? 65535 : 8192; 
1645         maxWidth 
=   version 
== wxWINDOWS_NT 
? INT_MAX 
: 32767; 
1649     widths
.Add(0, stlen
);  // fill the array with zeros 
1651     if (!::GetTextExtentExPoint(GetHdc(), 
1652                                 text
.c_str(),           // string to check 
1653                                 wxMin(stlen
, maxLenText
), 
1655                                 &fit
,                   // [out] count of chars 
1657                                 &widths
[0],             // array to fill 
1661         wxLogLastError(wxT("GetTextExtentExPoint")); 
1671 void wxDC::SetMapMode(int mode
) 
1673     WXMICROWIN_CHECK_HDC
 
1675     m_mappingMode 
= mode
; 
1677     if ( mode 
== wxMM_TEXT 
) 
1680         m_logicalScaleY 
= 1.0; 
1682     else // need to do some calculations 
1684         int pixel_width 
= ::GetDeviceCaps(GetHdc(), HORZRES
), 
1685             pixel_height 
= ::GetDeviceCaps(GetHdc(), VERTRES
), 
1686             mm_width 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
), 
1687             mm_height 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1689         if ( (mm_width 
== 0) || (mm_height 
== 0) ) 
1691             // we can't calculate mm2pixels[XY] then! 
1695         double mm2pixelsX 
= (double)pixel_width 
/ mm_width
, 
1696                mm2pixelsY 
= (double)pixel_height 
/ mm_height
; 
1701                 m_logicalScaleX 
= twips2mm 
* mm2pixelsX
; 
1702                 m_logicalScaleY 
= twips2mm 
* mm2pixelsY
; 
1706                 m_logicalScaleX 
= pt2mm 
* mm2pixelsX
; 
1707                 m_logicalScaleY 
= pt2mm 
* mm2pixelsY
; 
1711                 m_logicalScaleX 
= mm2pixelsX
; 
1712                 m_logicalScaleY 
= mm2pixelsY
; 
1716                 m_logicalScaleX 
= mm2pixelsX 
/ 10.0; 
1717                 m_logicalScaleY 
= mm2pixelsY 
/ 10.0; 
1721                 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); 
1725     // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of 
1726     //     cases we could do with MM_TEXT and in the remaining 0.9% with 
1727     //     MM_ISOTROPIC (TODO!) 
1729     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1731     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
1732         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
1734     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1735     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
1737     ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
); 
1738     ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
); 
1742 void wxDC::SetUserScale(double x
, double y
) 
1744     WXMICROWIN_CHECK_HDC
 
1747     if ( x 
== m_userScaleX 
&& y 
== m_userScaleY 
) 
1753     SetMapMode(m_mappingMode
); 
1757 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
) 
1759     WXMICROWIN_CHECK_HDC
 
1762     int signX 
= xLeftRight 
? 1 : -1, 
1763         signY 
= yBottomUp 
? -1 : 1; 
1765     if ( signX 
!= m_signX 
|| signY 
!= m_signY 
) 
1770         SetMapMode(m_mappingMode
); 
1775 void wxDC::SetSystemScale(double x
, double y
) 
1777     WXMICROWIN_CHECK_HDC
 
1780     if ( x 
== m_scaleX 
&& y 
== m_scaleY 
) 
1786     SetMapMode(m_mappingMode
); 
1790 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1792     WXMICROWIN_CHECK_HDC
 
1795     if ( x 
== m_logicalOriginX 
&& y 
== m_logicalOriginY 
) 
1798     m_logicalOriginX 
= x
; 
1799     m_logicalOriginY 
= y
; 
1801     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1805 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1807     WXMICROWIN_CHECK_HDC
 
1810     if ( x 
== m_deviceOriginX 
&& y 
== m_deviceOriginY 
) 
1813     m_deviceOriginX 
= x
; 
1814     m_deviceOriginY 
= y
; 
1816     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1820 // --------------------------------------------------------------------------- 
1821 // coordinates transformations 
1822 // --------------------------------------------------------------------------- 
1824 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1826     return DeviceToLogicalXRel(x 
- m_deviceOriginX
)*m_signX 
+ m_logicalOriginX
; 
1829 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1831     // axis orientation is not taken into account for conversion of a distance 
1832     return (wxCoord
)(x 
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
)); 
1835 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
1837     return DeviceToLogicalYRel(y 
- m_deviceOriginY
)*m_signY 
+ m_logicalOriginY
; 
1840 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
1842     // axis orientation is not taken into account for conversion of a distance 
1843     return (wxCoord
)( y 
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
)); 
1846 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
1848     return LogicalToDeviceXRel(x 
- m_logicalOriginX
)*m_signX 
+ m_deviceOriginX
; 
1851 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
1853     // axis orientation is not taken into account for conversion of a distance 
1854     return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
); 
1857 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
1859     return LogicalToDeviceYRel(y 
- m_logicalOriginY
)*m_signY 
+ m_deviceOriginY
; 
1862 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
1864     // axis orientation is not taken into account for conversion of a distance 
1865     return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
); 
1868 // --------------------------------------------------------------------------- 
1870 // --------------------------------------------------------------------------- 
1872 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, 
1873                   wxCoord width
, wxCoord height
, 
1874                   wxDC 
*source
, wxCoord xsrc
, wxCoord ysrc
, 
1875                   int rop
, bool useMask
, 
1876                   wxCoord xsrcMask
, wxCoord ysrcMask
) 
1878     wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") ); 
1880     WXMICROWIN_CHECK_HDC_RET(false) 
1882     const wxBitmap
& bmpSrc 
= source
->m_selectedBitmap
; 
1883     if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() ) 
1885         if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
, 
1886                       GetHdcOf(*source
), bmpSrc
) ) 
1890     wxMask 
*mask 
= NULL
; 
1893         mask 
= bmpSrc
.GetMask(); 
1895         if ( !(bmpSrc
.Ok() && mask 
&& mask
->GetMaskBitmap()) ) 
1897             // don't give assert here because this would break existing 
1898             // programs - just silently ignore useMask parameter 
1903     if (xsrcMask 
== -1 && ysrcMask 
== -1) 
1905         xsrcMask 
= xsrc
; ysrcMask 
= ysrc
; 
1908     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1909     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1910     if (m_textForegroundColour
.Ok()) 
1912         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1914     if (m_textBackgroundColour
.Ok()) 
1916         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1922         case wxXOR
:          dwRop 
= SRCINVERT
;        break; 
1923         case wxINVERT
:       dwRop 
= DSTINVERT
;        break; 
1924         case wxOR_REVERSE
:   dwRop 
= 0x00DD0228;       break; 
1925         case wxAND_REVERSE
:  dwRop 
= SRCERASE
;         break; 
1926         case wxCLEAR
:        dwRop 
= BLACKNESS
;        break; 
1927         case wxSET
:          dwRop 
= WHITENESS
;        break; 
1928         case wxOR_INVERT
:    dwRop 
= MERGEPAINT
;       break; 
1929         case wxAND
:          dwRop 
= SRCAND
;           break; 
1930         case wxOR
:           dwRop 
= SRCPAINT
;         break; 
1931         case wxEQUIV
:        dwRop 
= 0x00990066;       break; 
1932         case wxNAND
:         dwRop 
= 0x007700E6;       break; 
1933         case wxAND_INVERT
:   dwRop 
= 0x00220326;       break; 
1934         case wxCOPY
:         dwRop 
= SRCCOPY
;          break; 
1935         case wxNO_OP
:        dwRop 
= DSTCOPY
;          break; 
1936         case wxSRC_INVERT
:   dwRop 
= NOTSRCCOPY
;       break; 
1937         case wxNOR
:          dwRop 
= NOTSRCCOPY
;       break; 
1939            wxFAIL_MSG( wxT("unsupported logical function") ); 
1943     bool success 
= false; 
1948         // we want the part of the image corresponding to the mask to be 
1949         // transparent, so use "DSTCOPY" ROP for the mask points (the usual 
1950         // meaning of fg and bg is inverted which corresponds to wxWin notion 
1951         // of the mask which is also contrary to the Windows one) 
1953         // On some systems, MaskBlt succeeds yet is much much slower 
1954         // than the wxWindows fall-back implementation. So we need 
1955         // to be able to switch this on and off at runtime. 
1956 #if wxUSE_SYSTEM_OPTIONS 
1957         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1963                             xdest
, ydest
, width
, height
, 
1966                             (HBITMAP
)mask
->GetMaskBitmap(), 
1968                             MAKEROP4(dwRop
, DSTCOPY
) 
1975             // Blit bitmap with mask 
1978             HBITMAP buffer_bmap 
; 
1980 #if wxUSE_DC_CACHEING 
1981             // create a temp buffer bitmap and DCs to access it and the mask 
1982             wxDCCacheEntry
* dcCacheEntry1 
= FindDCInCache(NULL
, source
->GetHDC()); 
1983             dc_mask 
= (HDC
) dcCacheEntry1
->m_dc
; 
1985             wxDCCacheEntry
* dcCacheEntry2 
= FindDCInCache(dcCacheEntry1
, GetHDC()); 
1986             dc_buffer 
= (HDC
) dcCacheEntry2
->m_dc
; 
1988             wxDCCacheEntry
* bitmapCacheEntry 
= FindBitmapInCache(GetHDC(), 
1991             buffer_bmap 
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
; 
1992 #else // !wxUSE_DC_CACHEING 
1993             // create a temp buffer bitmap and DCs to access it and the mask 
1994             dc_mask 
= ::CreateCompatibleDC(GetHdcOf(*source
)); 
1995             dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
1996             buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
1997 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING 
1998             HGDIOBJ hOldMaskBitmap 
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap()); 
1999             HGDIOBJ hOldBufferBitmap 
= ::SelectObject(dc_buffer
, buffer_bmap
); 
2001             // copy dest to buffer 
2002             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2003                            GetHdc(), xdest
, ydest
, SRCCOPY
) ) 
2005                 wxLogLastError(wxT("BitBlt")); 
2008             // copy src to buffer using selected raster op 
2009             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2010                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) ) 
2012                 wxLogLastError(wxT("BitBlt")); 
2015             // set masked area in buffer to BLACK (pixel value 0) 
2016             COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
2017             COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
2018             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
2019                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
2021                 wxLogLastError(wxT("BitBlt")); 
2024             // set unmasked area in dest to BLACK 
2025             ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
2026             ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
2027             if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
, 
2028                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
2030                 wxLogLastError(wxT("BitBlt")); 
2032             ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
2033             ::SetTextColor(GetHdc(), prevCol
); 
2035             // OR buffer to dest 
2036             success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
2037                                (int)width
, (int)height
, 
2038                                dc_buffer
, 0, 0, SRCPAINT
) != 0; 
2041                 wxLogLastError(wxT("BitBlt")); 
2044             // tidy up temporary DCs and bitmap 
2045             ::SelectObject(dc_mask
, hOldMaskBitmap
); 
2046             ::SelectObject(dc_buffer
, hOldBufferBitmap
); 
2048 #if !wxUSE_DC_CACHEING 
2050                 ::DeleteDC(dc_mask
); 
2051                 ::DeleteDC(dc_buffer
); 
2052                 ::DeleteObject(buffer_bmap
); 
2057     else // no mask, just BitBlt() it 
2059         // if we already have a DIB, draw it using StretchDIBits(), otherwise 
2060         // use StretchBlt() if available and finally fall back to BitBlt() 
2062         // FIXME: use appropriate WinCE functions 
2064         const int caps 
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
); 
2065         if ( bmpSrc
.Ok() && (caps 
& RC_STRETCHDIB
) ) 
2070             if ( ::GetObject(GetHbitmapOf(bmpSrc
), 
2072                              &ds
) == sizeof(ds
) ) 
2074                 StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2076                 // Figure out what co-ordinate system we're supposed to specify 
2078                 const LONG hDIB 
= ds
.dsBmih
.biHeight
; 
2082                     ysrc 
= hDIB 
- (ysrc 
+ height
); 
2085                 if ( ::StretchDIBits(GetHdc(), 
2091                                      (LPBITMAPINFO
)&ds
.dsBmih
, 
2094                                      ) == (int)GDI_ERROR 
) 
2096                     // On Win9x this API fails most (all?) of the time, so 
2097                     // logging it becomes quite distracting.  Since it falls 
2098                     // back to the code below this is not really serious, so 
2100                     //wxLogLastError(wxT("StretchDIBits")); 
2109         if ( !success 
&& (caps 
& RC_STRETCHBLT
) ) 
2114             StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2120                         xdest
, ydest
, width
, height
, 
2122                         xsrc
, ysrc
, width
, height
, 
2126                 wxLogLastError(_T("StretchBlt")); 
2140                         (int)width
, (int)height
, 
2146                 wxLogLastError(_T("BitBlt")); 
2155     ::SetTextColor(GetHdc(), old_textground
); 
2156     ::SetBkColor(GetHdc(), old_background
); 
2161 void wxDC::DoGetSize(int *w
, int *h
) const 
2163     WXMICROWIN_CHECK_HDC
 
2165     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2166     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2169 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
2171     WXMICROWIN_CHECK_HDC
 
2173     // if we implement it in terms of DoGetSize() instead of directly using the 
2174     // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it 
2175     // will also work for wxWindowDC and wxClientDC even though their size is 
2176     // not the same as the total size of the screen 
2177     int wPixels
, hPixels
; 
2178     DoGetSize(&wPixels
, &hPixels
); 
2182         int wTotal 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2184         wxCHECK_RET( wTotal
, _T("0 width device?") ); 
2186         *w 
= (wPixels 
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
; 
2191         int hTotal 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2193         wxCHECK_RET( hTotal
, _T("0 height device?") ); 
2195         *h 
= (hPixels 
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
; 
2199 wxSize 
wxDC::GetPPI() const 
2201     WXMICROWIN_CHECK_HDC_RET(wxSize()) 
2203     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
2204     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
2206     return wxSize(x
, y
); 
2209 // For use by wxWindows only, unless custom units are required. 
2210 void wxDC::SetLogicalScale(double x
, double y
) 
2212     WXMICROWIN_CHECK_HDC
 
2214     m_logicalScaleX 
= x
; 
2215     m_logicalScaleY 
= y
; 
2218 // ---------------------------------------------------------------------------- 
2220 // ---------------------------------------------------------------------------- 
2222 #if wxUSE_DC_CACHEING 
2225  * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will 
2226  * improve it in due course, either using arrays, or simply storing pointers to one 
2227  * entry for the bitmap, and two for the DCs. -- JACS 
2230 wxList 
wxDC::sm_bitmapCache
; 
2231 wxList 
wxDC::sm_dcCache
; 
2233 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
) 
2242 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
) 
2251 wxDCCacheEntry::~wxDCCacheEntry() 
2254         ::DeleteObject((HBITMAP
) m_bitmap
); 
2256         ::DeleteDC((HDC
) m_dc
); 
2259 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
) 
2261     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2262     wxList::compatibility_iterator node 
= sm_bitmapCache
.GetFirst(); 
2265         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2267         if (entry
->m_depth 
== depth
) 
2269             if (entry
->m_width 
< w 
|| entry
->m_height 
< h
) 
2271                 ::DeleteObject((HBITMAP
) entry
->m_bitmap
); 
2272                 entry
->m_bitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2273                 if ( !entry
->m_bitmap
) 
2275                     wxLogLastError(wxT("CreateCompatibleBitmap")); 
2277                 entry
->m_width 
= w
; entry
->m_height 
= h
; 
2283         node 
= node
->GetNext(); 
2285     WXHBITMAP hBitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2288         wxLogLastError(wxT("CreateCompatibleBitmap")); 
2290     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
); 
2291     AddToBitmapCache(entry
); 
2295 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
) 
2297     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2298     wxList::compatibility_iterator node 
= sm_dcCache
.GetFirst(); 
2301         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2303         // Don't return the same one as we already have 
2304         if (!notThis 
|| (notThis 
!= entry
)) 
2306             if (entry
->m_depth 
== depth
) 
2312         node 
= node
->GetNext(); 
2314     WXHDC hDC 
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
); 
2317         wxLogLastError(wxT("CreateCompatibleDC")); 
2319     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hDC
, depth
); 
2320     AddToDCCache(entry
); 
2324 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
) 
2326     sm_bitmapCache
.Append(entry
); 
2329 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
) 
2331     sm_dcCache
.Append(entry
); 
2334 void wxDC::ClearCache() 
2336     WX_CLEAR_LIST(wxList
, sm_dcCache
); 
2337     WX_CLEAR_LIST(wxList
, sm_bitmapCache
); 
2340 // Clean up cache at app exit 
2341 class wxDCModule 
: public wxModule
 
2344     virtual bool OnInit() { return true; } 
2345     virtual void OnExit() { wxDC::ClearCache(); } 
2348     DECLARE_DYNAMIC_CLASS(wxDCModule
) 
2351 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
) 
2353 #endif // wxUSE_DC_CACHEING 
2355 // ---------------------------------------------------------------------------- 
2356 // alpha channel support 
2357 // ---------------------------------------------------------------------------- 
2359 static bool AlphaBlt(HDC hdcDst
, 
2360                      int x
, int y
, int width
, int height
, 
2362                      const wxBitmap
& bmp
) 
2364     wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") ); 
2365     wxASSERT_MSG( hdcDst 
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") ); 
2367     // do we have AlphaBlend() and company in the headers? 
2368 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS 
2369     // yes, now try to see if we have it during run-time 
2370     typedef BOOL (WINAPI 
*AlphaBlend_t
)(HDC
,int,int,int,int, 
2371                                         HDC
,int,int,int,int, 
2374     // bitmaps can be drawn only from GUI thread so there is no need to 
2375     // protect this static variable from multiple threads 
2376     static bool s_triedToLoad 
= false; 
2377     static AlphaBlend_t pfnAlphaBlend 
= NULL
; 
2378     if ( !s_triedToLoad 
) 
2380         s_triedToLoad 
= true; 
2382         // don't give errors about the DLL being unavailable, we're 
2383         // prepared to handle this 
2386         wxDynamicLibrary 
dll(_T("msimg32.dll")); 
2387         if ( dll
.IsLoaded() ) 
2389             pfnAlphaBlend 
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend")); 
2390             if ( pfnAlphaBlend 
) 
2392                 // we must keep the DLL loaded if we want to be able to 
2393                 // call AlphaBlend() so just never unload it at all, not a 
2400     if ( pfnAlphaBlend 
) 
2403         bf
.BlendOp 
= AC_SRC_OVER
; 
2405         bf
.SourceConstantAlpha 
= 0xff; 
2406         bf
.AlphaFormat 
= AC_SRC_ALPHA
; 
2408         if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
, 
2409                            hdcSrc
, 0, 0, width
, height
, 
2412             // skip wxAlphaBlend() call below 
2416         wxLogLastError(_T("AlphaBlend")); 
2418 #endif // defined(AC_SRC_OVER) 
2420     // AlphaBlend() unavailable of failed: use our own (probably much slower) 
2422 #ifdef wxHAVE_RAW_BITMAP 
2423     wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
); 
2426 #else // !wxHAVE_RAW_BITMAP 
2427     // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose 
2428     // alpha but at least something will be shown like this) 
2430 #endif // wxHAVE_RAW_BITMAP 
2434 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable 
2435 #ifdef wxHAVE_RAW_BITMAP 
2438 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
) 
2440     // get the destination DC pixels 
2441     wxBitmap 
bmpDst(w
, h
, 32 /* force creating RGBA DIB */); 
2443     SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmpDst
)); 
2445     if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) ) 
2447         wxLogLastError(_T("BitBlt")); 
2450     // combine them with the source bitmap using alpha 
2451     wxAlphaPixelData 
dataDst(bmpDst
), 
2452                      dataSrc((wxBitmap 
&)bmpSrc
); 
2454     wxCHECK_RET( dataDst 
&& dataSrc
, 
2455                     _T("failed to get raw data in wxAlphaBlend") ); 
2457     wxAlphaPixelData::Iterator 
pDst(dataDst
), 
2460     for ( int y 
= 0; y 
< h
; y
++ ) 
2462         wxAlphaPixelData::Iterator pDstRowStart 
= pDst
, 
2463                                    pSrcRowStart 
= pSrc
; 
2465         for ( int x 
= 0; x 
< w
; x
++ ) 
2467             // note that source bitmap uses premultiplied alpha (as required by 
2468             // the real AlphaBlend) 
2469             const unsigned beta 
= 255 - pSrc
.Alpha(); 
2471             pDst
.Red() = pSrc
.Red() + (beta 
* pDst
.Red() + 127) / 255; 
2472             pDst
.Blue() = pSrc
.Blue() + (beta 
* pDst
.Blue() + 127) / 255; 
2473             pDst
.Green() = pSrc
.Green() + (beta 
* pDst
.Green() + 127) / 255; 
2479         pDst 
= pDstRowStart
; 
2480         pSrc 
= pSrcRowStart
; 
2481         pDst
.OffsetY(dataDst
, 1); 
2482         pSrc
.OffsetY(dataSrc
, 1); 
2485     // and finally blit them back to the destination DC 
2486     if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) ) 
2488         wxLogLastError(_T("BitBlt")); 
2492 #endif // #ifdef wxHAVE_RAW_BITMAP