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-m_logicalOriginX)*m_signX+m_deviceOriginX)
118 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
119 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
120 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
122 #define XLOG2DEV(x) (x)
123 #define YLOG2DEV(y) (y)
124 #define XDEV2LOG(x) (x)
125 #define YDEV2LOG(y) (y)
128 // ---------------------------------------------------------------------------
130 // ---------------------------------------------------------------------------
132 // convert degrees to radians
133 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
135 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
137 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
138 // to pass it to this function but as we already have it at the point
139 // of call anyhow we do
141 // return true if we could draw the bitmap in one way or the other, false
143 static bool AlphaBlt(HDC hdcDst
,
144 int x
, int y
, int w
, int h
,
146 const wxBitmap
& bmpSrc
);
148 #ifdef wxHAVE_RAW_BITMAP
149 // our (limited) AlphaBlend() replacement
151 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
154 // ----------------------------------------------------------------------------
156 // ----------------------------------------------------------------------------
158 // instead of duplicating the same code which sets and then restores text
159 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
160 // encapsulate this in a small helper class
162 // wxColourChanger: changes the text colours in the ctor if required and
163 // restores them in the dtor
164 class wxColourChanger
167 wxColourChanger(wxDC
& dc
);
173 COLORREF m_colFgOld
, m_colBgOld
;
177 DECLARE_NO_COPY_CLASS(wxColourChanger
)
180 // this class saves the old stretch blit mode during its life time
181 class StretchBltModeChanger
184 StretchBltModeChanger(HDC hdc
, int mode
)
188 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
190 wxLogLastError(_T("SetStretchBltMode"));
194 ~StretchBltModeChanger()
197 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
198 wxLogLastError(_T("SetStretchBltMode"));
207 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
210 // ===========================================================================
212 // ===========================================================================
214 // ----------------------------------------------------------------------------
216 // ----------------------------------------------------------------------------
218 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
220 const wxBrush
& brush
= dc
.GetBrush();
221 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
223 HDC hdc
= GetHdcOf(dc
);
224 m_colFgOld
= ::GetTextColor(hdc
);
225 m_colBgOld
= ::GetBkColor(hdc
);
227 // note that Windows convention is opposite to wxWindows one, this is
228 // why text colour becomes the background one and vice versa
229 const wxColour
& colFg
= dc
.GetTextForeground();
232 ::SetBkColor(hdc
, colFg
.GetPixel());
235 const wxColour
& colBg
= dc
.GetTextBackground();
238 ::SetTextColor(hdc
, colBg
.GetPixel());
242 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
245 // flag which telsl us to undo changes in the dtor
250 // nothing done, nothing to undo
255 wxColourChanger::~wxColourChanger()
259 // restore the colours we changed
260 HDC hdc
= GetHdcOf(m_dc
);
262 ::SetBkMode(hdc
, TRANSPARENT
);
263 ::SetTextColor(hdc
, m_colFgOld
);
264 ::SetBkColor(hdc
, m_colBgOld
);
268 // ---------------------------------------------------------------------------
270 // ---------------------------------------------------------------------------
272 // Default constructor
283 #endif // wxUSE_PALETTE
293 SelectOldObjects(m_hDC
);
295 // if we own the HDC, we delete it, otherwise we just release it
299 ::DeleteDC(GetHdc());
301 else // we don't own our HDC
305 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
309 // Must have been a wxScreenDC
310 ::ReleaseDC((HWND
) NULL
, GetHdc());
316 // This will select current objects out of the DC,
317 // which is what you have to do before deleting the
319 void wxDC::SelectOldObjects(WXHDC dc
)
325 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
327 if (m_selectedBitmap
.Ok())
329 m_selectedBitmap
.SetSelectedInto(NULL
);
336 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
341 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
346 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
353 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
356 #endif // wxUSE_PALETTE
359 m_brush
= wxNullBrush
;
362 m_palette
= wxNullPalette
;
363 #endif // wxUSE_PALETTE
365 m_backgroundBrush
= wxNullBrush
;
366 m_selectedBitmap
= wxNullBitmap
;
369 // ---------------------------------------------------------------------------
371 // ---------------------------------------------------------------------------
373 void wxDC::UpdateClipBox()
378 ::GetClipBox(GetHdc(), &rect
);
380 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
381 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
382 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
383 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
386 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
387 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
389 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
393 // note that we combine the new clipping region with the existing one: this
394 // is compatible with what the other ports do and is the documented
395 // behaviour now (starting with 2.3.3)
396 #if defined(__WXWINCE__)
398 if ( !::GetClipBox(GetHdc(), &rectClip
) )
401 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
402 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
403 rectClip
.right
, rectClip
.bottom
);
405 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
407 ::SelectClipRgn(GetHdc(), hrgnDest
);
410 ::DeleteObject(hrgnClipOld
);
411 ::DeleteObject(hrgnDest
);
413 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
415 wxLogLastError(_T("ExtSelectClipRgn"));
419 #endif // WinCE/!WinCE
426 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
428 // the region coords are always the device ones, so do the translation
431 // FIXME: possible +/-1 error here, to check!
432 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
434 LogicalToDeviceX(x
+ w
),
435 LogicalToDeviceY(y
+ h
));
438 wxLogLastError(_T("CreateRectRgn"));
442 SetClippingHrgn((WXHRGN
)hrgn
);
444 ::DeleteObject(hrgn
);
448 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
450 SetClippingHrgn(region
.GetHRGN());
453 void wxDC::DestroyClippingRegion()
457 if (m_clipping
&& m_hDC
)
459 // TODO: this should restore the previous clipping region,
460 // so that OnPaint processing works correctly, and the update
461 // clipping region doesn't get destroyed after the first
462 // DestroyClippingRegion.
463 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
464 ::SelectClipRgn(GetHdc(), rgn
);
471 // ---------------------------------------------------------------------------
472 // query capabilities
473 // ---------------------------------------------------------------------------
475 bool wxDC::CanDrawBitmap() const
480 bool wxDC::CanGetTextExtent() const
482 #ifdef __WXMICROWIN__
483 // TODO Extend MicroWindows' GetDeviceCaps function
486 // What sort of display is it?
487 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
489 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
493 int wxDC::GetDepth() const
495 WXMICROWIN_CHECK_HDC_RET(16)
497 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
500 // ---------------------------------------------------------------------------
502 // ---------------------------------------------------------------------------
511 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
515 // No, I think we should simply ignore this if printing on e.g.
517 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
518 if (!m_selectedBitmap
.Ok())
521 rect
.left
= 0; rect
.top
= 0;
522 rect
.right
= m_selectedBitmap
.GetWidth();
523 rect
.bottom
= m_selectedBitmap
.GetHeight();
527 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
530 DWORD colour
= ::GetBkColor(GetHdc());
531 HBRUSH brush
= ::CreateSolidBrush(colour
);
532 ::FillRect(GetHdc(), &rect
, brush
);
533 ::DeleteObject(brush
);
535 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
536 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
539 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
541 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
542 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
543 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
544 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
548 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
554 WXMICROWIN_CHECK_HDC_RET(false)
556 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
558 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
559 : FLOODFILLBORDER
) ) ;
562 // quoting from the MSDN docs:
564 // Following are some of the reasons this function might fail:
566 // * The filling could not be completed.
567 // * The specified point has the boundary color specified by the
568 // crColor parameter (if FLOODFILLBORDER was requested).
569 // * The specified point does not have the color specified by
570 // crColor (if FLOODFILLSURFACE was requested)
571 // * The point is outside the clipping region that is, it is not
572 // visible on the device.
574 wxLogLastError(wxT("ExtFloodFill"));
577 CalcBoundingBox(x
, y
);
583 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
585 WXMICROWIN_CHECK_HDC_RET(false)
587 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
589 // get the color of the pixel
590 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
592 wxRGBToColour(*col
, pixelcolor
);
597 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
601 wxCoord x1
= x
-VIEWPORT_EXTENT
;
602 wxCoord y1
= y
-VIEWPORT_EXTENT
;
603 wxCoord x2
= x
+VIEWPORT_EXTENT
;
604 wxCoord y2
= y
+VIEWPORT_EXTENT
;
606 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
607 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
609 CalcBoundingBox(x1
, y1
);
610 CalcBoundingBox(x2
, y2
);
613 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
617 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
619 CalcBoundingBox(x1
, y1
);
620 CalcBoundingBox(x2
, y2
);
623 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
624 // and ending at (x2, y2)
625 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
626 wxCoord x2
, wxCoord y2
,
627 wxCoord xc
, wxCoord yc
)
630 // Slower emulation since WinCE doesn't support Pie and Arc
631 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
632 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
633 if( y1
>yc
) sa
= -sa
; // below center
634 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
635 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
640 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
644 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
645 wxCoord r
= (wxCoord
)radius
;
647 // treat the special case of full circle separately
648 if ( x1
== x2
&& y1
== y2
)
650 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
654 wxCoord xx1
= XLOG2DEV(x1
);
655 wxCoord yy1
= YLOG2DEV(y1
);
656 wxCoord xx2
= XLOG2DEV(x2
);
657 wxCoord yy2
= YLOG2DEV(y2
);
658 wxCoord xxc
= XLOG2DEV(xc
);
659 wxCoord yyc
= YLOG2DEV(yc
);
660 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
662 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
663 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
664 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
665 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
667 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
669 // Have to add 1 to bottom-right corner of rectangle
670 // to make semi-circles look right (crooked line otherwise).
671 // Unfortunately this is not a reliable method, depends
672 // on the size of shape.
673 // TODO: figure out why this happens!
674 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
678 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
681 CalcBoundingBox(xc
- r
, yc
- r
);
682 CalcBoundingBox(xc
+ r
, yc
+ r
);
686 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
687 wxCoord width
, wxCoord height
)
691 wxCoord x2
= x1
+ width
,
694 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
702 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
704 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
706 #else // Symantec-MicroWin
708 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
709 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
710 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
711 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
712 ::SetROP2(GetHdc(), R2_COPYPEN
);
713 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
714 MoveToEx(GetHdc(), x1
, y1
, NULL
);
715 LineTo(GetHdc(), x2
, y2
);
716 MoveToEx(GetHdc(), x2
, y1
, NULL
);
717 LineTo(GetHdc(), x1
, y2
);
718 ::SelectObject(GetHdc(), hPenOld
);
719 ::SelectObject(GetHdc(), hBrushOld
);
720 ::DeleteObject(blackPen
);
721 #endif // Win32/Symantec-MicroWin
723 CalcBoundingBox(x1
, y1
);
724 CalcBoundingBox(x2
, y2
);
727 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
731 COLORREF color
= 0x00ffffff;
734 color
= m_pen
.GetColour().GetPixel();
737 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
739 CalcBoundingBox(x
, y
);
742 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
746 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
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
);
761 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
763 (void)Polygon(GetHdc(), cpoints
, n
);
765 SetPolyFillMode(GetHdc(),prev
);
772 for (i
= 0; i
< n
; i
++)
773 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
776 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
778 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
780 SetPolyFillMode(GetHdc(),prev
);
786 wxDC::DoDrawPolyPolygon(int n
,
794 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
798 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
800 for (i
= cnt
= 0; i
< n
; i
++)
803 // Do things less efficiently if we have offsets
804 if (xoffset
!= 0 || yoffset
!= 0)
806 POINT
*cpoints
= new POINT
[cnt
];
807 for (i
= 0; i
< cnt
; i
++)
809 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
810 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
812 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
815 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
817 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
819 SetPolyFillMode(GetHdc(),prev
);
825 for (i
= 0; i
< cnt
; i
++)
826 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
829 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
831 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
833 SetPolyFillMode(GetHdc(),prev
);
840 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
844 // Do things less efficiently if we have offsets
845 if (xoffset
!= 0 || yoffset
!= 0)
847 POINT
*cpoints
= new POINT
[n
];
849 for (i
= 0; i
< n
; i
++)
851 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
852 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
854 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
856 (void)Polyline(GetHdc(), cpoints
, n
);
862 for (i
= 0; i
< n
; i
++)
863 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
865 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
869 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
873 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
875 wxCoord x2
= x
+ width
;
876 wxCoord y2
= y
+ height
;
878 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
881 rect
.left
= XLOG2DEV(x
);
882 rect
.top
= YLOG2DEV(y
);
883 rect
.right
= XLOG2DEV(x2
);
884 rect
.bottom
= YLOG2DEV(y2
);
885 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
889 // Windows draws the filled rectangles without outline (i.e. drawn with a
890 // transparent pen) one pixel smaller in both directions and we want them
891 // to have the same size regardless of which pen is used - adjust
893 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
894 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
900 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
904 CalcBoundingBox(x
, y
);
905 CalcBoundingBox(x2
, y2
);
908 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
912 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
914 // Now, a negative radius value is interpreted to mean
915 // 'the proportion of the smallest X or Y dimension'
919 double smallest
= (width
< height
) ? width
: height
;
920 radius
= (- radius
* smallest
);
923 wxCoord x2
= (x
+width
);
924 wxCoord y2
= (y
+height
);
926 // Windows draws the filled rectangles without outline (i.e. drawn with a
927 // transparent pen) one pixel smaller in both directions and we want them
928 // to have the same size regardless of which pen is used - adjust
929 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
935 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
936 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
938 CalcBoundingBox(x
, y
);
939 CalcBoundingBox(x2
, y2
);
942 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
946 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
948 wxCoord x2
= (x
+width
);
949 wxCoord y2
= (y
+height
);
951 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
953 CalcBoundingBox(x
, y
);
954 CalcBoundingBox(x2
, y2
);
957 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
958 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
961 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
966 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
971 int rx1
= XLOG2DEV(x
+w
/2);
972 int ry1
= YLOG2DEV(y
+h
/2);
979 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
980 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
981 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
982 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
984 // draw pie with NULL_PEN first and then outline otherwise a line is
985 // drawn from the start and end points to the centre
986 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
989 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
994 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
995 rx1
, ry1
-1, rx2
, ry2
-1);
998 ::SelectObject(GetHdc(), hpenOld
);
1000 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1001 rx1
, ry1
, rx2
, ry2
);
1003 CalcBoundingBox(x
, y
);
1004 CalcBoundingBox(x2
, y2
);
1008 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1010 WXMICROWIN_CHECK_HDC
1012 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1015 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1017 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1020 CalcBoundingBox(x
, y
);
1021 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1024 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1026 WXMICROWIN_CHECK_HDC
1028 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1030 int width
= bmp
.GetWidth(),
1031 height
= bmp
.GetHeight();
1033 HBITMAP hbmpMask
= 0;
1036 HPALETTE oldPal
= 0;
1037 #endif // wxUSE_PALETTE
1039 if ( bmp
.HasAlpha() )
1042 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1044 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1050 wxMask
*mask
= bmp
.GetMask();
1052 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1056 // don't give assert here because this would break existing
1057 // programs - just silently ignore useMask parameter
1064 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1066 // On some systems, MaskBlt succeeds yet is much much slower
1067 // than the wxWindows fall-back implementation. So we need
1068 // to be able to switch this on and off at runtime.
1070 #if wxUSE_SYSTEM_OPTIONS
1071 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1075 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1076 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1078 wxPalette
*pal
= bmp
.GetPalette();
1079 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1081 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1082 ::RealizePalette(hdcMem
);
1084 #endif // wxUSE_PALETTE
1086 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1089 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1093 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1094 #endif // wxUSE_PALETTE
1096 ::SelectObject(hdcMem
, hOldBitmap
);
1103 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1106 memDC
.SelectObject(bmp
);
1108 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1110 memDC
.SelectObject(wxNullBitmap
);
1113 else // no mask, just use BitBlt()
1116 HDC memdc
= ::CreateCompatibleDC( cdc
);
1117 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1119 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1121 COLORREF old_textground
= ::GetTextColor(GetHdc());
1122 COLORREF old_background
= ::GetBkColor(GetHdc());
1123 if (m_textForegroundColour
.Ok())
1125 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1127 if (m_textBackgroundColour
.Ok())
1129 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1133 wxPalette
*pal
= bmp
.GetPalette();
1134 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1136 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1137 ::RealizePalette(memdc
);
1139 #endif // wxUSE_PALETTE
1141 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1142 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1146 ::SelectPalette(memdc
, oldPal
, FALSE
);
1147 #endif // wxUSE_PALETTE
1149 ::SelectObject( memdc
, hOldBitmap
);
1150 ::DeleteDC( memdc
);
1152 ::SetTextColor(GetHdc(), old_textground
);
1153 ::SetBkColor(GetHdc(), old_background
);
1157 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1159 WXMICROWIN_CHECK_HDC
1161 DrawAnyText(text
, x
, y
);
1163 // update the bounding box
1164 CalcBoundingBox(x
, y
);
1167 GetTextExtent(text
, &w
, &h
);
1168 CalcBoundingBox(x
+ w
, y
+ h
);
1171 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1173 WXMICROWIN_CHECK_HDC
1175 // prepare for drawing the text
1176 if ( m_textForegroundColour
.Ok() )
1177 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1179 DWORD old_background
= 0;
1180 if ( m_textBackgroundColour
.Ok() )
1182 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1185 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1189 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1190 text
.c_str(), text
.length(), NULL
) == 0 )
1192 wxLogLastError(wxT("TextOut"));
1195 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1196 text
.c_str(), text
.length()) == 0 )
1198 wxLogLastError(wxT("TextOut"));
1202 // restore the old parameters (text foreground colour may be left because
1203 // it never is set to anything else, but background should remain
1204 // transparent even if we just drew an opaque string)
1205 if ( m_textBackgroundColour
.Ok() )
1206 (void)SetBkColor(GetHdc(), old_background
);
1208 SetBkMode(GetHdc(), TRANSPARENT
);
1211 void wxDC::DoDrawRotatedText(const wxString
& text
,
1212 wxCoord x
, wxCoord y
,
1215 WXMICROWIN_CHECK_HDC
1217 // we test that we have some font because otherwise we should still use the
1218 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1219 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1220 // font for drawing rotated fonts unfortunately)
1221 if ( (angle
== 0.0) && m_font
.Ok() )
1223 DoDrawText(text
, x
, y
);
1225 #ifndef __WXMICROWIN__
1228 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1229 // because it's not TrueType and so can't have non zero
1230 // orientation/escapement under Win9x
1231 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1232 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1234 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1236 wxLogLastError(wxT("GetObject(hfont)"));
1239 // GDI wants the angle in tenth of degree
1240 long angle10
= (long)(angle
* 10);
1241 lf
.lfEscapement
= angle10
;
1242 lf
. lfOrientation
= angle10
;
1244 hfont
= ::CreateFontIndirect(&lf
);
1247 wxLogLastError(wxT("CreateFont"));
1251 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1253 DrawAnyText(text
, x
, y
);
1255 (void)::SelectObject(GetHdc(), hfontOld
);
1256 (void)::DeleteObject(hfont
);
1259 // call the bounding box by adding all four vertices of the rectangle
1260 // containing the text to it (simpler and probably not slower than
1261 // determining which of them is really topmost/leftmost/...)
1263 GetTextExtent(text
, &w
, &h
);
1265 double rad
= DegToRad(angle
);
1267 // "upper left" and "upper right"
1268 CalcBoundingBox(x
, y
);
1269 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1271 // "bottom left" and "bottom right"
1272 x
+= (wxCoord
)(h
*sin(rad
));
1273 y
+= (wxCoord
)(h
*cos(rad
));
1274 CalcBoundingBox(x
, y
);
1275 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1280 // ---------------------------------------------------------------------------
1282 // ---------------------------------------------------------------------------
1286 void wxDC::DoSelectPalette(bool realize
)
1288 WXMICROWIN_CHECK_HDC
1290 // Set the old object temporarily, in case the assignment deletes an object
1291 // that's not yet selected out.
1294 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1298 if ( m_palette
.Ok() )
1300 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1301 GetHpaletteOf(m_palette
),
1304 m_oldPalette
= (WXHPALETTE
) oldPal
;
1307 ::RealizePalette(GetHdc());
1311 void wxDC::SetPalette(const wxPalette
& palette
)
1315 m_palette
= palette
;
1316 DoSelectPalette(true);
1320 void wxDC::InitializePalette()
1322 if ( wxDisplayDepth() <= 8 )
1324 // look for any window or parent that has a custom palette. If any has
1325 // one then we need to use it in drawing operations
1326 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1328 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1329 if ( m_hasCustomPalette
)
1331 m_palette
= win
->GetPalette();
1333 // turn on MSW translation for this palette
1339 #endif // wxUSE_PALETTE
1341 // SetFont/Pen/Brush() really ask to be implemented as a single template
1342 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1344 void wxDC::SetFont(const wxFont
& font
)
1346 WXMICROWIN_CHECK_HDC
1348 if ( font
== m_font
)
1353 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1354 if ( hfont
== HGDI_ERROR
)
1356 wxLogLastError(_T("SelectObject(font)"));
1361 m_oldFont
= (WXHPEN
)hfont
;
1366 else // invalid font, reset the current font
1370 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1372 wxLogLastError(_T("SelectObject(old font)"));
1378 m_font
= wxNullFont
;
1382 void wxDC::SetPen(const wxPen
& pen
)
1384 WXMICROWIN_CHECK_HDC
1391 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1392 if ( hpen
== HGDI_ERROR
)
1394 wxLogLastError(_T("SelectObject(pen)"));
1399 m_oldPen
= (WXHPEN
)hpen
;
1404 else // invalid pen, reset the current pen
1408 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1410 wxLogLastError(_T("SelectObject(old pen)"));
1420 void wxDC::SetBrush(const wxBrush
& brush
)
1422 WXMICROWIN_CHECK_HDC
1424 if ( brush
== m_brush
)
1429 // we must make sure the brush is aligned with the logical coordinates
1430 // before selecting it
1431 wxBitmap
*stipple
= brush
.GetStipple();
1432 if ( stipple
&& stipple
->Ok() )
1434 if ( !::SetBrushOrgEx
1437 m_deviceOriginX
% stipple
->GetWidth(),
1438 m_deviceOriginY
% stipple
->GetHeight(),
1439 NULL
// [out] previous brush origin
1442 wxLogLastError(_T("SetBrushOrgEx()"));
1446 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1447 if ( hbrush
== HGDI_ERROR
)
1449 wxLogLastError(_T("SelectObject(brush)"));
1454 m_oldBrush
= (WXHPEN
)hbrush
;
1459 else // invalid brush, reset the current brush
1463 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1465 wxLogLastError(_T("SelectObject(old brush)"));
1471 m_brush
= wxNullBrush
;
1475 void wxDC::SetBackground(const wxBrush
& brush
)
1477 WXMICROWIN_CHECK_HDC
1479 m_backgroundBrush
= brush
;
1481 if ( m_backgroundBrush
.Ok() )
1483 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1487 void wxDC::SetBackgroundMode(int mode
)
1489 WXMICROWIN_CHECK_HDC
1491 m_backgroundMode
= mode
;
1493 // SetBackgroundColour now only refers to text background
1494 // and m_backgroundMode is used there
1497 void wxDC::SetLogicalFunction(int function
)
1499 WXMICROWIN_CHECK_HDC
1501 m_logicalFunction
= function
;
1506 void wxDC::SetRop(WXHDC dc
)
1508 if ( !dc
|| m_logicalFunction
< 0 )
1513 switch (m_logicalFunction
)
1515 case wxCLEAR
: rop
= R2_BLACK
; break;
1516 case wxXOR
: rop
= R2_XORPEN
; break;
1517 case wxINVERT
: rop
= R2_NOT
; break;
1518 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1519 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1520 case wxCOPY
: rop
= R2_COPYPEN
; break;
1521 case wxAND
: rop
= R2_MASKPEN
; break;
1522 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1523 case wxNO_OP
: rop
= R2_NOP
; break;
1524 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1525 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1526 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1527 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1528 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1529 case wxOR
: rop
= R2_MERGEPEN
; break;
1530 case wxSET
: rop
= R2_WHITE
; break;
1533 wxFAIL_MSG( wxT("unsupported logical function") );
1537 SetROP2(GetHdc(), rop
);
1540 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1542 // We might be previewing, so return true to let it continue.
1550 void wxDC::StartPage()
1554 void wxDC::EndPage()
1558 // ---------------------------------------------------------------------------
1560 // ---------------------------------------------------------------------------
1562 wxCoord
wxDC::GetCharHeight() const
1564 WXMICROWIN_CHECK_HDC_RET(0)
1566 TEXTMETRIC lpTextMetric
;
1568 GetTextMetrics(GetHdc(), &lpTextMetric
);
1570 return lpTextMetric
.tmHeight
;
1573 wxCoord
wxDC::GetCharWidth() const
1575 WXMICROWIN_CHECK_HDC_RET(0)
1577 TEXTMETRIC lpTextMetric
;
1579 GetTextMetrics(GetHdc(), &lpTextMetric
);
1581 return lpTextMetric
.tmAveCharWidth
;
1584 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1585 wxCoord
*descent
, wxCoord
*externalLeading
,
1588 #ifdef __WXMICROWIN__
1593 if (descent
) *descent
= 0;
1594 if (externalLeading
) *externalLeading
= 0;
1597 #endif // __WXMICROWIN__
1602 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1604 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1606 else // don't change the font
1614 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1615 GetTextMetrics(GetHdc(), &tm
);
1622 *descent
= tm
.tmDescent
;
1623 if (externalLeading
)
1624 *externalLeading
= tm
.tmExternalLeading
;
1628 ::SelectObject(GetHdc(), hfontOld
);
1633 // Each element of the array will be the width of the string up to and
1634 // including the coresoponding character in text.
1636 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1638 static int maxLenText
= -1;
1639 static int maxWidth
= -1;
1642 int stlen
= text
.Length();
1644 if (maxLenText
== -1)
1646 // Win9x and WinNT+ have different limits
1647 int version
= wxGetOsVersion();
1648 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1649 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1653 widths
.Add(0, stlen
); // fill the array with zeros
1655 if (!::GetTextExtentExPoint(GetHdc(),
1656 text
.c_str(), // string to check
1657 wxMin(stlen
, maxLenText
),
1659 &fit
, // [out] count of chars
1661 &widths
[0], // array to fill
1665 wxLogLastError(wxT("GetTextExtentExPoint"));
1675 void wxDC::SetMapMode(int mode
)
1677 WXMICROWIN_CHECK_HDC
1679 m_mappingMode
= mode
;
1681 if ( mode
== wxMM_TEXT
)
1684 m_logicalScaleY
= 1.0;
1686 else // need to do some calculations
1688 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1689 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1690 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1691 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1693 if ( (mm_width
== 0) || (mm_height
== 0) )
1695 // we can't calculate mm2pixels[XY] then!
1699 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1700 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1705 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1706 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1710 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1711 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1715 m_logicalScaleX
= mm2pixelsX
;
1716 m_logicalScaleY
= mm2pixelsY
;
1720 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1721 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1725 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1729 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1730 // cases we could do with MM_TEXT and in the remaining 0.9% with
1731 // MM_ISOTROPIC (TODO!)
1733 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1735 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1736 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1738 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1739 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1741 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1742 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1746 void wxDC::SetUserScale(double x
, double y
)
1748 WXMICROWIN_CHECK_HDC
1751 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1757 SetMapMode(m_mappingMode
);
1761 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1763 WXMICROWIN_CHECK_HDC
1766 int signX
= xLeftRight
? 1 : -1,
1767 signY
= yBottomUp
? -1 : 1;
1769 if ( signX
!= m_signX
|| signY
!= m_signY
)
1774 SetMapMode(m_mappingMode
);
1779 void wxDC::SetSystemScale(double x
, double y
)
1781 WXMICROWIN_CHECK_HDC
1783 if ( x
== m_scaleX
&& y
== m_scaleY
)
1790 SetMapMode(m_mappingMode
);
1794 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1796 WXMICROWIN_CHECK_HDC
1798 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1801 m_logicalOriginX
= x
;
1802 m_logicalOriginY
= y
;
1805 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1809 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1811 WXMICROWIN_CHECK_HDC
1813 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1816 m_deviceOriginX
= x
;
1817 m_deviceOriginY
= y
;
1820 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1824 // ---------------------------------------------------------------------------
1825 // coordinates transformations
1826 // ---------------------------------------------------------------------------
1828 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1830 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1833 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1835 // axis orientation is not taken into account for conversion of a distance
1836 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1839 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1841 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1844 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1846 // axis orientation is not taken into account for conversion of a distance
1847 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1850 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1852 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1855 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1857 // axis orientation is not taken into account for conversion of a distance
1858 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1861 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1863 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1866 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1868 // axis orientation is not taken into account for conversion of a distance
1869 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1872 // ---------------------------------------------------------------------------
1874 // ---------------------------------------------------------------------------
1876 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1877 wxCoord width
, wxCoord height
,
1878 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1879 int rop
, bool useMask
,
1880 wxCoord xsrcMask
, wxCoord ysrcMask
)
1882 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1884 WXMICROWIN_CHECK_HDC_RET(false)
1886 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1887 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1889 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1890 GetHdcOf(*source
), bmpSrc
) )
1894 wxMask
*mask
= NULL
;
1897 mask
= bmpSrc
.GetMask();
1899 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1901 // don't give assert here because this would break existing
1902 // programs - just silently ignore useMask parameter
1907 if (xsrcMask
== -1 && ysrcMask
== -1)
1909 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1912 COLORREF old_textground
= ::GetTextColor(GetHdc());
1913 COLORREF old_background
= ::GetBkColor(GetHdc());
1914 if (m_textForegroundColour
.Ok())
1916 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1918 if (m_textBackgroundColour
.Ok())
1920 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1926 case wxXOR
: dwRop
= SRCINVERT
; break;
1927 case wxINVERT
: dwRop
= DSTINVERT
; break;
1928 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1929 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1930 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1931 case wxSET
: dwRop
= WHITENESS
; break;
1932 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1933 case wxAND
: dwRop
= SRCAND
; break;
1934 case wxOR
: dwRop
= SRCPAINT
; break;
1935 case wxEQUIV
: dwRop
= 0x00990066; break;
1936 case wxNAND
: dwRop
= 0x007700E6; break;
1937 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1938 case wxCOPY
: dwRop
= SRCCOPY
; break;
1939 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1940 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1941 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1943 wxFAIL_MSG( wxT("unsupported logical function") );
1947 bool success
= false;
1952 // we want the part of the image corresponding to the mask to be
1953 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1954 // meaning of fg and bg is inverted which corresponds to wxWin notion
1955 // of the mask which is also contrary to the Windows one)
1957 // On some systems, MaskBlt succeeds yet is much much slower
1958 // than the wxWindows fall-back implementation. So we need
1959 // to be able to switch this on and off at runtime.
1960 #if wxUSE_SYSTEM_OPTIONS
1961 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1967 xdest
, ydest
, width
, height
,
1970 (HBITMAP
)mask
->GetMaskBitmap(),
1972 MAKEROP4(dwRop
, DSTCOPY
)
1979 // Blit bitmap with mask
1982 HBITMAP buffer_bmap
;
1984 #if wxUSE_DC_CACHEING
1985 // create a temp buffer bitmap and DCs to access it and the mask
1986 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1987 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1989 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1990 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1992 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1995 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1996 #else // !wxUSE_DC_CACHEING
1997 // create a temp buffer bitmap and DCs to access it and the mask
1998 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1999 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2000 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2001 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2002 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2003 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2005 // copy dest to buffer
2006 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2007 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2009 wxLogLastError(wxT("BitBlt"));
2012 // copy src to buffer using selected raster op
2013 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2014 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2016 wxLogLastError(wxT("BitBlt"));
2019 // set masked area in buffer to BLACK (pixel value 0)
2020 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2021 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2022 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2023 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2025 wxLogLastError(wxT("BitBlt"));
2028 // set unmasked area in dest to BLACK
2029 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2030 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2031 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2032 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2034 wxLogLastError(wxT("BitBlt"));
2036 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2037 ::SetTextColor(GetHdc(), prevCol
);
2039 // OR buffer to dest
2040 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2041 (int)width
, (int)height
,
2042 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2045 wxLogLastError(wxT("BitBlt"));
2048 // tidy up temporary DCs and bitmap
2049 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2050 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2052 #if !wxUSE_DC_CACHEING
2054 ::DeleteDC(dc_mask
);
2055 ::DeleteDC(dc_buffer
);
2056 ::DeleteObject(buffer_bmap
);
2061 else // no mask, just BitBlt() it
2063 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2064 // use StretchBlt() if available and finally fall back to BitBlt()
2066 // FIXME: use appropriate WinCE functions
2068 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2069 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2074 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2076 &ds
) == sizeof(ds
) )
2078 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2080 // Figure out what co-ordinate system we're supposed to specify
2082 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2086 ysrc
= hDIB
- (ysrc
+ height
);
2089 if ( ::StretchDIBits(GetHdc(),
2095 (LPBITMAPINFO
)&ds
.dsBmih
,
2098 ) == (int)GDI_ERROR
)
2100 // On Win9x this API fails most (all?) of the time, so
2101 // logging it becomes quite distracting. Since it falls
2102 // back to the code below this is not really serious, so
2104 //wxLogLastError(wxT("StretchDIBits"));
2113 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2118 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2124 xdest
, ydest
, width
, height
,
2126 xsrc
, ysrc
, width
, height
,
2130 wxLogLastError(_T("StretchBlt"));
2144 (int)width
, (int)height
,
2150 wxLogLastError(_T("BitBlt"));
2159 ::SetTextColor(GetHdc(), old_textground
);
2160 ::SetBkColor(GetHdc(), old_background
);
2165 void wxDC::DoGetSize(int *w
, int *h
) const
2167 WXMICROWIN_CHECK_HDC
2169 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2170 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2173 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2175 WXMICROWIN_CHECK_HDC
2177 // if we implement it in terms of DoGetSize() instead of directly using the
2178 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2179 // will also work for wxWindowDC and wxClientDC even though their size is
2180 // not the same as the total size of the screen
2181 int wPixels
, hPixels
;
2182 DoGetSize(&wPixels
, &hPixels
);
2186 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2188 wxCHECK_RET( wTotal
, _T("0 width device?") );
2190 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2195 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2197 wxCHECK_RET( hTotal
, _T("0 height device?") );
2199 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2203 wxSize
wxDC::GetPPI() const
2205 WXMICROWIN_CHECK_HDC_RET(wxSize())
2207 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2208 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2210 return wxSize(x
, y
);
2213 // For use by wxWindows only, unless custom units are required.
2214 void wxDC::SetLogicalScale(double x
, double y
)
2216 WXMICROWIN_CHECK_HDC
2218 m_logicalScaleX
= x
;
2219 m_logicalScaleY
= y
;
2222 // ----------------------------------------------------------------------------
2224 // ----------------------------------------------------------------------------
2226 #if wxUSE_DC_CACHEING
2229 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2230 * improve it in due course, either using arrays, or simply storing pointers to one
2231 * entry for the bitmap, and two for the DCs. -- JACS
2234 wxList
wxDC::sm_bitmapCache
;
2235 wxList
wxDC::sm_dcCache
;
2237 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2246 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2255 wxDCCacheEntry::~wxDCCacheEntry()
2258 ::DeleteObject((HBITMAP
) m_bitmap
);
2260 ::DeleteDC((HDC
) m_dc
);
2263 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2265 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2266 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2269 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2271 if (entry
->m_depth
== depth
)
2273 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2275 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2276 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2277 if ( !entry
->m_bitmap
)
2279 wxLogLastError(wxT("CreateCompatibleBitmap"));
2281 entry
->m_width
= w
; entry
->m_height
= h
;
2287 node
= node
->GetNext();
2289 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2292 wxLogLastError(wxT("CreateCompatibleBitmap"));
2294 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2295 AddToBitmapCache(entry
);
2299 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2301 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2302 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2305 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2307 // Don't return the same one as we already have
2308 if (!notThis
|| (notThis
!= entry
))
2310 if (entry
->m_depth
== depth
)
2316 node
= node
->GetNext();
2318 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2321 wxLogLastError(wxT("CreateCompatibleDC"));
2323 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2324 AddToDCCache(entry
);
2328 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2330 sm_bitmapCache
.Append(entry
);
2333 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2335 sm_dcCache
.Append(entry
);
2338 void wxDC::ClearCache()
2340 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2341 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2344 // Clean up cache at app exit
2345 class wxDCModule
: public wxModule
2348 virtual bool OnInit() { return true; }
2349 virtual void OnExit() { wxDC::ClearCache(); }
2352 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2355 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2357 #endif // wxUSE_DC_CACHEING
2359 // ----------------------------------------------------------------------------
2360 // alpha channel support
2361 // ----------------------------------------------------------------------------
2363 static bool AlphaBlt(HDC hdcDst
,
2364 int x
, int y
, int width
, int height
,
2366 const wxBitmap
& bmp
)
2368 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2369 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2371 // do we have AlphaBlend() and company in the headers?
2372 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2373 // yes, now try to see if we have it during run-time
2374 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2375 HDC
,int,int,int,int,
2378 // bitmaps can be drawn only from GUI thread so there is no need to
2379 // protect this static variable from multiple threads
2380 static bool s_triedToLoad
= false;
2381 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2382 if ( !s_triedToLoad
)
2384 s_triedToLoad
= true;
2386 // don't give errors about the DLL being unavailable, we're
2387 // prepared to handle this
2390 wxDynamicLibrary
dll(_T("msimg32.dll"));
2391 if ( dll
.IsLoaded() )
2393 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2394 if ( pfnAlphaBlend
)
2396 // we must keep the DLL loaded if we want to be able to
2397 // call AlphaBlend() so just never unload it at all, not a
2404 if ( pfnAlphaBlend
)
2407 bf
.BlendOp
= AC_SRC_OVER
;
2409 bf
.SourceConstantAlpha
= 0xff;
2410 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2412 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2413 hdcSrc
, 0, 0, width
, height
,
2416 // skip wxAlphaBlend() call below
2420 wxLogLastError(_T("AlphaBlend"));
2422 #endif // defined(AC_SRC_OVER)
2424 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2426 #ifdef wxHAVE_RAW_BITMAP
2427 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2430 #else // !wxHAVE_RAW_BITMAP
2431 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2432 // alpha but at least something will be shown like this)
2434 #endif // wxHAVE_RAW_BITMAP
2438 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2439 #ifdef wxHAVE_RAW_BITMAP
2442 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2444 // get the destination DC pixels
2445 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2447 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2449 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2451 wxLogLastError(_T("BitBlt"));
2454 // combine them with the source bitmap using alpha
2455 wxAlphaPixelData
dataDst(bmpDst
),
2456 dataSrc((wxBitmap
&)bmpSrc
);
2458 wxCHECK_RET( dataDst
&& dataSrc
,
2459 _T("failed to get raw data in wxAlphaBlend") );
2461 wxAlphaPixelData::Iterator
pDst(dataDst
),
2464 for ( int y
= 0; y
< h
; y
++ )
2466 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2467 pSrcRowStart
= pSrc
;
2469 for ( int x
= 0; x
< w
; x
++ )
2471 // note that source bitmap uses premultiplied alpha (as required by
2472 // the real AlphaBlend)
2473 const unsigned beta
= 255 - pSrc
.Alpha();
2475 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2476 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2477 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2483 pDst
= pDstRowStart
;
2484 pSrc
= pSrcRowStart
;
2485 pDst
.OffsetY(dataDst
, 1);
2486 pSrc
.OffsetY(dataSrc
, 1);
2489 // and finally blit them back to the destination DC
2490 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2492 wxLogLastError(_T("BitBlt"));
2496 #endif // #ifdef wxHAVE_RAW_BITMAP