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"
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
45 #include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
47 #include "wx/sysopt.h"
48 #include "wx/dcprint.h"
49 #include "wx/module.h"
50 #include "wx/dynload.h"
52 #ifdef wxHAVE_RAW_BITMAP
53 #include "wx/rawbmp.h"
59 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
68 #define AC_SRC_ALPHA 1
71 /* Quaternary raster codes */
73 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
76 // apparently with MicroWindows it is possible that HDC is 0 so we have to
77 // check for this ourselves
79 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
80 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
82 #define WXMICROWIN_CHECK_HDC
83 #define WXMICROWIN_CHECK_HDC_RET(x)
86 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
88 // ---------------------------------------------------------------------------
90 // ---------------------------------------------------------------------------
92 static const int VIEWPORT_EXTENT
= 1000;
94 static const int MM_POINTS
= 9;
95 static const int MM_METRIC
= 10;
97 // usually this is defined in math.h
99 static const double M_PI
= 3.14159265358979323846;
102 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
103 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
104 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
106 // ----------------------------------------------------------------------------
107 // macros for logical <-> device coords conversion
108 // ----------------------------------------------------------------------------
111 We currently let Windows do all the translations itself so these macros are
112 not really needed (any more) but keep them to enhance readability of the
113 code by allowing to see where are the logical and where are the device
118 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
119 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
120 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
121 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
123 #define XLOG2DEV(x) (x)
124 #define YLOG2DEV(y) (y)
125 #define XDEV2LOG(x) (x)
126 #define YDEV2LOG(y) (y)
129 // ---------------------------------------------------------------------------
131 // ---------------------------------------------------------------------------
133 // convert degrees to radians
134 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
136 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
138 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
139 // to pass it to this function but as we already have it at the point
140 // of call anyhow we do
142 // return true if we could draw the bitmap in one way or the other, false
144 static bool AlphaBlt(HDC hdcDst
,
145 int x
, int y
, int w
, int h
,
147 const wxBitmap
& bmpSrc
);
149 #ifdef wxHAVE_RAW_BITMAP
150 // our (limited) AlphaBlend() replacement
152 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
155 // ----------------------------------------------------------------------------
157 // ----------------------------------------------------------------------------
159 // instead of duplicating the same code which sets and then restores text
160 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
161 // encapsulate this in a small helper class
163 // wxColourChanger: changes the text colours in the ctor if required and
164 // restores them in the dtor
165 class wxColourChanger
168 wxColourChanger(wxDC
& dc
);
174 COLORREF m_colFgOld
, m_colBgOld
;
178 DECLARE_NO_COPY_CLASS(wxColourChanger
)
181 // this class saves the old stretch blit mode during its life time
182 class StretchBltModeChanger
185 StretchBltModeChanger(HDC hdc
, int mode
)
189 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
191 wxLogLastError(_T("SetStretchBltMode"));
197 ~StretchBltModeChanger()
200 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
201 wxLogLastError(_T("SetStretchBltMode"));
210 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
213 // ===========================================================================
215 // ===========================================================================
217 // ----------------------------------------------------------------------------
219 // ----------------------------------------------------------------------------
221 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
223 const wxBrush
& brush
= dc
.GetBrush();
224 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
226 HDC hdc
= GetHdcOf(dc
);
227 m_colFgOld
= ::GetTextColor(hdc
);
228 m_colBgOld
= ::GetBkColor(hdc
);
230 // note that Windows convention is opposite to wxWidgets one, this is
231 // why text colour becomes the background one and vice versa
232 const wxColour
& colFg
= dc
.GetTextForeground();
235 ::SetBkColor(hdc
, colFg
.GetPixel());
238 const wxColour
& colBg
= dc
.GetTextBackground();
241 ::SetTextColor(hdc
, colBg
.GetPixel());
245 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
248 // flag which telsl us to undo changes in the dtor
253 // nothing done, nothing to undo
258 wxColourChanger::~wxColourChanger()
262 // restore the colours we changed
263 HDC hdc
= GetHdcOf(m_dc
);
265 ::SetBkMode(hdc
, TRANSPARENT
);
266 ::SetTextColor(hdc
, m_colFgOld
);
267 ::SetBkColor(hdc
, m_colBgOld
);
271 // ---------------------------------------------------------------------------
273 // ---------------------------------------------------------------------------
275 // Default constructor
286 #endif // wxUSE_PALETTE
296 SelectOldObjects(m_hDC
);
298 // if we own the HDC, we delete it, otherwise we just release it
302 ::DeleteDC(GetHdc());
304 else // we don't own our HDC
308 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
312 // Must have been a wxScreenDC
313 ::ReleaseDC((HWND
) NULL
, GetHdc());
319 // This will select current objects out of the DC,
320 // which is what you have to do before deleting the
322 void wxDC::SelectOldObjects(WXHDC dc
)
328 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
330 if (m_selectedBitmap
.Ok())
332 m_selectedBitmap
.SetSelectedInto(NULL
);
339 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
344 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
349 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
356 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
359 #endif // wxUSE_PALETTE
362 m_brush
= wxNullBrush
;
365 m_palette
= wxNullPalette
;
366 #endif // wxUSE_PALETTE
368 m_backgroundBrush
= wxNullBrush
;
369 m_selectedBitmap
= wxNullBitmap
;
372 // ---------------------------------------------------------------------------
374 // ---------------------------------------------------------------------------
376 void wxDC::UpdateClipBox()
381 ::GetClipBox(GetHdc(), &rect
);
383 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
384 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
385 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
386 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
390 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
392 // check if we should try to retrieve the clipping region possibly not set
393 // by our SetClippingRegion() but preset by Windows:this can only happen
394 // when we're associated with an existing HDC usign SetHDC(), see there
395 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
397 wxDC
*self
= wxConstCast(this, wxDC
);
398 self
->UpdateClipBox();
400 if ( !m_clipX1
&& !m_clipX2
)
401 self
->m_clipping
= false;
404 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
407 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
408 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
410 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
414 // note that we combine the new clipping region with the existing one: this
415 // is compatible with what the other ports do and is the documented
416 // behaviour now (starting with 2.3.3)
417 #if defined(__WXWINCE__)
419 if ( !::GetClipBox(GetHdc(), &rectClip
) )
422 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
423 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
424 rectClip
.right
, rectClip
.bottom
);
426 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
428 ::SelectClipRgn(GetHdc(), hrgnDest
);
431 ::DeleteObject(hrgnClipOld
);
432 ::DeleteObject(hrgnDest
);
434 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
436 wxLogLastError(_T("ExtSelectClipRgn"));
440 #endif // WinCE/!WinCE
447 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
449 // the region coords are always the device ones, so do the translation
452 // FIXME: possible +/-1 error here, to check!
453 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
455 LogicalToDeviceX(x
+ w
),
456 LogicalToDeviceY(y
+ h
));
459 wxLogLastError(_T("CreateRectRgn"));
463 SetClippingHrgn((WXHRGN
)hrgn
);
465 ::DeleteObject(hrgn
);
469 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
471 SetClippingHrgn(region
.GetHRGN());
474 void wxDC::DestroyClippingRegion()
478 if (m_clipping
&& m_hDC
)
480 // TODO: this should restore the previous clipping region,
481 // so that OnPaint processing works correctly, and the update
482 // clipping region doesn't get destroyed after the first
483 // DestroyClippingRegion.
484 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
485 ::SelectClipRgn(GetHdc(), rgn
);
489 wxDCBase::DestroyClippingRegion();
492 // ---------------------------------------------------------------------------
493 // query capabilities
494 // ---------------------------------------------------------------------------
496 bool wxDC::CanDrawBitmap() const
501 bool wxDC::CanGetTextExtent() const
503 #ifdef __WXMICROWIN__
504 // TODO Extend MicroWindows' GetDeviceCaps function
507 // What sort of display is it?
508 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
510 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
514 int wxDC::GetDepth() const
516 WXMICROWIN_CHECK_HDC_RET(16)
518 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
521 // ---------------------------------------------------------------------------
523 // ---------------------------------------------------------------------------
532 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
536 // No, I think we should simply ignore this if printing on e.g.
538 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
539 if (!m_selectedBitmap
.Ok())
542 rect
.left
= 0; rect
.top
= 0;
543 rect
.right
= m_selectedBitmap
.GetWidth();
544 rect
.bottom
= m_selectedBitmap
.GetHeight();
548 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
551 DWORD colour
= ::GetBkColor(GetHdc());
552 HBRUSH brush
= ::CreateSolidBrush(colour
);
553 ::FillRect(GetHdc(), &rect
, brush
);
554 ::DeleteObject(brush
);
556 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
557 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
560 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
562 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
563 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
564 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
565 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
569 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
579 WXMICROWIN_CHECK_HDC_RET(false)
581 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
583 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
584 : FLOODFILLBORDER
) ) ;
587 // quoting from the MSDN docs:
589 // Following are some of the reasons this function might fail:
591 // * The filling could not be completed.
592 // * The specified point has the boundary color specified by the
593 // crColor parameter (if FLOODFILLBORDER was requested).
594 // * The specified point does not have the color specified by
595 // crColor (if FLOODFILLSURFACE was requested)
596 // * The point is outside the clipping region that is, it is not
597 // visible on the device.
599 wxLogLastError(wxT("ExtFloodFill"));
602 CalcBoundingBox(x
, y
);
608 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
610 WXMICROWIN_CHECK_HDC_RET(false)
612 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
614 // get the color of the pixel
615 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
617 wxRGBToColour(*col
, pixelcolor
);
622 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
626 wxCoord x1
= x
-VIEWPORT_EXTENT
;
627 wxCoord y1
= y
-VIEWPORT_EXTENT
;
628 wxCoord x2
= x
+VIEWPORT_EXTENT
;
629 wxCoord y2
= y
+VIEWPORT_EXTENT
;
631 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
632 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
634 CalcBoundingBox(x1
, y1
);
635 CalcBoundingBox(x2
, y2
);
638 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
642 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
644 CalcBoundingBox(x1
, y1
);
645 CalcBoundingBox(x2
, y2
);
648 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
649 // and ending at (x2, y2)
650 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
651 wxCoord x2
, wxCoord y2
,
652 wxCoord xc
, wxCoord yc
)
655 // Slower emulation since WinCE doesn't support Pie and Arc
656 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
657 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
658 if( y1
>yc
) sa
= -sa
; // below center
659 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
660 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
665 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
669 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
670 wxCoord r
= (wxCoord
)radius
;
672 // treat the special case of full circle separately
673 if ( x1
== x2
&& y1
== y2
)
675 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
679 wxCoord xx1
= XLOG2DEV(x1
);
680 wxCoord yy1
= YLOG2DEV(y1
);
681 wxCoord xx2
= XLOG2DEV(x2
);
682 wxCoord yy2
= YLOG2DEV(y2
);
683 wxCoord xxc
= XLOG2DEV(xc
);
684 wxCoord yyc
= YLOG2DEV(yc
);
685 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
687 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
688 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
689 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
690 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
692 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
694 // Have to add 1 to bottom-right corner of rectangle
695 // to make semi-circles look right (crooked line otherwise).
696 // Unfortunately this is not a reliable method, depends
697 // on the size of shape.
698 // TODO: figure out why this happens!
699 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
703 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
706 CalcBoundingBox(xc
- r
, yc
- r
);
707 CalcBoundingBox(xc
+ r
, yc
+ r
);
711 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
712 wxCoord width
, wxCoord height
)
716 wxCoord x2
= x1
+ width
,
719 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
727 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
729 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
731 #else // Symantec-MicroWin
733 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
734 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
735 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
736 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
737 ::SetROP2(GetHdc(), R2_COPYPEN
);
738 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
739 MoveToEx(GetHdc(), x1
, y1
, NULL
);
740 LineTo(GetHdc(), x2
, y2
);
741 MoveToEx(GetHdc(), x2
, y1
, NULL
);
742 LineTo(GetHdc(), x1
, y2
);
743 ::SelectObject(GetHdc(), hPenOld
);
744 ::SelectObject(GetHdc(), hBrushOld
);
745 ::DeleteObject(blackPen
);
746 #endif // Win32/Symantec-MicroWin
748 CalcBoundingBox(x1
, y1
);
749 CalcBoundingBox(x2
, y2
);
752 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
756 COLORREF color
= 0x00ffffff;
759 color
= m_pen
.GetColour().GetPixel();
762 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
764 CalcBoundingBox(x
, y
);
767 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
771 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
773 // Do things less efficiently if we have offsets
774 if (xoffset
!= 0 || yoffset
!= 0)
776 POINT
*cpoints
= new POINT
[n
];
778 for (i
= 0; i
< n
; i
++)
780 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
781 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
783 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
786 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
788 wxUnusedVar(fillStyle
);
790 (void)Polygon(GetHdc(), cpoints
, n
);
792 SetPolyFillMode(GetHdc(),prev
);
799 for (i
= 0; i
< n
; i
++)
800 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
803 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
805 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
807 SetPolyFillMode(GetHdc(),prev
);
813 wxDC::DoDrawPolyPolygon(int n
,
821 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
825 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
827 for (i
= cnt
= 0; i
< n
; i
++)
830 // Do things less efficiently if we have offsets
831 if (xoffset
!= 0 || yoffset
!= 0)
833 POINT
*cpoints
= new POINT
[cnt
];
834 for (i
= 0; i
< cnt
; i
++)
836 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
837 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
839 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
842 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
844 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
846 SetPolyFillMode(GetHdc(),prev
);
852 for (i
= 0; i
< cnt
; i
++)
853 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
856 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
858 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
860 SetPolyFillMode(GetHdc(),prev
);
867 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
871 // Do things less efficiently if we have offsets
872 if (xoffset
!= 0 || yoffset
!= 0)
874 POINT
*cpoints
= new POINT
[n
];
876 for (i
= 0; i
< n
; i
++)
878 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
879 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
881 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
883 (void)Polyline(GetHdc(), cpoints
, n
);
889 for (i
= 0; i
< n
; i
++)
890 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
892 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
896 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
900 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
902 wxCoord x2
= x
+ width
;
903 wxCoord y2
= y
+ height
;
905 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
908 rect
.left
= XLOG2DEV(x
);
909 rect
.top
= YLOG2DEV(y
);
910 rect
.right
= XLOG2DEV(x2
);
911 rect
.bottom
= YLOG2DEV(y2
);
912 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
916 // Windows draws the filled rectangles without outline (i.e. drawn with a
917 // transparent pen) one pixel smaller in both directions and we want them
918 // to have the same size regardless of which pen is used - adjust
920 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
921 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
927 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
931 CalcBoundingBox(x
, y
);
932 CalcBoundingBox(x2
, y2
);
935 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
939 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
941 // Now, a negative radius value is interpreted to mean
942 // 'the proportion of the smallest X or Y dimension'
946 double smallest
= (width
< height
) ? width
: height
;
947 radius
= (- radius
* smallest
);
950 wxCoord x2
= (x
+width
);
951 wxCoord y2
= (y
+height
);
953 // Windows draws the filled rectangles without outline (i.e. drawn with a
954 // transparent pen) one pixel smaller in both directions and we want them
955 // to have the same size regardless of which pen is used - adjust
956 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
962 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
963 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
965 CalcBoundingBox(x
, y
);
966 CalcBoundingBox(x2
, y2
);
969 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
973 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
975 wxCoord x2
= (x
+width
);
976 wxCoord y2
= (y
+height
);
978 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
980 CalcBoundingBox(x
, y
);
981 CalcBoundingBox(x2
, y2
);
984 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
985 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
988 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
993 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
998 int rx1
= XLOG2DEV(x
+w
/2);
999 int ry1
= YLOG2DEV(y
+h
/2);
1006 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1007 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1008 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1009 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1011 // draw pie with NULL_PEN first and then outline otherwise a line is
1012 // drawn from the start and end points to the centre
1013 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1016 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1017 rx1
, ry1
, rx2
, ry2
);
1021 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1022 rx1
, ry1
-1, rx2
, ry2
-1);
1025 ::SelectObject(GetHdc(), hpenOld
);
1027 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1028 rx1
, ry1
, rx2
, ry2
);
1030 CalcBoundingBox(x
, y
);
1031 CalcBoundingBox(x2
, y2
);
1035 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1037 WXMICROWIN_CHECK_HDC
1039 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1042 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1044 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1047 CalcBoundingBox(x
, y
);
1048 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1051 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1053 WXMICROWIN_CHECK_HDC
1055 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1057 int width
= bmp
.GetWidth(),
1058 height
= bmp
.GetHeight();
1060 HBITMAP hbmpMask
= 0;
1063 HPALETTE oldPal
= 0;
1064 #endif // wxUSE_PALETTE
1066 if ( bmp
.HasAlpha() )
1069 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1071 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1077 wxMask
*mask
= bmp
.GetMask();
1079 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1083 // don't give assert here because this would break existing
1084 // programs - just silently ignore useMask parameter
1091 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1093 // On some systems, MaskBlt succeeds yet is much much slower
1094 // than the wxWidgets fall-back implementation. So we need
1095 // to be able to switch this on and off at runtime.
1097 #if wxUSE_SYSTEM_OPTIONS
1098 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1102 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1103 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1105 wxPalette
*pal
= bmp
.GetPalette();
1106 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1108 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1109 ::RealizePalette(hdcMem
);
1111 #endif // wxUSE_PALETTE
1113 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1116 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1120 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1121 #endif // wxUSE_PALETTE
1123 ::SelectObject(hdcMem
, hOldBitmap
);
1130 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1133 memDC
.SelectObject(bmp
);
1135 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1137 memDC
.SelectObject(wxNullBitmap
);
1140 else // no mask, just use BitBlt()
1143 HDC memdc
= ::CreateCompatibleDC( cdc
);
1144 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1146 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1148 COLORREF old_textground
= ::GetTextColor(GetHdc());
1149 COLORREF old_background
= ::GetBkColor(GetHdc());
1150 if (m_textForegroundColour
.Ok())
1152 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1154 if (m_textBackgroundColour
.Ok())
1156 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1160 wxPalette
*pal
= bmp
.GetPalette();
1161 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1163 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1164 ::RealizePalette(memdc
);
1166 #endif // wxUSE_PALETTE
1168 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1169 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1173 ::SelectPalette(memdc
, oldPal
, FALSE
);
1174 #endif // wxUSE_PALETTE
1176 ::SelectObject( memdc
, hOldBitmap
);
1177 ::DeleteDC( memdc
);
1179 ::SetTextColor(GetHdc(), old_textground
);
1180 ::SetBkColor(GetHdc(), old_background
);
1184 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1186 WXMICROWIN_CHECK_HDC
1188 DrawAnyText(text
, x
, y
);
1190 // update the bounding box
1191 CalcBoundingBox(x
, y
);
1194 GetTextExtent(text
, &w
, &h
);
1195 CalcBoundingBox(x
+ w
, y
+ h
);
1198 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1200 WXMICROWIN_CHECK_HDC
1202 // prepare for drawing the text
1203 if ( m_textForegroundColour
.Ok() )
1204 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1206 DWORD old_background
= 0;
1207 if ( m_textBackgroundColour
.Ok() )
1209 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1212 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1216 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1217 text
.c_str(), text
.length(), NULL
) == 0 )
1219 wxLogLastError(wxT("TextOut"));
1222 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1223 text
.c_str(), text
.length()) == 0 )
1225 wxLogLastError(wxT("TextOut"));
1229 // restore the old parameters (text foreground colour may be left because
1230 // it never is set to anything else, but background should remain
1231 // transparent even if we just drew an opaque string)
1232 if ( m_textBackgroundColour
.Ok() )
1233 (void)SetBkColor(GetHdc(), old_background
);
1235 SetBkMode(GetHdc(), TRANSPARENT
);
1238 void wxDC::DoDrawRotatedText(const wxString
& text
,
1239 wxCoord x
, wxCoord y
,
1242 WXMICROWIN_CHECK_HDC
1244 // we test that we have some font because otherwise we should still use the
1245 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1246 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1247 // font for drawing rotated fonts unfortunately)
1248 if ( (angle
== 0.0) && m_font
.Ok() )
1250 DoDrawText(text
, x
, y
);
1252 #ifndef __WXMICROWIN__
1255 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1256 // because it's not TrueType and so can't have non zero
1257 // orientation/escapement under Win9x
1258 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1259 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1261 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1263 wxLogLastError(wxT("GetObject(hfont)"));
1266 // GDI wants the angle in tenth of degree
1267 long angle10
= (long)(angle
* 10);
1268 lf
.lfEscapement
= angle10
;
1269 lf
. lfOrientation
= angle10
;
1271 hfont
= ::CreateFontIndirect(&lf
);
1274 wxLogLastError(wxT("CreateFont"));
1278 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1280 DrawAnyText(text
, x
, y
);
1282 (void)::SelectObject(GetHdc(), hfontOld
);
1283 (void)::DeleteObject(hfont
);
1286 // call the bounding box by adding all four vertices of the rectangle
1287 // containing the text to it (simpler and probably not slower than
1288 // determining which of them is really topmost/leftmost/...)
1290 GetTextExtent(text
, &w
, &h
);
1292 double rad
= DegToRad(angle
);
1294 // "upper left" and "upper right"
1295 CalcBoundingBox(x
, y
);
1296 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1298 // "bottom left" and "bottom right"
1299 x
+= (wxCoord
)(h
*sin(rad
));
1300 y
+= (wxCoord
)(h
*cos(rad
));
1301 CalcBoundingBox(x
, y
);
1302 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1307 // ---------------------------------------------------------------------------
1309 // ---------------------------------------------------------------------------
1313 void wxDC::DoSelectPalette(bool realize
)
1315 WXMICROWIN_CHECK_HDC
1317 // Set the old object temporarily, in case the assignment deletes an object
1318 // that's not yet selected out.
1321 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1325 if ( m_palette
.Ok() )
1327 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1328 GetHpaletteOf(m_palette
),
1331 m_oldPalette
= (WXHPALETTE
) oldPal
;
1334 ::RealizePalette(GetHdc());
1338 void wxDC::SetPalette(const wxPalette
& palette
)
1342 m_palette
= palette
;
1343 DoSelectPalette(true);
1347 void wxDC::InitializePalette()
1349 if ( wxDisplayDepth() <= 8 )
1351 // look for any window or parent that has a custom palette. If any has
1352 // one then we need to use it in drawing operations
1353 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1355 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1356 if ( m_hasCustomPalette
)
1358 m_palette
= win
->GetPalette();
1360 // turn on MSW translation for this palette
1366 #endif // wxUSE_PALETTE
1368 // SetFont/Pen/Brush() really ask to be implemented as a single template
1369 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1371 void wxDC::SetFont(const wxFont
& font
)
1373 WXMICROWIN_CHECK_HDC
1375 if ( font
== m_font
)
1380 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1381 if ( hfont
== HGDI_ERROR
)
1383 wxLogLastError(_T("SelectObject(font)"));
1388 m_oldFont
= (WXHPEN
)hfont
;
1393 else // invalid font, reset the current font
1397 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1399 wxLogLastError(_T("SelectObject(old font)"));
1405 m_font
= wxNullFont
;
1409 void wxDC::SetPen(const wxPen
& pen
)
1411 WXMICROWIN_CHECK_HDC
1418 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1419 if ( hpen
== HGDI_ERROR
)
1421 wxLogLastError(_T("SelectObject(pen)"));
1426 m_oldPen
= (WXHPEN
)hpen
;
1431 else // invalid pen, reset the current pen
1435 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1437 wxLogLastError(_T("SelectObject(old pen)"));
1447 void wxDC::SetBrush(const wxBrush
& brush
)
1449 WXMICROWIN_CHECK_HDC
1451 if ( brush
== m_brush
)
1456 // we must make sure the brush is aligned with the logical coordinates
1457 // before selecting it
1458 wxBitmap
*stipple
= brush
.GetStipple();
1459 if ( stipple
&& stipple
->Ok() )
1461 if ( !::SetBrushOrgEx
1464 m_deviceOriginX
% stipple
->GetWidth(),
1465 m_deviceOriginY
% stipple
->GetHeight(),
1466 NULL
// [out] previous brush origin
1469 wxLogLastError(_T("SetBrushOrgEx()"));
1473 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1474 if ( hbrush
== HGDI_ERROR
)
1476 wxLogLastError(_T("SelectObject(brush)"));
1481 m_oldBrush
= (WXHPEN
)hbrush
;
1486 else // invalid brush, reset the current brush
1490 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1492 wxLogLastError(_T("SelectObject(old brush)"));
1498 m_brush
= wxNullBrush
;
1502 void wxDC::SetBackground(const wxBrush
& brush
)
1504 WXMICROWIN_CHECK_HDC
1506 m_backgroundBrush
= brush
;
1508 if ( m_backgroundBrush
.Ok() )
1510 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1514 void wxDC::SetBackgroundMode(int mode
)
1516 WXMICROWIN_CHECK_HDC
1518 m_backgroundMode
= mode
;
1520 // SetBackgroundColour now only refers to text background
1521 // and m_backgroundMode is used there
1524 void wxDC::SetLogicalFunction(int function
)
1526 WXMICROWIN_CHECK_HDC
1528 m_logicalFunction
= function
;
1533 void wxDC::SetRop(WXHDC dc
)
1535 if ( !dc
|| m_logicalFunction
< 0 )
1540 switch (m_logicalFunction
)
1542 case wxCLEAR
: rop
= R2_BLACK
; break;
1543 case wxXOR
: rop
= R2_XORPEN
; break;
1544 case wxINVERT
: rop
= R2_NOT
; break;
1545 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1546 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1547 case wxCOPY
: rop
= R2_COPYPEN
; break;
1548 case wxAND
: rop
= R2_MASKPEN
; break;
1549 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1550 case wxNO_OP
: rop
= R2_NOP
; break;
1551 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1552 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1553 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1554 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1555 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1556 case wxOR
: rop
= R2_MERGEPEN
; break;
1557 case wxSET
: rop
= R2_WHITE
; break;
1560 wxFAIL_MSG( wxT("unsupported logical function") );
1564 SetROP2(GetHdc(), rop
);
1567 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1569 // We might be previewing, so return true to let it continue.
1577 void wxDC::StartPage()
1581 void wxDC::EndPage()
1585 // ---------------------------------------------------------------------------
1587 // ---------------------------------------------------------------------------
1589 wxCoord
wxDC::GetCharHeight() const
1591 WXMICROWIN_CHECK_HDC_RET(0)
1593 TEXTMETRIC lpTextMetric
;
1595 GetTextMetrics(GetHdc(), &lpTextMetric
);
1597 return lpTextMetric
.tmHeight
;
1600 wxCoord
wxDC::GetCharWidth() const
1602 WXMICROWIN_CHECK_HDC_RET(0)
1604 TEXTMETRIC lpTextMetric
;
1606 GetTextMetrics(GetHdc(), &lpTextMetric
);
1608 return lpTextMetric
.tmAveCharWidth
;
1611 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1612 wxCoord
*descent
, wxCoord
*externalLeading
,
1615 #ifdef __WXMICROWIN__
1620 if (descent
) *descent
= 0;
1621 if (externalLeading
) *externalLeading
= 0;
1624 #endif // __WXMICROWIN__
1629 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1631 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1633 else // don't change the font
1641 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1642 GetTextMetrics(GetHdc(), &tm
);
1649 *descent
= tm
.tmDescent
;
1650 if (externalLeading
)
1651 *externalLeading
= tm
.tmExternalLeading
;
1655 ::SelectObject(GetHdc(), hfontOld
);
1660 // Each element of the array will be the width of the string up to and
1661 // including the coresoponding character in text.
1663 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1665 static int maxLenText
= -1;
1666 static int maxWidth
= -1;
1669 int stlen
= text
.Length();
1671 if (maxLenText
== -1)
1673 // Win9x and WinNT+ have different limits
1674 int version
= wxGetOsVersion();
1675 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1676 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1680 widths
.Add(0, stlen
); // fill the array with zeros
1682 if (!::GetTextExtentExPoint(GetHdc(),
1683 text
.c_str(), // string to check
1684 wxMin(stlen
, maxLenText
),
1686 &fit
, // [out] count of chars
1688 &widths
[0], // array to fill
1692 wxLogLastError(wxT("GetTextExtentExPoint"));
1702 void wxDC::SetMapMode(int mode
)
1704 WXMICROWIN_CHECK_HDC
1706 m_mappingMode
= mode
;
1708 if ( mode
== wxMM_TEXT
)
1711 m_logicalScaleY
= 1.0;
1713 else // need to do some calculations
1715 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1716 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1717 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1718 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1720 if ( (mm_width
== 0) || (mm_height
== 0) )
1722 // we can't calculate mm2pixels[XY] then!
1726 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1727 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1732 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1733 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1737 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1738 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1742 m_logicalScaleX
= mm2pixelsX
;
1743 m_logicalScaleY
= mm2pixelsY
;
1747 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1748 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1752 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1756 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1757 // cases we could do with MM_TEXT and in the remaining 0.9% with
1758 // MM_ISOTROPIC (TODO!)
1760 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1762 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1763 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1765 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1766 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1768 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1769 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1773 void wxDC::SetUserScale(double x
, double y
)
1775 WXMICROWIN_CHECK_HDC
1777 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1783 this->SetMapMode(m_mappingMode
);
1786 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1788 WXMICROWIN_CHECK_HDC
1791 int signX
= xLeftRight
? 1 : -1,
1792 signY
= yBottomUp
? -1 : 1;
1794 if ( signX
!= m_signX
|| signY
!= m_signY
)
1799 SetMapMode(m_mappingMode
);
1802 wxUnusedVar(xLeftRight
);
1803 wxUnusedVar(yBottomUp
);
1807 void wxDC::SetSystemScale(double x
, double y
)
1809 WXMICROWIN_CHECK_HDC
1811 if ( x
== m_scaleX
&& y
== m_scaleY
)
1818 SetMapMode(m_mappingMode
);
1822 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1824 WXMICROWIN_CHECK_HDC
1826 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1829 m_logicalOriginX
= x
;
1830 m_logicalOriginY
= y
;
1833 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1837 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1839 WXMICROWIN_CHECK_HDC
1841 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1844 m_deviceOriginX
= x
;
1845 m_deviceOriginY
= y
;
1848 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1852 // ---------------------------------------------------------------------------
1853 // coordinates transformations
1854 // ---------------------------------------------------------------------------
1856 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1858 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1861 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1863 // axis orientation is not taken into account for conversion of a distance
1864 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1867 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1869 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1872 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1874 // axis orientation is not taken into account for conversion of a distance
1875 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1878 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1880 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1883 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1885 // axis orientation is not taken into account for conversion of a distance
1886 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1889 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1891 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1894 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1896 // axis orientation is not taken into account for conversion of a distance
1897 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1900 // ---------------------------------------------------------------------------
1902 // ---------------------------------------------------------------------------
1904 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1905 wxCoord width
, wxCoord height
,
1906 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1907 int rop
, bool useMask
,
1908 wxCoord xsrcMask
, wxCoord ysrcMask
)
1910 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1912 WXMICROWIN_CHECK_HDC_RET(false)
1914 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1915 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1917 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1918 GetHdcOf(*source
), bmpSrc
) )
1922 wxMask
*mask
= NULL
;
1925 mask
= bmpSrc
.GetMask();
1927 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1929 // don't give assert here because this would break existing
1930 // programs - just silently ignore useMask parameter
1935 if (xsrcMask
== -1 && ysrcMask
== -1)
1937 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1940 COLORREF old_textground
= ::GetTextColor(GetHdc());
1941 COLORREF old_background
= ::GetBkColor(GetHdc());
1942 if (m_textForegroundColour
.Ok())
1944 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1946 if (m_textBackgroundColour
.Ok())
1948 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1954 case wxXOR
: dwRop
= SRCINVERT
; break;
1955 case wxINVERT
: dwRop
= DSTINVERT
; break;
1956 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1957 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1958 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1959 case wxSET
: dwRop
= WHITENESS
; break;
1960 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1961 case wxAND
: dwRop
= SRCAND
; break;
1962 case wxOR
: dwRop
= SRCPAINT
; break;
1963 case wxEQUIV
: dwRop
= 0x00990066; break;
1964 case wxNAND
: dwRop
= 0x007700E6; break;
1965 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1966 case wxCOPY
: dwRop
= SRCCOPY
; break;
1967 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1968 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1969 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1971 wxFAIL_MSG( wxT("unsupported logical function") );
1975 bool success
= false;
1980 // we want the part of the image corresponding to the mask to be
1981 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1982 // meaning of fg and bg is inverted which corresponds to wxWin notion
1983 // of the mask which is also contrary to the Windows one)
1985 // On some systems, MaskBlt succeeds yet is much much slower
1986 // than the wxWidgets fall-back implementation. So we need
1987 // to be able to switch this on and off at runtime.
1988 #if wxUSE_SYSTEM_OPTIONS
1989 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1995 xdest
, ydest
, width
, height
,
1998 (HBITMAP
)mask
->GetMaskBitmap(),
2000 MAKEROP4(dwRop
, DSTCOPY
)
2007 // Blit bitmap with mask
2010 HBITMAP buffer_bmap
;
2012 #if wxUSE_DC_CACHEING
2013 // create a temp buffer bitmap and DCs to access it and the mask
2014 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2015 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2017 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2018 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2020 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2023 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2024 #else // !wxUSE_DC_CACHEING
2025 // create a temp buffer bitmap and DCs to access it and the mask
2026 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2027 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2028 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2029 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2030 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2031 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2033 // copy dest to buffer
2034 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2035 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2037 wxLogLastError(wxT("BitBlt"));
2040 // copy src to buffer using selected raster op
2041 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2042 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2044 wxLogLastError(wxT("BitBlt"));
2047 // set masked area in buffer to BLACK (pixel value 0)
2048 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2049 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2050 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2051 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2053 wxLogLastError(wxT("BitBlt"));
2056 // set unmasked area in dest to BLACK
2057 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2058 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2059 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2060 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2062 wxLogLastError(wxT("BitBlt"));
2064 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2065 ::SetTextColor(GetHdc(), prevCol
);
2067 // OR buffer to dest
2068 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2069 (int)width
, (int)height
,
2070 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2073 wxLogLastError(wxT("BitBlt"));
2076 // tidy up temporary DCs and bitmap
2077 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2078 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2080 #if !wxUSE_DC_CACHEING
2082 ::DeleteDC(dc_mask
);
2083 ::DeleteDC(dc_buffer
);
2084 ::DeleteObject(buffer_bmap
);
2089 else // no mask, just BitBlt() it
2091 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2092 // use StretchBlt() if available and finally fall back to BitBlt()
2094 // FIXME: use appropriate WinCE functions
2096 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2097 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2102 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2104 &ds
) == sizeof(ds
) )
2106 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2108 // Figure out what co-ordinate system we're supposed to specify
2110 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2114 ysrc
= hDIB
- (ysrc
+ height
);
2117 if ( ::StretchDIBits(GetHdc(),
2123 (LPBITMAPINFO
)&ds
.dsBmih
,
2126 ) == (int)GDI_ERROR
)
2128 // On Win9x this API fails most (all?) of the time, so
2129 // logging it becomes quite distracting. Since it falls
2130 // back to the code below this is not really serious, so
2132 //wxLogLastError(wxT("StretchDIBits"));
2141 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2146 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2152 xdest
, ydest
, width
, height
,
2154 xsrc
, ysrc
, width
, height
,
2158 wxLogLastError(_T("StretchBlt"));
2172 (int)width
, (int)height
,
2178 wxLogLastError(_T("BitBlt"));
2187 ::SetTextColor(GetHdc(), old_textground
);
2188 ::SetBkColor(GetHdc(), old_background
);
2193 void wxDC::DoGetSize(int *w
, int *h
) const
2195 WXMICROWIN_CHECK_HDC
2197 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2198 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2201 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2203 WXMICROWIN_CHECK_HDC
2205 // if we implement it in terms of DoGetSize() instead of directly using the
2206 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2207 // will also work for wxWindowDC and wxClientDC even though their size is
2208 // not the same as the total size of the screen
2209 int wPixels
, hPixels
;
2210 DoGetSize(&wPixels
, &hPixels
);
2214 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2216 wxCHECK_RET( wTotal
, _T("0 width device?") );
2218 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2223 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2225 wxCHECK_RET( hTotal
, _T("0 height device?") );
2227 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2231 wxSize
wxDC::GetPPI() const
2233 WXMICROWIN_CHECK_HDC_RET(wxSize())
2235 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2236 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2238 return wxSize(x
, y
);
2241 // For use by wxWidgets only, unless custom units are required.
2242 void wxDC::SetLogicalScale(double x
, double y
)
2244 WXMICROWIN_CHECK_HDC
2246 m_logicalScaleX
= x
;
2247 m_logicalScaleY
= y
;
2250 // ----------------------------------------------------------------------------
2252 // ----------------------------------------------------------------------------
2254 #if wxUSE_DC_CACHEING
2257 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2258 * improve it in due course, either using arrays, or simply storing pointers to one
2259 * entry for the bitmap, and two for the DCs. -- JACS
2262 wxList
wxDC::sm_bitmapCache
;
2263 wxList
wxDC::sm_dcCache
;
2265 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2274 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2283 wxDCCacheEntry::~wxDCCacheEntry()
2286 ::DeleteObject((HBITMAP
) m_bitmap
);
2288 ::DeleteDC((HDC
) m_dc
);
2291 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2293 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2294 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2297 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2299 if (entry
->m_depth
== depth
)
2301 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2303 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2304 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2305 if ( !entry
->m_bitmap
)
2307 wxLogLastError(wxT("CreateCompatibleBitmap"));
2309 entry
->m_width
= w
; entry
->m_height
= h
;
2315 node
= node
->GetNext();
2317 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2320 wxLogLastError(wxT("CreateCompatibleBitmap"));
2322 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2323 AddToBitmapCache(entry
);
2327 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2329 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2330 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2333 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2335 // Don't return the same one as we already have
2336 if (!notThis
|| (notThis
!= entry
))
2338 if (entry
->m_depth
== depth
)
2344 node
= node
->GetNext();
2346 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2349 wxLogLastError(wxT("CreateCompatibleDC"));
2351 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2352 AddToDCCache(entry
);
2356 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2358 sm_bitmapCache
.Append(entry
);
2361 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2363 sm_dcCache
.Append(entry
);
2366 void wxDC::ClearCache()
2368 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2369 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2372 // Clean up cache at app exit
2373 class wxDCModule
: public wxModule
2376 virtual bool OnInit() { return true; }
2377 virtual void OnExit() { wxDC::ClearCache(); }
2380 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2383 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2385 #endif // wxUSE_DC_CACHEING
2387 // ----------------------------------------------------------------------------
2388 // alpha channel support
2389 // ----------------------------------------------------------------------------
2391 static bool AlphaBlt(HDC hdcDst
,
2392 int x
, int y
, int width
, int height
,
2394 const wxBitmap
& bmp
)
2396 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2397 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2399 // do we have AlphaBlend() and company in the headers?
2400 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2401 // yes, now try to see if we have it during run-time
2402 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2403 HDC
,int,int,int,int,
2406 // bitmaps can be drawn only from GUI thread so there is no need to
2407 // protect this static variable from multiple threads
2408 static bool s_triedToLoad
= false;
2409 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2410 if ( !s_triedToLoad
)
2412 s_triedToLoad
= true;
2414 // don't give errors about the DLL being unavailable, we're
2415 // prepared to handle this
2418 wxDynamicLibrary
dll(_T("msimg32.dll"));
2419 if ( dll
.IsLoaded() )
2421 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2422 if ( pfnAlphaBlend
)
2424 // we must keep the DLL loaded if we want to be able to
2425 // call AlphaBlend() so just never unload it at all, not a
2432 if ( pfnAlphaBlend
)
2435 bf
.BlendOp
= AC_SRC_OVER
;
2437 bf
.SourceConstantAlpha
= 0xff;
2438 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2440 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2441 hdcSrc
, 0, 0, width
, height
,
2444 // skip wxAlphaBlend() call below
2448 wxLogLastError(_T("AlphaBlend"));
2450 #endif // defined(AC_SRC_OVER)
2452 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2454 #ifdef wxHAVE_RAW_BITMAP
2455 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2458 #else // !wxHAVE_RAW_BITMAP
2459 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2460 // alpha but at least something will be shown like this)
2462 #endif // wxHAVE_RAW_BITMAP
2466 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2467 #ifdef wxHAVE_RAW_BITMAP
2470 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2472 // get the destination DC pixels
2473 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2475 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2477 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2479 wxLogLastError(_T("BitBlt"));
2482 // combine them with the source bitmap using alpha
2483 wxAlphaPixelData
dataDst(bmpDst
),
2484 dataSrc((wxBitmap
&)bmpSrc
);
2486 wxCHECK_RET( dataDst
&& dataSrc
,
2487 _T("failed to get raw data in wxAlphaBlend") );
2489 wxAlphaPixelData::Iterator
pDst(dataDst
),
2492 for ( int y
= 0; y
< h
; y
++ )
2494 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2495 pSrcRowStart
= pSrc
;
2497 for ( int x
= 0; x
< w
; x
++ )
2499 // note that source bitmap uses premultiplied alpha (as required by
2500 // the real AlphaBlend)
2501 const unsigned beta
= 255 - pSrc
.Alpha();
2503 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2504 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2505 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2511 pDst
= pDstRowStart
;
2512 pSrc
= pSrcRowStart
;
2513 pDst
.OffsetY(dataDst
, 1);
2514 pSrc
.OffsetY(dataSrc
, 1);
2517 // and finally blit them back to the destination DC
2518 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2520 wxLogLastError(_T("BitBlt"));
2524 #endif // #ifdef wxHAVE_RAW_BITMAP