1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  21     #pragma implementation "dc.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  32     #include "wx/window.h" 
  35     #include "wx/dialog.h" 
  37     #include "wx/bitmap.h" 
  38     #include "wx/dcmemory.h" 
  43 #include "wx/sysopt.h" 
  44 #include "wx/dcprint.h" 
  45 #include "wx/module.h" 
  46 #include "wx/dynload.h" 
  47 #include "wx/rawbmp.h" 
  52 #include "wx/msw/private.h" // needs to be before #include <commdlg.h> 
  54 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__) 
  63 #define AC_SRC_ALPHA 1 
  66 /* Quaternary raster codes */ 
  68 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) 
  71 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
) 
  73 // --------------------------------------------------------------------------- 
  75 // --------------------------------------------------------------------------- 
  77 static const int VIEWPORT_EXTENT 
= 1000; 
  79 static const int MM_POINTS 
= 9; 
  80 static const int MM_METRIC 
= 10; 
  82 // usually this is defined in math.h 
  84     static const double M_PI 
= 3.14159265358979323846; 
  87 // ROPs which don't have standard names (see "Ternary Raster Operations" in the 
  88 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) 
  89 #define DSTCOPY 0x00AA0029      // a.k.a. NOP operation 
  91 // ---------------------------------------------------------------------------- 
  92 // macros for logical <-> device coords conversion 
  93 // ---------------------------------------------------------------------------- 
  96    We currently let Windows do all the translations itself so these macros are 
  97    not really needed (any more) but keep them to enhance readability of the 
  98    code by allowing to see where are the logical and where are the device 
 103 #define XLOG2DEV(x) (x) 
 104 #define YLOG2DEV(y) (y) 
 107 #define XDEV2LOG(x) (x) 
 108 #define YDEV2LOG(y) (y) 
 110 // --------------------------------------------------------------------------- 
 112 // --------------------------------------------------------------------------- 
 114 // convert degrees to radians 
 115 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
 117 // our (limited) AlphaBlend() replacement 
 119 wxAlphaBlend(wxDC
& dc
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
); 
 121 // ---------------------------------------------------------------------------- 
 123 // ---------------------------------------------------------------------------- 
 125 // instead of duplicating the same code which sets and then restores text 
 126 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, 
 127 // encapsulate this in a small helper class 
 129 // wxColourChanger: changes the text colours in the ctor if required and 
 130 //                  restores them in the dtor 
 131 class wxColourChanger
 
 134     wxColourChanger(wxDC
& dc
); 
 140     COLORREF m_colFgOld
, m_colBgOld
; 
 145 // this class saves the old stretch blit mode during its life time 
 146 class StretchBltModeChanger
 
 149     StretchBltModeChanger(HDC hdc
, int mode
) 
 152         m_modeOld 
= ::SetStretchBltMode(m_hdc
, mode
); 
 154             wxLogLastError(_T("SetStretchBltMode")); 
 157     ~StretchBltModeChanger() 
 159         if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) ) 
 160             wxLogLastError(_T("SetStretchBltMode")); 
 169 // =========================================================================== 
 171 // =========================================================================== 
 173 // ---------------------------------------------------------------------------- 
 175 // ---------------------------------------------------------------------------- 
 177 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
) 
 179     const wxBrush
& brush 
= dc
.GetBrush(); 
 180     if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE 
) 
 182         HDC hdc 
= GetHdcOf(dc
); 
 183         m_colFgOld 
= ::GetTextColor(hdc
); 
 184         m_colBgOld 
= ::GetBkColor(hdc
); 
 186         // note that Windows convention is opposite to wxWindows one, this is 
 187         // why text colour becomes the background one and vice versa 
 188         const wxColour
& colFg 
= dc
.GetTextForeground(); 
 191             ::SetBkColor(hdc
, colFg
.GetPixel()); 
 194         const wxColour
& colBg 
= dc
.GetTextBackground(); 
 197             ::SetTextColor(hdc
, colBg
.GetPixel()); 
 201                   dc
.GetBackgroundMode() == wxTRANSPARENT 
? TRANSPARENT
 
 204         // flag which telsl us to undo changes in the dtor 
 209         // nothing done, nothing to undo 
 214 wxColourChanger::~wxColourChanger() 
 218         // restore the colours we changed 
 219         HDC hdc 
= GetHdcOf(m_dc
); 
 221         ::SetBkMode(hdc
, TRANSPARENT
); 
 222         ::SetTextColor(hdc
, m_colFgOld
); 
 223         ::SetBkColor(hdc
, m_colBgOld
); 
 227 // --------------------------------------------------------------------------- 
 229 // --------------------------------------------------------------------------- 
 231 // Default constructor 
 242 #endif // wxUSE_PALETTE 
 252         SelectOldObjects(m_hDC
); 
 254         // if we own the HDC, we delete it, otherwise we just release it 
 258             ::DeleteDC(GetHdc()); 
 260         else // we don't own our HDC 
 264                 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc()); 
 268                 // Must have been a wxScreenDC 
 269                 ::ReleaseDC((HWND
) NULL
, GetHdc()); 
 275 // This will select current objects out of the DC, 
 276 // which is what you have to do before deleting the 
 278 void wxDC::SelectOldObjects(WXHDC dc
) 
 284             ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
); 
 286             if (m_selectedBitmap
.Ok()) 
 288                 m_selectedBitmap
.SetSelectedInto(NULL
); 
 295             ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
); 
 300             ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
); 
 305             ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
); 
 312             ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
); 
 315 #endif // wxUSE_PALETTE 
 318     m_brush 
= wxNullBrush
; 
 321     m_palette 
= wxNullPalette
; 
 322 #endif // wxUSE_PALETTE 
 324     m_backgroundBrush 
= wxNullBrush
; 
 325     m_selectedBitmap 
= wxNullBitmap
; 
 328 // --------------------------------------------------------------------------- 
 330 // --------------------------------------------------------------------------- 
 332 void wxDC::UpdateClipBox() 
 334 #ifdef __WXMICROWIN__ 
 335     if (!GetHDC()) return; 
 339     ::GetClipBox(GetHdc(), &rect
); 
 341     m_clipX1 
= (wxCoord
) XDEV2LOG(rect
.left
); 
 342     m_clipY1 
= (wxCoord
) YDEV2LOG(rect
.top
); 
 343     m_clipX2 
= (wxCoord
) XDEV2LOG(rect
.right
); 
 344     m_clipY2 
= (wxCoord
) YDEV2LOG(rect
.bottom
); 
 347 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion() 
 348 void wxDC::SetClippingHrgn(WXHRGN hrgn
) 
 350     wxCHECK_RET( hrgn
, wxT("invalid clipping region") ); 
 352 #ifdef __WXMICROWIN__ 
 353     if (!GetHdc()) return; 
 354 #endif // __WXMICROWIN__ 
 356     // note that we combine the new clipping region with the existing one: this 
 357     // is compatible with what the other ports do and is the documented 
 358     // behaviour now (starting with 2.3.3) 
 361     if ( !::GetClipBox(GetHdc(), &rectClip
) ) 
 364     HRGN hrgnDest 
= ::CreateRectRgn(0, 0, 0, 0); 
 365     HRGN hrgnClipOld 
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
, 
 366                                        rectClip
.right
, rectClip
.bottom
); 
 368     if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR 
) 
 370         ::SelectClipRgn(GetHdc(), hrgnDest
); 
 373     ::DeleteObject(hrgnClipOld
); 
 374     ::DeleteObject(hrgnDest
); 
 376     if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR 
) 
 378         wxLogLastError(_T("ExtSelectClipRgn")); 
 389 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) 
 391     // the region coords are always the device ones, so do the translation 
 394     // FIXME: possible +/-1 error here, to check! 
 395     HRGN hrgn 
= ::CreateRectRgn(LogicalToDeviceX(x
), 
 397                                 LogicalToDeviceX(x 
+ w
), 
 398                                 LogicalToDeviceY(y 
+ h
)); 
 401         wxLogLastError(_T("CreateRectRgn")); 
 405         SetClippingHrgn((WXHRGN
)hrgn
); 
 407         ::DeleteObject(hrgn
); 
 411 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
) 
 413     SetClippingHrgn(region
.GetHRGN()); 
 416 void wxDC::DestroyClippingRegion() 
 418 #ifdef __WXMICROWIN__ 
 419     if (!GetHDC()) return; 
 422     if (m_clipping 
&& m_hDC
) 
 424         // TODO: this should restore the previous clipping region, 
 425         //       so that OnPaint processing works correctly, and the update 
 426         //       clipping region doesn't get destroyed after the first 
 427         //       DestroyClippingRegion. 
 428         HRGN rgn 
= CreateRectRgn(0, 0, 32000, 32000); 
 429         ::SelectClipRgn(GetHdc(), rgn
); 
 436 // --------------------------------------------------------------------------- 
 437 // query capabilities 
 438 // --------------------------------------------------------------------------- 
 440 bool wxDC::CanDrawBitmap() const 
 445 bool wxDC::CanGetTextExtent() const 
 447 #ifdef __WXMICROWIN__ 
 448     // TODO Extend MicroWindows' GetDeviceCaps function 
 451     // What sort of display is it? 
 452     int technology 
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
); 
 454     return (technology 
== DT_RASDISPLAY
) || (technology 
== DT_RASPRINTER
); 
 458 int wxDC::GetDepth() const 
 460 #ifdef __WXMICROWIN__ 
 461     if (!GetHDC()) return 16; 
 464     return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
); 
 467 // --------------------------------------------------------------------------- 
 469 // --------------------------------------------------------------------------- 
 473 #ifdef __WXMICROWIN__ 
 474     if (!GetHDC()) return; 
 480         GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
); 
 484         // No, I think we should simply ignore this if printing on e.g. 
 486         // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); 
 487         if (!m_selectedBitmap
.Ok()) 
 490         rect
.left 
= 0; rect
.top 
= 0; 
 491         rect
.right 
= m_selectedBitmap
.GetWidth(); 
 492         rect
.bottom 
= m_selectedBitmap
.GetHeight(); 
 495     (void) ::SetMapMode(GetHdc(), MM_TEXT
); 
 497     DWORD colour 
= ::GetBkColor(GetHdc()); 
 498     HBRUSH brush 
= ::CreateSolidBrush(colour
); 
 499     ::FillRect(GetHdc(), &rect
, brush
); 
 500     ::DeleteObject(brush
); 
 502     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
 503         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
 505     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
 506     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
 507     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
 508     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
 509     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
 512 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
) 
 514 #ifdef __WXMICROWIN__ 
 515     if (!GetHDC()) return FALSE
; 
 518     bool success 
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
 520                          style 
== wxFLOOD_SURFACE 
? FLOODFILLSURFACE
 
 521                                                   : FLOODFILLBORDER
) ) ; 
 524         // quoting from the MSDN docs: 
 526         //      Following are some of the reasons this function might fail: 
 528         //      * The filling could not be completed. 
 529         //      * The specified point has the boundary color specified by the 
 530         //        crColor parameter (if FLOODFILLBORDER was requested). 
 531         //      * The specified point does not have the color specified by 
 532         //        crColor (if FLOODFILLSURFACE was requested) 
 533         //      * The point is outside the clipping region that is, it is not 
 534         //        visible on the device. 
 536         wxLogLastError(wxT("ExtFloodFill")); 
 539     CalcBoundingBox(x
, y
); 
 544 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour 
*col
) const 
 546 #ifdef __WXMICROWIN__ 
 547     if (!GetHDC()) return FALSE
; 
 550     wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") ); 
 552     // get the color of the pixel 
 553     COLORREF pixelcolor 
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)); 
 555     wxRGBToColour(*col
, pixelcolor
); 
 560 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
) 
 562 #ifdef __WXMICROWIN__ 
 563     if (!GetHDC()) return; 
 566     wxCoord x1 
= x
-VIEWPORT_EXTENT
; 
 567     wxCoord y1 
= y
-VIEWPORT_EXTENT
; 
 568     wxCoord x2 
= x
+VIEWPORT_EXTENT
; 
 569     wxCoord y2 
= y
+VIEWPORT_EXTENT
; 
 571     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
); 
 572     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
)); 
 574     (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
); 
 575     (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
)); 
 577     CalcBoundingBox(x1
, y1
); 
 578     CalcBoundingBox(x2
, y2
); 
 581 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
) 
 583 #ifdef __WXMICROWIN__ 
 584     if (!GetHDC()) return; 
 587     (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
); 
 588     (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 590     CalcBoundingBox(x1
, y1
); 
 591     CalcBoundingBox(x2
, y2
); 
 594 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1) 
 595 // and ending at (x2, y2) 
 596 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
, 
 597                      wxCoord x2
, wxCoord y2
, 
 598                      wxCoord xc
, wxCoord yc
) 
 600 #ifdef __WXMICROWIN__ 
 601     if (!GetHDC()) return; 
 604     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 608     double radius 
= (double)sqrt(dx
*dx
+dy
*dy
); 
 609     wxCoord r 
= (wxCoord
)radius
; 
 611     // treat the special case of full circle separately 
 612     if ( x1 
== x2 
&& y1 
== y2 
) 
 614         DrawEllipse(xc 
- r
, yc 
- r
, 2*r
, 2*r
); 
 618     wxCoord xx1 
= XLOG2DEV(x1
); 
 619     wxCoord yy1 
= YLOG2DEV(y1
); 
 620     wxCoord xx2 
= XLOG2DEV(x2
); 
 621     wxCoord yy2 
= YLOG2DEV(y2
); 
 622     wxCoord xxc 
= XLOG2DEV(xc
); 
 623     wxCoord yyc 
= YLOG2DEV(yc
); 
 624     wxCoord ray 
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))); 
 626     wxCoord xxx1 
= (wxCoord
) (xxc
-ray
); 
 627     wxCoord yyy1 
= (wxCoord
) (yyc
-ray
); 
 628     wxCoord xxx2 
= (wxCoord
) (xxc
+ray
); 
 629     wxCoord yyy2 
= (wxCoord
) (yyc
+ray
); 
 631     if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT 
) 
 633         // Have to add 1 to bottom-right corner of rectangle 
 634         // to make semi-circles look right (crooked line otherwise). 
 635         // Unfortunately this is not a reliable method, depends 
 636         // on the size of shape. 
 637         // TODO: figure out why this happens! 
 638         Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
); 
 642         Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
); 
 645     CalcBoundingBox(xc 
- r
, yc 
- r
); 
 646     CalcBoundingBox(xc 
+ r
, yc 
+ r
); 
 649 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, 
 650                            wxCoord width
, wxCoord height
) 
 652 #ifdef __WXMICROWIN__ 
 653     if (!GetHDC()) return; 
 656     wxCoord x2 
= x1 
+ width
, 
 659 #if defined(__WIN32__) && !defined(__SC__) && !defined(__WXMICROWIN__) 
 666     DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
); 
 668     // In WIN16, draw a cross 
 669     HPEN blackPen 
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0)); 
 670     HPEN whiteBrush 
= (HPEN
)::GetStockObject(WHITE_BRUSH
); 
 671     HPEN hPenOld 
= (HPEN
)::SelectObject(GetHdc(), blackPen
); 
 672     HPEN hBrushOld 
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
); 
 673     ::SetROP2(GetHdc(), R2_COPYPEN
); 
 674     Rectangle(GetHdc(), x1
, y1
, x2
, y2
); 
 675     MoveToEx(GetHdc(), x1
, y1
, NULL
); 
 676     LineTo(GetHdc(), x2
, y2
); 
 677     MoveToEx(GetHdc(), x2
, y1
, NULL
); 
 678     LineTo(GetHdc(), x1
, y2
); 
 679     ::SelectObject(GetHdc(), hPenOld
); 
 680     ::SelectObject(GetHdc(), hBrushOld
); 
 681     ::DeleteObject(blackPen
); 
 684     CalcBoundingBox(x1
, y1
); 
 685     CalcBoundingBox(x2
, y2
); 
 688 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
) 
 690 #ifdef __WXMICROWIN__ 
 691     if (!GetHDC()) return; 
 694     COLORREF color 
= 0x00ffffff; 
 697         color 
= m_pen
.GetColour().GetPixel(); 
 700     SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
); 
 702     CalcBoundingBox(x
, y
); 
 705 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
) 
 707 #ifdef __WXMICROWIN__ 
 708     if (!GetHDC()) return; 
 711     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 713     // Do things less efficiently if we have offsets 
 714     if (xoffset 
!= 0 || yoffset 
!= 0) 
 716         POINT 
*cpoints 
= new POINT
[n
]; 
 718         for (i 
= 0; i 
< n
; i
++) 
 720             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 721             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 723             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 725         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 726         (void)Polygon(GetHdc(), cpoints
, n
); 
 727         SetPolyFillMode(GetHdc(),prev
); 
 733         for (i 
= 0; i 
< n
; i
++) 
 734             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 736         int prev 
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
); 
 737         (void)Polygon(GetHdc(), (POINT
*) points
, n
); 
 738         SetPolyFillMode(GetHdc(),prev
); 
 742 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
) 
 744 #ifdef __WXMICROWIN__ 
 745     if (!GetHDC()) return; 
 748     // Do things less efficiently if we have offsets 
 749     if (xoffset 
!= 0 || yoffset 
!= 0) 
 751         POINT 
*cpoints 
= new POINT
[n
]; 
 753         for (i 
= 0; i 
< n
; i
++) 
 755             cpoints
[i
].x 
= (int)(points
[i
].x 
+ xoffset
); 
 756             cpoints
[i
].y 
= (int)(points
[i
].y 
+ yoffset
); 
 758             CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
); 
 760         (void)Polyline(GetHdc(), cpoints
, n
); 
 766         for (i 
= 0; i 
< n
; i
++) 
 767             CalcBoundingBox(points
[i
].x
, points
[i
].y
); 
 769         (void)Polyline(GetHdc(), (POINT
*) points
, n
); 
 773 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 775 #ifdef __WXMICROWIN__ 
 776     if (!GetHDC()) return; 
 779     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 781     wxCoord x2 
= x 
+ width
; 
 782     wxCoord y2 
= y 
+ height
; 
 784     if ((m_logicalFunction 
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
)) 
 787         rect
.left 
= XLOG2DEV(x
); 
 788         rect
.top 
= YLOG2DEV(y
); 
 789         rect
.right 
= XLOG2DEV(x2
); 
 790         rect
.bottom 
= YLOG2DEV(y2
); 
 791         (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() ); 
 795         // Windows draws the filled rectangles without outline (i.e. drawn with a 
 796         // transparent pen) one pixel smaller in both directions and we want them 
 797         // to have the same size regardless of which pen is used - adjust 
 799         // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. 
 800         if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 806         (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 810     CalcBoundingBox(x
, y
); 
 811     CalcBoundingBox(x2
, y2
); 
 814 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
) 
 816 #ifdef __WXMICROWIN__ 
 817     if (!GetHDC()) return; 
 820     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 822     // Now, a negative radius value is interpreted to mean 
 823     // 'the proportion of the smallest X or Y dimension' 
 827         double smallest 
= 0.0; 
 832         radius 
= (- radius 
* smallest
); 
 835     wxCoord x2 
= (x
+width
); 
 836     wxCoord y2 
= (y
+height
); 
 838     // Windows draws the filled rectangles without outline (i.e. drawn with a 
 839     // transparent pen) one pixel smaller in both directions and we want them 
 840     // to have the same size regardless of which pen is used - adjust 
 841     if ( m_pen
.GetStyle() == wxTRANSPARENT 
) 
 847     (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), 
 848         YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
))); 
 850     CalcBoundingBox(x
, y
); 
 851     CalcBoundingBox(x2
, y2
); 
 854 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
) 
 856 #ifdef __WXMICROWIN__ 
 857     if (!GetHDC()) return; 
 860     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 862     wxCoord x2 
= (x
+width
); 
 863     wxCoord y2 
= (y
+height
); 
 865     (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
)); 
 867     CalcBoundingBox(x
, y
); 
 868     CalcBoundingBox(x2
, y2
); 
 871 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows 
 872 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
) 
 874 #ifdef __WXMICROWIN__ 
 875     if (!GetHDC()) return; 
 878     wxColourChanger 
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling 
 883     int rx1 
= XLOG2DEV(x
+w
/2); 
 884     int ry1 
= YLOG2DEV(y
+h
/2); 
 891     rx1 
+= (int)(100.0 * abs(w
) * cos(sa
)); 
 892     ry1 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(sa
)); 
 893     rx2 
+= (int)(100.0 * abs(w
) * cos(ea
)); 
 894     ry2 
-= (int)(100.0 * abs(h
) * m_signY 
* sin(ea
)); 
 896     // draw pie with NULL_PEN first and then outline otherwise a line is 
 897     // drawn from the start and end points to the centre 
 898     HPEN hpenOld 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
)); 
 901         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1, 
 906         (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
), 
 907                   rx1
, ry1
-1, rx2
, ry2
-1); 
 910     ::SelectObject(GetHdc(), hpenOld
); 
 912     (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
), 
 915     CalcBoundingBox(x
, y
); 
 916     CalcBoundingBox(x2
, y2
); 
 919 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
) 
 921 #ifdef __WXMICROWIN__ 
 922     if (!GetHDC()) return; 
 925     wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") ); 
 928     ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
); 
 930     ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
)); 
 933     CalcBoundingBox(x
, y
); 
 934     CalcBoundingBox(x 
+ icon
.GetWidth(), y 
+ icon
.GetHeight()); 
 937 void wxDC::DoDrawBitmap( const wxBitmap 
&bmp
, wxCoord x
, wxCoord y
, bool useMask 
) 
 939 #ifdef __WXMICROWIN__ 
 940     if (!GetHDC()) return; 
 943     wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") ); 
 945     int width 
= bmp
.GetWidth(), 
 946         height 
= bmp
.GetHeight(); 
 948     HBITMAP hbmpMask 
= 0; 
 952 #endif // wxUSE_PALETTE 
 954     // do we have AlphaBlend() and company in the headers? 
 956     if ( bmp
.HasAlpha() ) 
 958         // yes, now try to see if we have it during run-time 
 960         typedef BOOL (WINAPI 
*AlphaBlend_t
)(HDC
,int,int,int,int, 
 964         // bitmaps can be drawn only from GUI thread so there is no need to 
 965         // protect this static variable from multiple threads 
 966         static bool s_triedToLoad 
= FALSE
; 
 967         static AlphaBlend_t pfnAlphaBlend 
= NULL
; 
 968         if ( !s_triedToLoad 
) 
 970             s_triedToLoad 
= TRUE
; 
 972             // don't give errors about the DLL being unavailable, we're 
 973             // prepared to handle this 
 976             wxDynamicLibrary 
dll(_T("msimg32.dll")); 
 977             if ( dll
.IsLoaded() ) 
 979                 pfnAlphaBlend 
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend")); 
 982                     // we must keep the DLL loaded if we want to be able to 
 983                     // call AlphaBlend() so just never unload it at all, not a 
 993             SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmp
)); 
 996             bf
.BlendOp 
= AC_SRC_OVER
; 
 998             bf
.SourceConstantAlpha 
= 0xff; 
 999             bf
.AlphaFormat 
= AC_SRC_ALPHA
; 
1001             if ( !pfnAlphaBlend(GetHdc(), x
, y
, width
, height
, 
1002                                 hdcMem
, 0, 0, width
, height
, 
1005                 wxLogLastError(_T("AlphaBlend")); 
1008         else // use our own (probably much slower) implementation 
1010             wxAlphaBlend(*this, x
, y
, width
, height
, bmp
); 
1015 #endif // defined(AC_SRC_OVER) 
1019         wxMask 
*mask 
= bmp
.GetMask(); 
1021             hbmpMask 
= (HBITMAP
)mask
->GetMaskBitmap(); 
1025             // don't give assert here because this would break existing 
1026             // programs - just silently ignore useMask parameter 
1033         // use MaskBlt() with ROP which doesn't do anything to dst in the mask 
1035         // On some systems, MaskBlt succeeds yet is much much slower 
1036         // than the wxWindows fall-back implementation. So we need 
1037         // to be able to switch this on and off at runtime. 
1039 #if wxUSE_SYSTEM_OPTIONS 
1040         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1044             HDC hdcMem 
= ::CreateCompatibleDC(GetHdc()); 
1045             HGDIOBJ hOldBitmap 
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
)); 
1047             wxPalette 
*pal 
= bmp
.GetPalette(); 
1048             if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1050                 oldPal 
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
); 
1051                 ::RealizePalette(hdcMem
); 
1053 #endif // wxUSE_PALETTE 
1055             ok 
= ::MaskBlt(cdc
, x
, y
, width
, height
, 
1058                             MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0; 
1062                 ::SelectPalette(hdcMem
, oldPal
, FALSE
); 
1063 #endif // wxUSE_PALETTE 
1065             ::SelectObject(hdcMem
, hOldBitmap
); 
1072             // Rather than reproduce wxDC::Blit, let's do it at the wxWin API 
1075             memDC
.SelectObject(bmp
); 
1077             Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
); 
1079             memDC
.SelectObject(wxNullBitmap
); 
1082     else // no mask, just use BitBlt() 
1085         HDC memdc 
= ::CreateCompatibleDC( cdc 
); 
1086         HBITMAP hbitmap 
= (HBITMAP
) bmp
.GetHBITMAP( ); 
1088         wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") ); 
1090         COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1091         COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1092         if (m_textForegroundColour
.Ok()) 
1094             ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1096         if (m_textBackgroundColour
.Ok()) 
1098             ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1102         wxPalette 
*pal 
= bmp
.GetPalette(); 
1103         if ( pal 
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 ) 
1105             oldPal 
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
); 
1106             ::RealizePalette(memdc
); 
1108 #endif // wxUSE_PALETTE 
1110         HGDIOBJ hOldBitmap 
= ::SelectObject( memdc
, hbitmap 
); 
1111         ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
); 
1115             ::SelectPalette(memdc
, oldPal
, FALSE
); 
1116 #endif // wxUSE_PALETTE 
1118         ::SelectObject( memdc
, hOldBitmap 
); 
1119         ::DeleteDC( memdc 
); 
1121         ::SetTextColor(GetHdc(), old_textground
); 
1122         ::SetBkColor(GetHdc(), old_background
); 
1126 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1128 #ifdef __WXMICROWIN__ 
1129     if (!GetHDC()) return; 
1132     DrawAnyText(text
, x
, y
); 
1134     // update the bounding box 
1135     CalcBoundingBox(x
, y
); 
1138     GetTextExtent(text
, &w
, &h
); 
1139     CalcBoundingBox(x 
+ w
, y 
+ h
); 
1142 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
) 
1144 #ifdef __WXMICROWIN__ 
1145     if (!GetHDC()) return; 
1148     // prepare for drawing the text 
1149     if ( m_textForegroundColour
.Ok() ) 
1150         SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel()); 
1152     DWORD old_background 
= 0; 
1153     if ( m_textBackgroundColour
.Ok() ) 
1155         old_background 
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1158     SetBkMode(GetHdc(), m_backgroundMode 
== wxTRANSPARENT 
? TRANSPARENT
 
1161     if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 
1162                    text
.c_str(), text
.length()) == 0 ) 
1164         wxLogLastError(wxT("TextOut")); 
1167     // restore the old parameters (text foreground colour may be left because 
1168     // it never is set to anything else, but background should remain 
1169     // transparent even if we just drew an opaque string) 
1170     if ( m_textBackgroundColour
.Ok() ) 
1171         (void)SetBkColor(GetHdc(), old_background
); 
1173     SetBkMode(GetHdc(), TRANSPARENT
); 
1176 void wxDC::DoDrawRotatedText(const wxString
& text
, 
1177                              wxCoord x
, wxCoord y
, 
1180 #ifdef __WXMICROWIN__ 
1181     if (!GetHDC()) return; 
1184     // we test that we have some font because otherwise we should still use the 
1185     // "else" part below to avoid that DrawRotatedText(angle = 180) and 
1186     // DrawRotatedText(angle = 0) use different fonts (we can't use the default 
1187     // font for drawing rotated fonts unfortunately) 
1188     if ( (angle 
== 0.0) && m_font
.Ok() ) 
1190         DoDrawText(text
, x
, y
); 
1192 #ifndef __WXMICROWIN__ 
1195         // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) 
1196         //     because it's not TrueType and so can't have non zero 
1197         //     orientation/escapement under Win9x 
1198         wxFont font 
= m_font
.Ok() ? m_font 
: *wxSWISS_FONT
; 
1199         HFONT hfont 
= (HFONT
)font
.GetResourceHandle(); 
1201         if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 ) 
1203             wxLogLastError(wxT("GetObject(hfont)")); 
1206         // GDI wants the angle in tenth of degree 
1207         long angle10 
= (long)(angle 
* 10); 
1208         lf
.lfEscapement 
= angle10
; 
1209         lf
. lfOrientation 
= angle10
; 
1211         hfont 
= ::CreateFontIndirect(&lf
); 
1214             wxLogLastError(wxT("CreateFont")); 
1218             HFONT hfontOld 
= (HFONT
)::SelectObject(GetHdc(), hfont
); 
1220             DrawAnyText(text
, x
, y
); 
1222             (void)::SelectObject(GetHdc(), hfontOld
); 
1223             (void)::DeleteObject(hfont
); 
1226         // call the bounding box by adding all four vertices of the rectangle 
1227         // containing the text to it (simpler and probably not slower than 
1228         // determining which of them is really topmost/leftmost/...) 
1230         GetTextExtent(text
, &w
, &h
); 
1232         double rad 
= DegToRad(angle
); 
1234         // "upper left" and "upper right" 
1235         CalcBoundingBox(x
, y
); 
1236         CalcBoundingBox(x 
+ wxCoord(w
*cos(rad
)), y 
- wxCoord(h
*sin(rad
))); 
1238         // "bottom left" and "bottom right" 
1239         x 
+= (wxCoord
)(h
*sin(rad
)); 
1240         y 
+= (wxCoord
)(h
*cos(rad
)); 
1241         CalcBoundingBox(x
, y
); 
1242         CalcBoundingBox(x 
+ wxCoord(h
*sin(rad
)), y 
+ wxCoord(h
*cos(rad
))); 
1247 // --------------------------------------------------------------------------- 
1249 // --------------------------------------------------------------------------- 
1253 void wxDC::DoSelectPalette(bool realize
) 
1255 #ifdef __WXMICROWIN__ 
1256     if (!GetHDC()) return; 
1259     // Set the old object temporarily, in case the assignment deletes an object 
1260     // that's not yet selected out. 
1263         ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
); 
1267     if ( m_palette
.Ok() ) 
1269         HPALETTE oldPal 
= ::SelectPalette(GetHdc(), 
1270                                           GetHpaletteOf(m_palette
), 
1273             m_oldPalette 
= (WXHPALETTE
) oldPal
; 
1276             ::RealizePalette(GetHdc()); 
1280 void wxDC::SetPalette(const wxPalette
& palette
) 
1284         m_palette 
= palette
; 
1285         DoSelectPalette(TRUE
); 
1289 void wxDC::InitializePalette() 
1291     if ( wxDisplayDepth() <= 8 ) 
1293         // look for any window or parent that has a custom palette. If any has 
1294         // one then we need to use it in drawing operations 
1295         wxWindow 
*win 
= m_canvas
->GetAncestorWithCustomPalette(); 
1297         m_hasCustomPalette 
= win 
&& win
->HasCustomPalette(); 
1298         if ( m_hasCustomPalette 
) 
1300             m_palette 
= win
->GetPalette(); 
1302             // turn on MSW translation for this palette 
1308 #endif // wxUSE_PALETTE 
1310 void wxDC::SetFont(const wxFont
& the_font
) 
1312 #ifdef __WXMICROWIN__ 
1313     if (!GetHDC()) return; 
1316     // Set the old object temporarily, in case the assignment deletes an object 
1317     // that's not yet selected out. 
1320         ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
1329             ::SelectObject(GetHdc(), (HFONT
) m_oldFont
); 
1333     if (m_font
.Ok() && m_font
.GetResourceHandle()) 
1335         HFONT f 
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle()); 
1336         if (f 
== (HFONT
) NULL
) 
1338             wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont.")); 
1341             m_oldFont 
= (WXHFONT
) f
; 
1345 void wxDC::SetPen(const wxPen
& pen
) 
1347 #ifdef __WXMICROWIN__ 
1348     if (!GetHDC()) return; 
1351     // Set the old object temporarily, in case the assignment deletes an object 
1352     // that's not yet selected out. 
1355         ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
1364             ::SelectObject(GetHdc(), (HPEN
) m_oldPen
); 
1370         if (m_pen
.GetResourceHandle()) 
1372             HPEN p 
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle()); 
1374                 m_oldPen 
= (WXHPEN
) p
; 
1379 void wxDC::SetBrush(const wxBrush
& brush
) 
1381 #ifdef __WXMICROWIN__ 
1382     if (!GetHDC()) return; 
1385     // Set the old object temporarily, in case the assignment deletes an object 
1386     // that's not yet selected out. 
1389         ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
1398             ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
); 
1404         // to make sure the brush is alligned with the logical coordinates 
1405         wxBitmap 
*stipple 
= m_brush
.GetStipple(); 
1406         if ( stipple 
&& stipple
->Ok() ) 
1409             ::SetBrushOrgEx(GetHdc(), 
1410                             m_deviceOriginX 
% stipple
->GetWidth(), 
1411                             m_deviceOriginY 
% stipple
->GetHeight(), 
1412                             NULL
);  // don't need previous brush origin 
1414             ::SetBrushOrg(GetHdc(), 
1415                             m_deviceOriginX 
% stipple
->GetWidth(), 
1416                             m_deviceOriginY 
% stipple
->GetHeight()); 
1420         if ( m_brush
.GetResourceHandle() ) 
1423             b 
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle()); 
1425                 m_oldBrush 
= (WXHBRUSH
) b
; 
1430 void wxDC::SetBackground(const wxBrush
& brush
) 
1432 #ifdef __WXMICROWIN__ 
1433     if (!GetHDC()) return; 
1436     m_backgroundBrush 
= brush
; 
1438     if (!m_backgroundBrush
.Ok()) 
1443         bool customColours 
= TRUE
; 
1444         // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to 
1445         // change background colours from the control-panel specified colours. 
1446         if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
)) 
1447             customColours 
= FALSE
; 
1451             if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
) 
1453                 m_canvas
->SetTransparent(TRUE
); 
1457                 // New behaviour, 10/2/99: setting the background brush of a DC 
1458                 // doesn't affect the window background colour. However, 
1459                 // I'm leaving in the transparency setting because it's needed by 
1460                 // various controls (e.g. wxStaticText) to determine whether to draw 
1461                 // transparently or not. TODO: maybe this should be a new function 
1462                 // wxWindow::SetTransparency(). Should that apply to the child itself, or the 
1464                 //        m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour()); 
1465                 m_canvas
->SetTransparent(FALSE
); 
1469     COLORREF new_color 
= m_backgroundBrush
.GetColour().GetPixel(); 
1471         (void)SetBkColor(GetHdc(), new_color
); 
1475 void wxDC::SetBackgroundMode(int mode
) 
1477 #ifdef __WXMICROWIN__ 
1478     if (!GetHDC()) return; 
1481     m_backgroundMode 
= mode
; 
1483     // SetBackgroundColour now only refers to text background 
1484     // and m_backgroundMode is used there 
1487 void wxDC::SetLogicalFunction(int function
) 
1489 #ifdef __WXMICROWIN__ 
1490     if (!GetHDC()) return; 
1493     m_logicalFunction 
= function
; 
1498 void wxDC::SetRop(WXHDC dc
) 
1500     if ( !dc 
|| m_logicalFunction 
< 0 ) 
1505     switch (m_logicalFunction
) 
1507         case wxCLEAR
:        rop 
= R2_BLACK
;         break; 
1508         case wxXOR
:          rop 
= R2_XORPEN
;        break; 
1509         case wxINVERT
:       rop 
= R2_NOT
;           break; 
1510         case wxOR_REVERSE
:   rop 
= R2_MERGEPENNOT
;   break; 
1511         case wxAND_REVERSE
:  rop 
= R2_MASKPENNOT
;    break; 
1512         case wxCOPY
:         rop 
= R2_COPYPEN
;       break; 
1513         case wxAND
:          rop 
= R2_MASKPEN
;       break; 
1514         case wxAND_INVERT
:   rop 
= R2_MASKNOTPEN
;    break; 
1515         case wxNO_OP
:        rop 
= R2_NOP
;           break; 
1516         case wxNOR
:          rop 
= R2_NOTMERGEPEN
;   break; 
1517         case wxEQUIV
:        rop 
= R2_NOTXORPEN
;     break; 
1518         case wxSRC_INVERT
:   rop 
= R2_NOTCOPYPEN
;    break; 
1519         case wxOR_INVERT
:    rop 
= R2_MERGENOTPEN
;   break; 
1520         case wxNAND
:         rop 
= R2_NOTMASKPEN
;    break; 
1521         case wxOR
:           rop 
= R2_MERGEPEN
;      break; 
1522         case wxSET
:          rop 
= R2_WHITE
;         break; 
1525            wxFAIL_MSG( wxT("unsupported logical function") ); 
1529     SetROP2(GetHdc(), rop
); 
1532 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
)) 
1534     // We might be previewing, so return TRUE to let it continue. 
1542 void wxDC::StartPage() 
1546 void wxDC::EndPage() 
1550 // --------------------------------------------------------------------------- 
1552 // --------------------------------------------------------------------------- 
1554 wxCoord 
wxDC::GetCharHeight() const 
1556 #ifdef __WXMICROWIN__ 
1557     if (!GetHDC()) return 0; 
1560     TEXTMETRIC lpTextMetric
; 
1562     GetTextMetrics(GetHdc(), &lpTextMetric
); 
1564     return lpTextMetric
.tmHeight
; 
1567 wxCoord 
wxDC::GetCharWidth() const 
1569 #ifdef __WXMICROWIN__ 
1570     if (!GetHDC()) return 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
); 
1628 void wxDC::SetMapMode(int mode
) 
1630 #ifdef __WXMICROWIN__ 
1631     if (!GetHDC()) return; 
1634     m_mappingMode 
= mode
; 
1636     if ( mode 
== wxMM_TEXT 
) 
1639         m_logicalScaleY 
= 1.0; 
1641     else // need to do some calculations 
1643         int pixel_width 
= ::GetDeviceCaps(GetHdc(), HORZRES
), 
1644             pixel_height 
= ::GetDeviceCaps(GetHdc(), VERTRES
), 
1645             mm_width 
= ::GetDeviceCaps(GetHdc(), HORZSIZE
), 
1646             mm_height 
= ::GetDeviceCaps(GetHdc(), VERTSIZE
); 
1648         if ( (mm_width 
== 0) || (mm_height 
== 0) ) 
1650             // we can't calculate mm2pixels[XY] then! 
1654         double mm2pixelsX 
= pixel_width 
/ mm_width
, 
1655                mm2pixelsY 
= pixel_height 
/ mm_height
; 
1660                 m_logicalScaleX 
= twips2mm 
* mm2pixelsX
; 
1661                 m_logicalScaleY 
= twips2mm 
* mm2pixelsY
; 
1665                 m_logicalScaleX 
= pt2mm 
* mm2pixelsX
; 
1666                 m_logicalScaleY 
= pt2mm 
* mm2pixelsY
; 
1670                 m_logicalScaleX 
= mm2pixelsX
; 
1671                 m_logicalScaleY 
= mm2pixelsY
; 
1675                 m_logicalScaleX 
= mm2pixelsX 
/ 10.0; 
1676                 m_logicalScaleY 
= mm2pixelsY 
/ 10.0; 
1680                 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); 
1684     // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of 
1685     //     cases we could do with MM_TEXT and in the remaining 0.9% with 
1686     //     MM_ISOTROPIC (TODO!) 
1687     ::SetMapMode(GetHdc(), MM_ANISOTROPIC
); 
1689     int width 
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
, 
1690         height 
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
; 
1692     ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
); 
1693     ::SetWindowExtEx(GetHdc(), width
, height
, NULL
); 
1695     ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
); 
1696     ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
); 
1699 void wxDC::SetUserScale(double x
, double y
) 
1701 #ifdef __WXMICROWIN__ 
1702     if (!GetHDC()) return; 
1705     if ( x 
== m_userScaleX 
&& y 
== m_userScaleY 
) 
1711     SetMapMode(m_mappingMode
); 
1714 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
) 
1716 #ifdef __WXMICROWIN__ 
1717     if (!GetHDC()) return; 
1720     int signX 
= xLeftRight 
? 1 : -1, 
1721         signY 
= yBottomUp 
? -1 : 1; 
1723     if ( signX 
!= m_signX 
|| signY 
!= m_signY 
) 
1728         SetMapMode(m_mappingMode
); 
1732 void wxDC::SetSystemScale(double x
, double y
) 
1734 #ifdef __WXMICROWIN__ 
1735     if (!GetHDC()) return; 
1738     if ( x 
== m_scaleX 
&& y 
== m_scaleY 
) 
1744     SetMapMode(m_mappingMode
); 
1747 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
) 
1749 #ifdef __WXMICROWIN__ 
1750     if (!GetHDC()) return; 
1753     if ( x 
== m_logicalOriginX 
&& y 
== m_logicalOriginY 
) 
1756     m_logicalOriginX 
= x
; 
1757     m_logicalOriginY 
= y
; 
1759     ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
); 
1762 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
) 
1764 #ifdef __WXMICROWIN__ 
1765     if (!GetHDC()) return; 
1768     if ( x 
== m_deviceOriginX 
&& y 
== m_deviceOriginY 
) 
1771     m_deviceOriginX 
= x
; 
1772     m_deviceOriginY 
= y
; 
1774     ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
); 
1777 // --------------------------------------------------------------------------- 
1778 // coordinates transformations 
1779 // --------------------------------------------------------------------------- 
1781 wxCoord 
wxDCBase::DeviceToLogicalX(wxCoord x
) const 
1783     return DeviceToLogicalXRel(x 
- m_deviceOriginX
)*m_signX 
+ m_logicalOriginX
; 
1786 wxCoord 
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const 
1788     // axis orientation is not taken into account for conversion of a distance 
1789     return (wxCoord
)(x 
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
)); 
1792 wxCoord 
wxDCBase::DeviceToLogicalY(wxCoord y
) const 
1794     return DeviceToLogicalYRel(y 
- m_deviceOriginY
)*m_signY 
+ m_logicalOriginY
; 
1797 wxCoord 
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const 
1799     // axis orientation is not taken into account for conversion of a distance 
1800     return (wxCoord
)( y 
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
)); 
1803 wxCoord 
wxDCBase::LogicalToDeviceX(wxCoord x
) const 
1805     return LogicalToDeviceXRel(x 
- m_logicalOriginX
)*m_signX 
+ m_deviceOriginX
; 
1808 wxCoord 
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const 
1810     // axis orientation is not taken into account for conversion of a distance 
1811     return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
); 
1814 wxCoord 
wxDCBase::LogicalToDeviceY(wxCoord y
) const 
1816     return LogicalToDeviceYRel(y 
- m_logicalOriginY
)*m_signY 
+ m_deviceOriginY
; 
1819 wxCoord 
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const 
1821     // axis orientation is not taken into account for conversion of a distance 
1822     return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
); 
1825 // --------------------------------------------------------------------------- 
1827 // --------------------------------------------------------------------------- 
1829 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, 
1830                   wxCoord width
, wxCoord height
, 
1831                   wxDC 
*source
, wxCoord xsrc
, wxCoord ysrc
, 
1832                   int rop
, bool useMask
, 
1833                   wxCoord xsrcMask
, wxCoord ysrcMask
) 
1835 #ifdef __WXMICROWIN__ 
1836     if (!GetHDC()) return FALSE
; 
1839     const wxBitmap
& bmpSrc 
= source
->m_selectedBitmap
; 
1841     wxMask 
*mask 
= NULL
; 
1844         mask 
= bmpSrc
.GetMask(); 
1846         if ( !(bmpSrc
.Ok() && mask 
&& mask
->GetMaskBitmap()) ) 
1848             // don't give assert here because this would break existing 
1849             // programs - just silently ignore useMask parameter 
1854     if (xsrcMask 
== -1 && ysrcMask 
== -1) 
1856         xsrcMask 
= xsrc
; ysrcMask 
= ysrc
; 
1859     COLORREF old_textground 
= ::GetTextColor(GetHdc()); 
1860     COLORREF old_background 
= ::GetBkColor(GetHdc()); 
1861     if (m_textForegroundColour
.Ok()) 
1863         ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() ); 
1865     if (m_textBackgroundColour
.Ok()) 
1867         ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() ); 
1870     DWORD dwRop 
= SRCCOPY
; 
1873         case wxXOR
:          dwRop 
= SRCINVERT
;        break; 
1874         case wxINVERT
:       dwRop 
= DSTINVERT
;        break; 
1875         case wxOR_REVERSE
:   dwRop 
= 0x00DD0228;       break; 
1876         case wxAND_REVERSE
:  dwRop 
= SRCERASE
;         break; 
1877         case wxCLEAR
:        dwRop 
= BLACKNESS
;        break; 
1878         case wxSET
:          dwRop 
= WHITENESS
;        break; 
1879         case wxOR_INVERT
:    dwRop 
= MERGEPAINT
;       break; 
1880         case wxAND
:          dwRop 
= SRCAND
;           break; 
1881         case wxOR
:           dwRop 
= SRCPAINT
;         break; 
1882         case wxEQUIV
:        dwRop 
= 0x00990066;       break; 
1883         case wxNAND
:         dwRop 
= 0x007700E6;       break; 
1884         case wxAND_INVERT
:   dwRop 
= 0x00220326;       break; 
1885         case wxCOPY
:         dwRop 
= SRCCOPY
;          break; 
1886         case wxNO_OP
:        dwRop 
= DSTCOPY
;          break; 
1887         case wxSRC_INVERT
:   dwRop 
= NOTSRCCOPY
;       break; 
1888         case wxNOR
:          dwRop 
= NOTSRCCOPY
;       break; 
1890            wxFAIL_MSG( wxT("unsupported logical function") ); 
1894     bool success 
= FALSE
; 
1899         // we want the part of the image corresponding to the mask to be 
1900         // transparent, so use "DSTCOPY" ROP for the mask points (the usual 
1901         // meaning of fg and bg is inverted which corresponds to wxWin notion 
1902         // of the mask which is also contrary to the Windows one) 
1904         // On some systems, MaskBlt succeeds yet is much much slower 
1905         // than the wxWindows fall-back implementation. So we need 
1906         // to be able to switch this on and off at runtime. 
1907 #if wxUSE_SYSTEM_OPTIONS 
1908         if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) 
1914                             xdest
, ydest
, width
, height
, 
1917                             (HBITMAP
)mask
->GetMaskBitmap(), 
1919                             MAKEROP4(dwRop
, DSTCOPY
) 
1926             // Blit bitmap with mask 
1929             HBITMAP buffer_bmap 
; 
1931 #if wxUSE_DC_CACHEING 
1932             // create a temp buffer bitmap and DCs to access it and the mask 
1933             wxDCCacheEntry
* dcCacheEntry1 
= FindDCInCache(NULL
, source
->GetHDC()); 
1934             dc_mask 
= (HDC
) dcCacheEntry1
->m_dc
; 
1936             wxDCCacheEntry
* dcCacheEntry2 
= FindDCInCache(dcCacheEntry1
, GetHDC()); 
1937             dc_buffer 
= (HDC
) dcCacheEntry2
->m_dc
; 
1939             wxDCCacheEntry
* bitmapCacheEntry 
= FindBitmapInCache(GetHDC(), 
1942             buffer_bmap 
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
; 
1943 #else // !wxUSE_DC_CACHEING 
1944             // create a temp buffer bitmap and DCs to access it and the mask 
1945             dc_mask 
= ::CreateCompatibleDC(GetHdcOf(*source
)); 
1946             dc_buffer 
= ::CreateCompatibleDC(GetHdc()); 
1947             buffer_bmap 
= ::CreateCompatibleBitmap(GetHdc(), width
, height
); 
1948 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING 
1949             HGDIOBJ hOldMaskBitmap 
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap()); 
1950             HGDIOBJ hOldBufferBitmap 
= ::SelectObject(dc_buffer
, buffer_bmap
); 
1952             // copy dest to buffer 
1953             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1954                            GetHdc(), xdest
, ydest
, SRCCOPY
) ) 
1956                 wxLogLastError(wxT("BitBlt")); 
1959             // copy src to buffer using selected raster op 
1960             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1961                            GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) ) 
1963                 wxLogLastError(wxT("BitBlt")); 
1966             // set masked area in buffer to BLACK (pixel value 0) 
1967             COLORREF prevBkCol 
= ::SetBkColor(GetHdc(), RGB(255, 255, 255)); 
1968             COLORREF prevCol 
= ::SetTextColor(GetHdc(), RGB(0, 0, 0)); 
1969             if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
, 
1970                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
1972                 wxLogLastError(wxT("BitBlt")); 
1975             // set unmasked area in dest to BLACK 
1976             ::SetBkColor(GetHdc(), RGB(0, 0, 0)); 
1977             ::SetTextColor(GetHdc(), RGB(255, 255, 255)); 
1978             if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
, 
1979                            dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) ) 
1981                 wxLogLastError(wxT("BitBlt")); 
1983             ::SetBkColor(GetHdc(), prevBkCol
);   // restore colours to original values 
1984             ::SetTextColor(GetHdc(), prevCol
); 
1986             // OR buffer to dest 
1987             success 
= ::BitBlt(GetHdc(), xdest
, ydest
, 
1988                                (int)width
, (int)height
, 
1989                                dc_buffer
, 0, 0, SRCPAINT
) != 0; 
1992                 wxLogLastError(wxT("BitBlt")); 
1995             // tidy up temporary DCs and bitmap 
1996             ::SelectObject(dc_mask
, hOldMaskBitmap
); 
1997             ::SelectObject(dc_buffer
, hOldBufferBitmap
); 
1999 #if !wxUSE_DC_CACHEING 
2001                 ::DeleteDC(dc_mask
); 
2002                 ::DeleteDC(dc_buffer
); 
2003                 ::DeleteObject(buffer_bmap
); 
2008     else // no mask, just BitBlt() it 
2010         // if we already have a DIB, draw it using StretchDIBits(), otherwise 
2011         // use StretchBlt() if available and finally fall back to BitBlt() 
2012         const int caps 
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
); 
2013         if ( bmpSrc
.Ok() && (caps 
& RC_STRETCHDIB
) ) 
2018             if ( ::GetObject(GetHbitmapOf(bmpSrc
), 
2020                              &ds
) == sizeof(ds
) ) 
2022                 StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2024                 if ( ::StretchDIBits(GetHdc(), 
2030                                      (LPBITMAPINFO
)&ds
.dsBmih
, 
2033                                      ) == (int)GDI_ERROR 
) 
2035                     wxLogLastError(wxT("StretchDIBits")); 
2044         if ( !success 
&& (caps 
& RC_STRETCHBLT
) ) 
2046             StretchBltModeChanger 
changeMode(GetHdc(), COLORONCOLOR
); 
2051                         xdest
, ydest
, width
, height
, 
2053                         xsrc
, ysrc
, width
, height
, 
2057                 wxLogLastError(_T("StretchBlt")); 
2071                         (int)width
, (int)height
, 
2077                 wxLogLastError(_T("BitBlt")); 
2086     ::SetTextColor(GetHdc(), old_textground
); 
2087     ::SetBkColor(GetHdc(), old_background
); 
2092 void wxDC::DoGetSize(int *w
, int *h
) const 
2094 #ifdef __WXMICROWIN__ 
2095     if (!GetHDC()) return; 
2098     if ( w 
) *w 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2099     if ( h 
) *h 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2102 void wxDC::DoGetSizeMM(int *w
, int *h
) const 
2104 #ifdef __WXMICROWIN__ 
2105     if (!GetHDC()) return; 
2108     // if we implement it in terms of DoGetSize() instead of directly using the 
2109     // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it 
2110     // will also work for wxWindowDC and wxClientDC even though their size is 
2111     // not the same as the total size of the screen 
2112     int wPixels
, hPixels
; 
2113     DoGetSize(&wPixels
, &hPixels
); 
2117         int wTotal 
= ::GetDeviceCaps(GetHdc(), HORZRES
); 
2119         wxCHECK_RET( wTotal
, _T("0 width device?") ); 
2121         *w 
= (wPixels 
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
; 
2126         int hTotal 
= ::GetDeviceCaps(GetHdc(), VERTRES
); 
2128         wxCHECK_RET( hTotal
, _T("0 height device?") ); 
2130         *h 
= (hPixels 
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
; 
2134 wxSize 
wxDC::GetPPI() const 
2136 #ifdef __WXMICROWIN__ 
2137     if (!GetHDC()) return wxSize(); 
2140     int x 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
); 
2141     int y 
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
); 
2143     return wxSize(x
, y
); 
2146 // For use by wxWindows only, unless custom units are required. 
2147 void wxDC::SetLogicalScale(double x
, double y
) 
2149 #ifdef __WXMICROWIN__ 
2150     if (!GetHDC()) return; 
2153     m_logicalScaleX 
= x
; 
2154     m_logicalScaleY 
= y
; 
2157 // ---------------------------------------------------------------------------- 
2159 // ---------------------------------------------------------------------------- 
2161 #if wxUSE_DC_CACHEING 
2164  * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will 
2165  * improve it in due course, either using arrays, or simply storing pointers to one 
2166  * entry for the bitmap, and two for the DCs. -- JACS 
2169 wxList 
wxDC::sm_bitmapCache
; 
2170 wxList 
wxDC::sm_dcCache
; 
2172 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
) 
2181 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
) 
2190 wxDCCacheEntry::~wxDCCacheEntry() 
2193         ::DeleteObject((HBITMAP
) m_bitmap
); 
2195         ::DeleteDC((HDC
) m_dc
); 
2198 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
) 
2200     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2201     wxNode
* node 
= sm_bitmapCache
.GetFirst(); 
2204         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2206         if (entry
->m_depth 
== depth
) 
2208             if (entry
->m_width 
< w 
|| entry
->m_height 
< h
) 
2210                 ::DeleteObject((HBITMAP
) entry
->m_bitmap
); 
2211                 entry
->m_bitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2212                 if ( !entry
->m_bitmap
) 
2214                     wxLogLastError(wxT("CreateCompatibleBitmap")); 
2216                 entry
->m_width 
= w
; entry
->m_height 
= h
; 
2222         node 
= node
->GetNext(); 
2224     WXHBITMAP hBitmap 
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
); 
2227         wxLogLastError(wxT("CreateCompatibleBitmap")); 
2229     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
); 
2230     AddToBitmapCache(entry
); 
2234 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
) 
2236     int depth 
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
); 
2237     wxNode
* node 
= sm_dcCache
.GetFirst(); 
2240         wxDCCacheEntry
* entry 
= (wxDCCacheEntry
*) node
->GetData(); 
2242         // Don't return the same one as we already have 
2243         if (!notThis 
|| (notThis 
!= entry
)) 
2245             if (entry
->m_depth 
== depth
) 
2251         node 
= node
->GetNext(); 
2253     WXHDC hDC 
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
); 
2256         wxLogLastError(wxT("CreateCompatibleDC")); 
2258     wxDCCacheEntry
* entry 
= new wxDCCacheEntry(hDC
, depth
); 
2259     AddToDCCache(entry
); 
2263 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
) 
2265     sm_bitmapCache
.Append(entry
); 
2268 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
) 
2270     sm_dcCache
.Append(entry
); 
2273 void wxDC::ClearCache() 
2275     sm_dcCache
.DeleteContents(TRUE
); 
2277     sm_dcCache
.DeleteContents(FALSE
); 
2278     sm_bitmapCache
.DeleteContents(TRUE
); 
2279     sm_bitmapCache
.Clear(); 
2280     sm_bitmapCache
.DeleteContents(FALSE
); 
2283 // Clean up cache at app exit 
2284 class wxDCModule 
: public wxModule
 
2287     virtual bool OnInit() { return TRUE
; } 
2288     virtual void OnExit() { wxDC::ClearCache(); } 
2291     DECLARE_DYNAMIC_CLASS(wxDCModule
) 
2294 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
) 
2296 #endif // wxUSE_DC_CACHEING 
2298 // ---------------------------------------------------------------------------- 
2299 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable 
2300 // ---------------------------------------------------------------------------- 
2303 wxAlphaBlend(wxDC
& dc
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
) 
2305     // get the destination DC pixels 
2306     wxBitmap 
bmpDst(w
, h
, 32 /* force creating RGBA DIB */); 
2308     SelectInHDC 
select(hdcMem
, GetHbitmapOf(bmpDst
)); 
2310     if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, GetHdcOf(dc
), 0, 0, SRCCOPY
) ) 
2312         wxLogLastError(_T("BitBlt")); 
2315     // combine them with the source bitmap using alpha 
2316     wxAlphaPixelData 
dataDst(bmpDst
), 
2319     wxCHECK_RET( dataDst 
&& dataSrc
, 
2320                     _T("failed to get raw data in wxAlphaBlend") ); 
2322     wxAlphaPixelData::Iterator 
pDst(dataDst
), 
2325     for ( int y 
= 0; y 
< h
; y
++ ) 
2327         wxAlphaPixelData::Iterator pDstRowStart 
= pDst
, 
2328                                    pSrcRowStart 
= pSrc
; 
2330         for ( int x 
= 0; x 
< w
; x
++ ) 
2332             // note that source bitmap uses premultiplied alpha (as required by 
2333             // the real AlphaBlend) 
2334             const unsigned beta 
= 255 - pSrc
.Alpha(); 
2336             pDst
.Red() = pSrc
.Red() + (beta 
* pDst
.Red() + 127) / 255; 
2337             pDst
.Blue() = pSrc
.Blue() + (beta 
* pDst
.Blue() + 127) / 255; 
2338             pDst
.Green() = pSrc
.Green() + (beta 
* pDst
.Green() + 127) / 255; 
2344         pDst 
= pDstRowStart
; 
2345         pSrc 
= pSrcRowStart
; 
2346         pDst
.OffsetY(dataDst
, 1); 
2347         pSrc
.OffsetY(dataSrc
, 1); 
2350     // and finally blit them back to the destination DC 
2351     if ( !::BitBlt(GetHdcOf(dc
), xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) ) 
2353         wxLogLastError(_T("BitBlt"));