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/sysopt.h"
45 #include "wx/dcprint.h"
46 #include "wx/module.h"
47 #include "wx/dynload.h"
49 #ifdef wxHAVE_RAW_BITMAP
50 #include "wx/rawbmp.h"
55 #include "wx/msw/wrapcdlg.h"
61 #define AC_SRC_ALPHA 1
64 /* Quaternary raster codes */
66 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
69 // apparently with MicroWindows it is possible that HDC is 0 so we have to
70 // check for this ourselves
72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
75 #define WXMICROWIN_CHECK_HDC
76 #define WXMICROWIN_CHECK_HDC_RET(x)
79 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 static const int MM_POINTS
= 9;
88 static const int MM_METRIC
= 10;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
107 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
108 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
109 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
111 #define XLOG2DEV(x) (x)
112 #define YLOG2DEV(y) (y)
113 #define XDEV2LOG(x) (x)
114 #define YDEV2LOG(y) (y)
117 // ---------------------------------------------------------------------------
119 // ---------------------------------------------------------------------------
121 // convert degrees to radians
122 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
124 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
126 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
127 // to pass it to this function but as we already have it at the point
128 // of call anyhow we do
130 // return true if we could draw the bitmap in one way or the other, false
132 static bool AlphaBlt(HDC hdcDst
,
133 int x
, int y
, int w
, int h
,
135 const wxBitmap
& bmpSrc
);
137 #ifdef wxHAVE_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement
140 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
147 // instead of duplicating the same code which sets and then restores text
148 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
149 // encapsulate this in a small helper class
151 // wxColourChanger: changes the text colours in the ctor if required and
152 // restores them in the dtor
153 class wxColourChanger
156 wxColourChanger(wxDC
& dc
);
162 COLORREF m_colFgOld
, m_colBgOld
;
166 DECLARE_NO_COPY_CLASS(wxColourChanger
)
169 // this class saves the old stretch blit mode during its life time
170 class StretchBltModeChanger
173 StretchBltModeChanger(HDC hdc
, int mode
)
177 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
179 wxLogLastError(_T("SetStretchBltMode"));
185 ~StretchBltModeChanger()
188 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
189 wxLogLastError(_T("SetStretchBltMode"));
198 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
201 // ===========================================================================
203 // ===========================================================================
205 // ----------------------------------------------------------------------------
207 // ----------------------------------------------------------------------------
209 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
211 const wxBrush
& brush
= dc
.GetBrush();
212 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
214 HDC hdc
= GetHdcOf(dc
);
215 m_colFgOld
= ::GetTextColor(hdc
);
216 m_colBgOld
= ::GetBkColor(hdc
);
218 // note that Windows convention is opposite to wxWidgets one, this is
219 // why text colour becomes the background one and vice versa
220 const wxColour
& colFg
= dc
.GetTextForeground();
223 ::SetBkColor(hdc
, colFg
.GetPixel());
226 const wxColour
& colBg
= dc
.GetTextBackground();
229 ::SetTextColor(hdc
, colBg
.GetPixel());
233 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
236 // flag which telsl us to undo changes in the dtor
241 // nothing done, nothing to undo
246 wxColourChanger::~wxColourChanger()
250 // restore the colours we changed
251 HDC hdc
= GetHdcOf(m_dc
);
253 ::SetBkMode(hdc
, TRANSPARENT
);
254 ::SetTextColor(hdc
, m_colFgOld
);
255 ::SetBkColor(hdc
, m_colBgOld
);
259 // ---------------------------------------------------------------------------
261 // ---------------------------------------------------------------------------
263 // Default constructor
274 #endif // wxUSE_PALETTE
284 SelectOldObjects(m_hDC
);
286 // if we own the HDC, we delete it, otherwise we just release it
290 ::DeleteDC(GetHdc());
292 else // we don't own our HDC
296 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
300 // Must have been a wxScreenDC
301 ::ReleaseDC((HWND
) NULL
, GetHdc());
307 // This will select current objects out of the DC,
308 // which is what you have to do before deleting the
310 void wxDC::SelectOldObjects(WXHDC dc
)
316 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
318 if (m_selectedBitmap
.Ok())
320 m_selectedBitmap
.SetSelectedInto(NULL
);
327 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
332 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
337 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
344 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
347 #endif // wxUSE_PALETTE
350 m_brush
= wxNullBrush
;
353 m_palette
= wxNullPalette
;
354 #endif // wxUSE_PALETTE
356 m_backgroundBrush
= wxNullBrush
;
357 m_selectedBitmap
= wxNullBitmap
;
360 // ---------------------------------------------------------------------------
362 // ---------------------------------------------------------------------------
364 void wxDC::UpdateClipBox()
369 ::GetClipBox(GetHdc(), &rect
);
371 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
372 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
373 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
374 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
378 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
380 // check if we should try to retrieve the clipping region possibly not set
381 // by our SetClippingRegion() but preset by Windows:this can only happen
382 // when we're associated with an existing HDC usign SetHDC(), see there
383 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
385 wxDC
*self
= wxConstCast(this, wxDC
);
386 self
->UpdateClipBox();
388 if ( !m_clipX1
&& !m_clipX2
)
389 self
->m_clipping
= false;
392 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
395 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
396 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
398 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
402 // note that we combine the new clipping region with the existing one: this
403 // is compatible with what the other ports do and is the documented
404 // behaviour now (starting with 2.3.3)
405 #if defined(__WXWINCE__)
407 if ( !::GetClipBox(GetHdc(), &rectClip
) )
410 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
411 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
412 rectClip
.right
, rectClip
.bottom
);
414 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
416 ::SelectClipRgn(GetHdc(), hrgnDest
);
419 ::DeleteObject(hrgnClipOld
);
420 ::DeleteObject(hrgnDest
);
422 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
424 wxLogLastError(_T("ExtSelectClipRgn"));
428 #endif // WinCE/!WinCE
435 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
437 // the region coords are always the device ones, so do the translation
440 // FIXME: possible +/-1 error here, to check!
441 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
443 LogicalToDeviceX(x
+ w
),
444 LogicalToDeviceY(y
+ h
));
447 wxLogLastError(_T("CreateRectRgn"));
451 SetClippingHrgn((WXHRGN
)hrgn
);
453 ::DeleteObject(hrgn
);
457 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
459 SetClippingHrgn(region
.GetHRGN());
462 void wxDC::DestroyClippingRegion()
466 if (m_clipping
&& m_hDC
)
468 // TODO: this should restore the previous clipping region,
469 // so that OnPaint processing works correctly, and the update
470 // clipping region doesn't get destroyed after the first
471 // DestroyClippingRegion.
472 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
473 ::SelectClipRgn(GetHdc(), rgn
);
477 wxDCBase::DestroyClippingRegion();
480 // ---------------------------------------------------------------------------
481 // query capabilities
482 // ---------------------------------------------------------------------------
484 bool wxDC::CanDrawBitmap() const
489 bool wxDC::CanGetTextExtent() const
491 #ifdef __WXMICROWIN__
492 // TODO Extend MicroWindows' GetDeviceCaps function
495 // What sort of display is it?
496 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
498 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
502 int wxDC::GetDepth() const
504 WXMICROWIN_CHECK_HDC_RET(16)
506 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
509 // ---------------------------------------------------------------------------
511 // ---------------------------------------------------------------------------
520 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
524 // No, I think we should simply ignore this if printing on e.g.
526 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
527 if (!m_selectedBitmap
.Ok())
530 rect
.left
= 0; rect
.top
= 0;
531 rect
.right
= m_selectedBitmap
.GetWidth();
532 rect
.bottom
= m_selectedBitmap
.GetHeight();
536 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
539 DWORD colour
= ::GetBkColor(GetHdc());
540 HBRUSH brush
= ::CreateSolidBrush(colour
);
541 ::FillRect(GetHdc(), &rect
, brush
);
542 ::DeleteObject(brush
);
545 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
546 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
548 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
550 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
551 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
552 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
553 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
557 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
567 WXMICROWIN_CHECK_HDC_RET(false)
569 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
571 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
572 : FLOODFILLBORDER
) ) ;
575 // quoting from the MSDN docs:
577 // Following are some of the reasons this function might fail:
579 // * The filling could not be completed.
580 // * The specified point has the boundary color specified by the
581 // crColor parameter (if FLOODFILLBORDER was requested).
582 // * The specified point does not have the color specified by
583 // crColor (if FLOODFILLSURFACE was requested)
584 // * The point is outside the clipping region that is, it is not
585 // visible on the device.
587 wxLogLastError(wxT("ExtFloodFill"));
590 CalcBoundingBox(x
, y
);
596 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
598 WXMICROWIN_CHECK_HDC_RET(false)
600 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
602 // get the color of the pixel
603 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
605 wxRGBToColour(*col
, pixelcolor
);
610 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
614 wxCoord x1
= x
-VIEWPORT_EXTENT
;
615 wxCoord y1
= y
-VIEWPORT_EXTENT
;
616 wxCoord x2
= x
+VIEWPORT_EXTENT
;
617 wxCoord y2
= y
+VIEWPORT_EXTENT
;
619 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
620 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
622 CalcBoundingBox(x1
, y1
);
623 CalcBoundingBox(x2
, y2
);
626 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
630 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
632 CalcBoundingBox(x1
, y1
);
633 CalcBoundingBox(x2
, y2
);
636 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
637 // and ending at (x2, y2)
638 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
639 wxCoord x2
, wxCoord y2
,
640 wxCoord xc
, wxCoord yc
)
643 // Slower emulation since WinCE doesn't support Pie and Arc
644 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
645 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
646 if( y1
>yc
) sa
= -sa
; // below center
647 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
648 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
653 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
657 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
658 wxCoord r
= (wxCoord
)radius
;
660 // treat the special case of full circle separately
661 if ( x1
== x2
&& y1
== y2
)
663 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
667 wxCoord xx1
= XLOG2DEV(x1
);
668 wxCoord yy1
= YLOG2DEV(y1
);
669 wxCoord xx2
= XLOG2DEV(x2
);
670 wxCoord yy2
= YLOG2DEV(y2
);
671 wxCoord xxc
= XLOG2DEV(xc
);
672 wxCoord yyc
= YLOG2DEV(yc
);
673 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
675 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
676 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
677 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
678 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
680 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
682 // Have to add 1 to bottom-right corner of rectangle
683 // to make semi-circles look right (crooked line otherwise).
684 // Unfortunately this is not a reliable method, depends
685 // on the size of shape.
686 // TODO: figure out why this happens!
687 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
691 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
694 CalcBoundingBox(xc
- r
, yc
- r
);
695 CalcBoundingBox(xc
+ r
, yc
+ r
);
699 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
700 wxCoord width
, wxCoord height
)
704 wxCoord x2
= x1
+ width
,
707 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
715 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
717 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
719 #else // Symantec-MicroWin
721 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
722 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
723 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
724 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
725 ::SetROP2(GetHdc(), R2_COPYPEN
);
726 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
727 MoveToEx(GetHdc(), x1
, y1
, NULL
);
728 LineTo(GetHdc(), x2
, y2
);
729 MoveToEx(GetHdc(), x2
, y1
, NULL
);
730 LineTo(GetHdc(), x1
, y2
);
731 ::SelectObject(GetHdc(), hPenOld
);
732 ::SelectObject(GetHdc(), hBrushOld
);
733 ::DeleteObject(blackPen
);
734 #endif // Win32/Symantec-MicroWin
736 CalcBoundingBox(x1
, y1
);
737 CalcBoundingBox(x2
, y2
);
740 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
744 COLORREF color
= 0x00ffffff;
747 color
= m_pen
.GetColour().GetPixel();
750 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
752 CalcBoundingBox(x
, y
);
755 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
759 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
761 // Do things less efficiently if we have offsets
762 if (xoffset
!= 0 || yoffset
!= 0)
764 POINT
*cpoints
= new POINT
[n
];
766 for (i
= 0; i
< n
; i
++)
768 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
769 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
771 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
774 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
776 wxUnusedVar(fillStyle
);
778 (void)Polygon(GetHdc(), cpoints
, n
);
780 SetPolyFillMode(GetHdc(),prev
);
787 for (i
= 0; i
< n
; i
++)
788 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
791 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
793 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
795 SetPolyFillMode(GetHdc(),prev
);
801 wxDC::DoDrawPolyPolygon(int n
,
809 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
813 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
815 for (i
= cnt
= 0; i
< n
; i
++)
818 // Do things less efficiently if we have offsets
819 if (xoffset
!= 0 || yoffset
!= 0)
821 POINT
*cpoints
= new POINT
[cnt
];
822 for (i
= 0; i
< cnt
; i
++)
824 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
825 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
827 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
830 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
832 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
834 SetPolyFillMode(GetHdc(),prev
);
840 for (i
= 0; i
< cnt
; i
++)
841 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
844 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
846 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
848 SetPolyFillMode(GetHdc(),prev
);
855 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
859 // Do things less efficiently if we have offsets
860 if (xoffset
!= 0 || yoffset
!= 0)
862 POINT
*cpoints
= new POINT
[n
];
864 for (i
= 0; i
< n
; i
++)
866 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
867 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
869 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
871 (void)Polyline(GetHdc(), cpoints
, n
);
877 for (i
= 0; i
< n
; i
++)
878 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
880 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
884 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
888 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
890 wxCoord x2
= x
+ width
;
891 wxCoord y2
= y
+ height
;
893 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
896 rect
.left
= XLOG2DEV(x
);
897 rect
.top
= YLOG2DEV(y
);
898 rect
.right
= XLOG2DEV(x2
);
899 rect
.bottom
= YLOG2DEV(y2
);
900 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
904 // Windows draws the filled rectangles without outline (i.e. drawn with a
905 // transparent pen) one pixel smaller in both directions and we want them
906 // to have the same size regardless of which pen is used - adjust
908 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
909 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
911 // Apparently not needed for WinCE (see e.g. Life! demo)
918 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
922 CalcBoundingBox(x
, y
);
923 CalcBoundingBox(x2
, y2
);
926 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
930 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
932 // Now, a negative radius value is interpreted to mean
933 // 'the proportion of the smallest X or Y dimension'
937 double smallest
= (width
< height
) ? width
: height
;
938 radius
= (- radius
* smallest
);
941 wxCoord x2
= (x
+width
);
942 wxCoord y2
= (y
+height
);
944 // Windows draws the filled rectangles without outline (i.e. drawn with a
945 // transparent pen) one pixel smaller in both directions and we want them
946 // to have the same size regardless of which pen is used - adjust
947 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
953 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
954 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
956 CalcBoundingBox(x
, y
);
957 CalcBoundingBox(x2
, y2
);
960 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
964 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
966 wxCoord x2
= (x
+width
);
967 wxCoord y2
= (y
+height
);
969 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
971 CalcBoundingBox(x
, y
);
972 CalcBoundingBox(x2
, y2
);
975 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
976 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
979 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
984 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
989 int rx1
= XLOG2DEV(x
+w
/2);
990 int ry1
= YLOG2DEV(y
+h
/2);
997 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
998 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
999 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1000 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1002 // draw pie with NULL_PEN first and then outline otherwise a line is
1003 // drawn from the start and end points to the centre
1004 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1007 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1008 rx1
, ry1
, rx2
, ry2
);
1012 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1013 rx1
, ry1
-1, rx2
, ry2
-1);
1016 ::SelectObject(GetHdc(), hpenOld
);
1018 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1019 rx1
, ry1
, rx2
, ry2
);
1021 CalcBoundingBox(x
, y
);
1022 CalcBoundingBox(x2
, y2
);
1026 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1028 WXMICROWIN_CHECK_HDC
1030 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1033 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1035 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1038 CalcBoundingBox(x
, y
);
1039 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1042 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1044 WXMICROWIN_CHECK_HDC
1046 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1048 int width
= bmp
.GetWidth(),
1049 height
= bmp
.GetHeight();
1051 HBITMAP hbmpMask
= 0;
1054 HPALETTE oldPal
= 0;
1055 #endif // wxUSE_PALETTE
1057 if ( bmp
.HasAlpha() )
1060 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1062 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1068 wxMask
*mask
= bmp
.GetMask();
1070 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1074 // don't give assert here because this would break existing
1075 // programs - just silently ignore useMask parameter
1082 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1084 // On some systems, MaskBlt succeeds yet is much much slower
1085 // than the wxWidgets fall-back implementation. So we need
1086 // to be able to switch this on and off at runtime.
1088 #if wxUSE_SYSTEM_OPTIONS
1089 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1093 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1094 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1096 wxPalette
*pal
= bmp
.GetPalette();
1097 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1099 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1100 ::RealizePalette(hdcMem
);
1102 #endif // wxUSE_PALETTE
1104 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1107 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1111 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1112 #endif // wxUSE_PALETTE
1114 ::SelectObject(hdcMem
, hOldBitmap
);
1121 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1124 memDC
.SelectObject(bmp
);
1126 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1128 memDC
.SelectObject(wxNullBitmap
);
1131 else // no mask, just use BitBlt()
1134 HDC memdc
= ::CreateCompatibleDC( cdc
);
1135 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1137 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1139 COLORREF old_textground
= ::GetTextColor(GetHdc());
1140 COLORREF old_background
= ::GetBkColor(GetHdc());
1141 if (m_textForegroundColour
.Ok())
1143 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1145 if (m_textBackgroundColour
.Ok())
1147 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1151 wxPalette
*pal
= bmp
.GetPalette();
1152 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1154 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1155 ::RealizePalette(memdc
);
1157 #endif // wxUSE_PALETTE
1159 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1160 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1164 ::SelectPalette(memdc
, oldPal
, FALSE
);
1165 #endif // wxUSE_PALETTE
1167 ::SelectObject( memdc
, hOldBitmap
);
1168 ::DeleteDC( memdc
);
1170 ::SetTextColor(GetHdc(), old_textground
);
1171 ::SetBkColor(GetHdc(), old_background
);
1175 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1177 WXMICROWIN_CHECK_HDC
1179 DrawAnyText(text
, x
, y
);
1181 // update the bounding box
1182 CalcBoundingBox(x
, y
);
1185 GetTextExtent(text
, &w
, &h
);
1186 CalcBoundingBox(x
+ w
, y
+ h
);
1189 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1191 WXMICROWIN_CHECK_HDC
1193 // prepare for drawing the text
1194 if ( m_textForegroundColour
.Ok() )
1195 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1197 DWORD old_background
= 0;
1198 if ( m_textBackgroundColour
.Ok() )
1200 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1203 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1207 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1208 text
.c_str(), text
.length(), NULL
) == 0 )
1210 wxLogLastError(wxT("TextOut"));
1213 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1214 text
.c_str(), text
.length()) == 0 )
1216 wxLogLastError(wxT("TextOut"));
1220 // restore the old parameters (text foreground colour may be left because
1221 // it never is set to anything else, but background should remain
1222 // transparent even if we just drew an opaque string)
1223 if ( m_textBackgroundColour
.Ok() )
1224 (void)SetBkColor(GetHdc(), old_background
);
1226 SetBkMode(GetHdc(), TRANSPARENT
);
1229 void wxDC::DoDrawRotatedText(const wxString
& text
,
1230 wxCoord x
, wxCoord y
,
1233 WXMICROWIN_CHECK_HDC
1235 // we test that we have some font because otherwise we should still use the
1236 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1237 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1238 // font for drawing rotated fonts unfortunately)
1239 if ( (angle
== 0.0) && m_font
.Ok() )
1241 DoDrawText(text
, x
, y
);
1243 #ifndef __WXMICROWIN__
1246 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1247 // because it's not TrueType and so can't have non zero
1248 // orientation/escapement under Win9x
1249 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1250 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1252 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1254 wxLogLastError(wxT("GetObject(hfont)"));
1257 // GDI wants the angle in tenth of degree
1258 long angle10
= (long)(angle
* 10);
1259 lf
.lfEscapement
= angle10
;
1260 lf
. lfOrientation
= angle10
;
1262 hfont
= ::CreateFontIndirect(&lf
);
1265 wxLogLastError(wxT("CreateFont"));
1269 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1271 DrawAnyText(text
, x
, y
);
1273 (void)::SelectObject(GetHdc(), hfontOld
);
1274 (void)::DeleteObject(hfont
);
1277 // call the bounding box by adding all four vertices of the rectangle
1278 // containing the text to it (simpler and probably not slower than
1279 // determining which of them is really topmost/leftmost/...)
1281 GetTextExtent(text
, &w
, &h
);
1283 double rad
= DegToRad(angle
);
1285 // "upper left" and "upper right"
1286 CalcBoundingBox(x
, y
);
1287 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1289 // "bottom left" and "bottom right"
1290 x
+= (wxCoord
)(h
*sin(rad
));
1291 y
+= (wxCoord
)(h
*cos(rad
));
1292 CalcBoundingBox(x
, y
);
1293 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1298 // ---------------------------------------------------------------------------
1300 // ---------------------------------------------------------------------------
1304 void wxDC::DoSelectPalette(bool realize
)
1306 WXMICROWIN_CHECK_HDC
1308 // Set the old object temporarily, in case the assignment deletes an object
1309 // that's not yet selected out.
1312 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1316 if ( m_palette
.Ok() )
1318 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1319 GetHpaletteOf(m_palette
),
1322 m_oldPalette
= (WXHPALETTE
) oldPal
;
1325 ::RealizePalette(GetHdc());
1329 void wxDC::SetPalette(const wxPalette
& palette
)
1333 m_palette
= palette
;
1334 DoSelectPalette(true);
1338 void wxDC::InitializePalette()
1340 if ( wxDisplayDepth() <= 8 )
1342 // look for any window or parent that has a custom palette. If any has
1343 // one then we need to use it in drawing operations
1344 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1346 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1347 if ( m_hasCustomPalette
)
1349 m_palette
= win
->GetPalette();
1351 // turn on MSW translation for this palette
1357 #endif // wxUSE_PALETTE
1359 // SetFont/Pen/Brush() really ask to be implemented as a single template
1360 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1362 void wxDC::SetFont(const wxFont
& font
)
1364 WXMICROWIN_CHECK_HDC
1366 if ( font
== m_font
)
1371 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1372 if ( hfont
== HGDI_ERROR
)
1374 wxLogLastError(_T("SelectObject(font)"));
1379 m_oldFont
= (WXHPEN
)hfont
;
1384 else // invalid font, reset the current font
1388 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1390 wxLogLastError(_T("SelectObject(old font)"));
1396 m_font
= wxNullFont
;
1400 void wxDC::SetPen(const wxPen
& pen
)
1402 WXMICROWIN_CHECK_HDC
1409 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1410 if ( hpen
== HGDI_ERROR
)
1412 wxLogLastError(_T("SelectObject(pen)"));
1417 m_oldPen
= (WXHPEN
)hpen
;
1422 else // invalid pen, reset the current pen
1426 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1428 wxLogLastError(_T("SelectObject(old pen)"));
1438 void wxDC::SetBrush(const wxBrush
& brush
)
1440 WXMICROWIN_CHECK_HDC
1442 if ( brush
== m_brush
)
1447 // we must make sure the brush is aligned with the logical coordinates
1448 // before selecting it
1449 wxBitmap
*stipple
= brush
.GetStipple();
1450 if ( stipple
&& stipple
->Ok() )
1452 if ( !::SetBrushOrgEx
1455 m_deviceOriginX
% stipple
->GetWidth(),
1456 m_deviceOriginY
% stipple
->GetHeight(),
1457 NULL
// [out] previous brush origin
1460 wxLogLastError(_T("SetBrushOrgEx()"));
1464 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1465 if ( hbrush
== HGDI_ERROR
)
1467 wxLogLastError(_T("SelectObject(brush)"));
1472 m_oldBrush
= (WXHPEN
)hbrush
;
1477 else // invalid brush, reset the current brush
1481 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1483 wxLogLastError(_T("SelectObject(old brush)"));
1489 m_brush
= wxNullBrush
;
1493 void wxDC::SetBackground(const wxBrush
& brush
)
1495 WXMICROWIN_CHECK_HDC
1497 m_backgroundBrush
= brush
;
1499 if ( m_backgroundBrush
.Ok() )
1501 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1505 void wxDC::SetBackgroundMode(int mode
)
1507 WXMICROWIN_CHECK_HDC
1509 m_backgroundMode
= mode
;
1511 // SetBackgroundColour now only refers to text background
1512 // and m_backgroundMode is used there
1515 void wxDC::SetLogicalFunction(int function
)
1517 WXMICROWIN_CHECK_HDC
1519 m_logicalFunction
= function
;
1524 void wxDC::SetRop(WXHDC dc
)
1526 if ( !dc
|| m_logicalFunction
< 0 )
1531 switch (m_logicalFunction
)
1533 case wxCLEAR
: rop
= R2_BLACK
; break;
1534 case wxXOR
: rop
= R2_XORPEN
; break;
1535 case wxINVERT
: rop
= R2_NOT
; break;
1536 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1537 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1538 case wxCOPY
: rop
= R2_COPYPEN
; break;
1539 case wxAND
: rop
= R2_MASKPEN
; break;
1540 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1541 case wxNO_OP
: rop
= R2_NOP
; break;
1542 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1543 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1544 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1545 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1546 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1547 case wxOR
: rop
= R2_MERGEPEN
; break;
1548 case wxSET
: rop
= R2_WHITE
; break;
1551 wxFAIL_MSG( wxT("unsupported logical function") );
1555 SetROP2(GetHdc(), rop
);
1558 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1560 // We might be previewing, so return true to let it continue.
1568 void wxDC::StartPage()
1572 void wxDC::EndPage()
1576 // ---------------------------------------------------------------------------
1578 // ---------------------------------------------------------------------------
1580 wxCoord
wxDC::GetCharHeight() const
1582 WXMICROWIN_CHECK_HDC_RET(0)
1584 TEXTMETRIC lpTextMetric
;
1586 GetTextMetrics(GetHdc(), &lpTextMetric
);
1588 return lpTextMetric
.tmHeight
;
1591 wxCoord
wxDC::GetCharWidth() const
1593 WXMICROWIN_CHECK_HDC_RET(0)
1595 TEXTMETRIC lpTextMetric
;
1597 GetTextMetrics(GetHdc(), &lpTextMetric
);
1599 return lpTextMetric
.tmAveCharWidth
;
1602 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1603 wxCoord
*descent
, wxCoord
*externalLeading
,
1606 #ifdef __WXMICROWIN__
1611 if (descent
) *descent
= 0;
1612 if (externalLeading
) *externalLeading
= 0;
1615 #endif // __WXMICROWIN__
1620 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1622 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1624 else // don't change the font
1632 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1633 GetTextMetrics(GetHdc(), &tm
);
1640 *descent
= tm
.tmDescent
;
1641 if (externalLeading
)
1642 *externalLeading
= tm
.tmExternalLeading
;
1646 ::SelectObject(GetHdc(), hfontOld
);
1651 // Each element of the array will be the width of the string up to and
1652 // including the coresoponding character in text.
1654 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1656 static int maxLenText
= -1;
1657 static int maxWidth
= -1;
1660 int stlen
= text
.Length();
1662 if (maxLenText
== -1)
1664 // Win9x and WinNT+ have different limits
1665 int version
= wxGetOsVersion();
1666 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1667 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1671 widths
.Add(0, stlen
); // fill the array with zeros
1673 if (!::GetTextExtentExPoint(GetHdc(),
1674 text
.c_str(), // string to check
1675 wxMin(stlen
, maxLenText
),
1677 &fit
, // [out] count of chars
1679 &widths
[0], // array to fill
1683 wxLogLastError(wxT("GetTextExtentExPoint"));
1693 void wxDC::SetMapMode(int mode
)
1695 WXMICROWIN_CHECK_HDC
1697 m_mappingMode
= mode
;
1699 if ( mode
== wxMM_TEXT
)
1702 m_logicalScaleY
= 1.0;
1704 else // need to do some calculations
1706 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1707 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1708 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1709 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1711 if ( (mm_width
== 0) || (mm_height
== 0) )
1713 // we can't calculate mm2pixels[XY] then!
1717 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1718 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1723 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1724 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1728 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1729 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1733 m_logicalScaleX
= mm2pixelsX
;
1734 m_logicalScaleY
= mm2pixelsY
;
1738 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1739 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1743 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1747 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1748 // cases we could do with MM_TEXT and in the remaining 0.9% with
1749 // MM_ISOTROPIC (TODO!)
1751 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1753 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1754 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1756 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1757 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1759 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1760 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1764 void wxDC::SetUserScale(double x
, double y
)
1766 WXMICROWIN_CHECK_HDC
1768 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1774 this->SetMapMode(m_mappingMode
);
1777 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1779 WXMICROWIN_CHECK_HDC
1782 int signX
= xLeftRight
? 1 : -1,
1783 signY
= yBottomUp
? -1 : 1;
1785 if ( signX
!= m_signX
|| signY
!= m_signY
)
1790 SetMapMode(m_mappingMode
);
1793 wxUnusedVar(xLeftRight
);
1794 wxUnusedVar(yBottomUp
);
1798 void wxDC::SetSystemScale(double x
, double y
)
1800 WXMICROWIN_CHECK_HDC
1802 if ( x
== m_scaleX
&& y
== m_scaleY
)
1809 SetMapMode(m_mappingMode
);
1813 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1815 WXMICROWIN_CHECK_HDC
1817 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1820 m_logicalOriginX
= x
;
1821 m_logicalOriginY
= y
;
1824 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1828 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1830 WXMICROWIN_CHECK_HDC
1832 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1835 m_deviceOriginX
= x
;
1836 m_deviceOriginY
= y
;
1839 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1843 // ---------------------------------------------------------------------------
1844 // coordinates transformations
1845 // ---------------------------------------------------------------------------
1847 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1849 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1852 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1854 // axis orientation is not taken into account for conversion of a distance
1855 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1858 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1860 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1863 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1865 // axis orientation is not taken into account for conversion of a distance
1866 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1869 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1871 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1874 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1876 // axis orientation is not taken into account for conversion of a distance
1877 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1880 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1882 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1885 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1887 // axis orientation is not taken into account for conversion of a distance
1888 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1891 // ---------------------------------------------------------------------------
1893 // ---------------------------------------------------------------------------
1895 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1896 wxCoord width
, wxCoord height
,
1897 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1898 int rop
, bool useMask
,
1899 wxCoord xsrcMask
, wxCoord ysrcMask
)
1901 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1903 WXMICROWIN_CHECK_HDC_RET(false)
1905 // if either the source or destination has alpha channel, we must use
1906 // AlphaBlt() as other function don't handle it correctly
1907 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1908 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1909 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1911 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1912 GetHdcOf(*source
), bmpSrc
) )
1916 wxMask
*mask
= NULL
;
1919 mask
= bmpSrc
.GetMask();
1921 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1923 // don't give assert here because this would break existing
1924 // programs - just silently ignore useMask parameter
1929 if (xsrcMask
== -1 && ysrcMask
== -1)
1931 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1934 COLORREF old_textground
= ::GetTextColor(GetHdc());
1935 COLORREF old_background
= ::GetBkColor(GetHdc());
1936 if (m_textForegroundColour
.Ok())
1938 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1940 if (m_textBackgroundColour
.Ok())
1942 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1948 case wxXOR
: dwRop
= SRCINVERT
; break;
1949 case wxINVERT
: dwRop
= DSTINVERT
; break;
1950 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1951 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1952 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1953 case wxSET
: dwRop
= WHITENESS
; break;
1954 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1955 case wxAND
: dwRop
= SRCAND
; break;
1956 case wxOR
: dwRop
= SRCPAINT
; break;
1957 case wxEQUIV
: dwRop
= 0x00990066; break;
1958 case wxNAND
: dwRop
= 0x007700E6; break;
1959 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1960 case wxCOPY
: dwRop
= SRCCOPY
; break;
1961 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1962 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1963 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1965 wxFAIL_MSG( wxT("unsupported logical function") );
1969 bool success
= false;
1974 // we want the part of the image corresponding to the mask to be
1975 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1976 // meaning of fg and bg is inverted which corresponds to wxWin notion
1977 // of the mask which is also contrary to the Windows one)
1979 // On some systems, MaskBlt succeeds yet is much much slower
1980 // than the wxWidgets fall-back implementation. So we need
1981 // to be able to switch this on and off at runtime.
1982 #if wxUSE_SYSTEM_OPTIONS
1983 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1989 xdest
, ydest
, width
, height
,
1992 (HBITMAP
)mask
->GetMaskBitmap(),
1994 MAKEROP4(dwRop
, DSTCOPY
)
2001 // Blit bitmap with mask
2004 HBITMAP buffer_bmap
;
2006 #if wxUSE_DC_CACHEING
2007 // create a temp buffer bitmap and DCs to access it and the mask
2008 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2009 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2011 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2012 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2014 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2017 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2018 #else // !wxUSE_DC_CACHEING
2019 // create a temp buffer bitmap and DCs to access it and the mask
2020 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2021 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2022 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2023 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2024 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2025 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2027 // copy dest to buffer
2028 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2029 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2031 wxLogLastError(wxT("BitBlt"));
2034 // copy src to buffer using selected raster op
2035 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2036 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2038 wxLogLastError(wxT("BitBlt"));
2041 // set masked area in buffer to BLACK (pixel value 0)
2042 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2043 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2044 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2045 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2047 wxLogLastError(wxT("BitBlt"));
2050 // set unmasked area in dest to BLACK
2051 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2052 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2053 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2054 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2056 wxLogLastError(wxT("BitBlt"));
2058 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2059 ::SetTextColor(GetHdc(), prevCol
);
2061 // OR buffer to dest
2062 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2063 (int)width
, (int)height
,
2064 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2067 wxLogLastError(wxT("BitBlt"));
2070 // tidy up temporary DCs and bitmap
2071 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2072 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2074 #if !wxUSE_DC_CACHEING
2076 ::DeleteDC(dc_mask
);
2077 ::DeleteDC(dc_buffer
);
2078 ::DeleteObject(buffer_bmap
);
2083 else // no mask, just BitBlt() it
2085 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2086 // use StretchBlt() if available and finally fall back to BitBlt()
2088 // FIXME: use appropriate WinCE functions
2090 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2091 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2096 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2098 &ds
) == sizeof(ds
) )
2100 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2102 // Figure out what co-ordinate system we're supposed to specify
2104 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2108 ysrc
= hDIB
- (ysrc
+ height
);
2111 if ( ::StretchDIBits(GetHdc(),
2117 (LPBITMAPINFO
)&ds
.dsBmih
,
2120 ) == (int)GDI_ERROR
)
2122 // On Win9x this API fails most (all?) of the time, so
2123 // logging it becomes quite distracting. Since it falls
2124 // back to the code below this is not really serious, so
2126 //wxLogLastError(wxT("StretchDIBits"));
2135 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2140 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2146 xdest
, ydest
, width
, height
,
2148 xsrc
, ysrc
, width
, height
,
2152 wxLogLastError(_T("StretchBlt"));
2166 (int)width
, (int)height
,
2172 wxLogLastError(_T("BitBlt"));
2181 ::SetTextColor(GetHdc(), old_textground
);
2182 ::SetBkColor(GetHdc(), old_background
);
2187 void wxDC::DoGetSize(int *w
, int *h
) const
2189 WXMICROWIN_CHECK_HDC
2191 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2192 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2195 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2197 WXMICROWIN_CHECK_HDC
2199 // if we implement it in terms of DoGetSize() instead of directly using the
2200 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2201 // will also work for wxWindowDC and wxClientDC even though their size is
2202 // not the same as the total size of the screen
2203 int wPixels
, hPixels
;
2204 DoGetSize(&wPixels
, &hPixels
);
2208 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2210 wxCHECK_RET( wTotal
, _T("0 width device?") );
2212 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2217 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2219 wxCHECK_RET( hTotal
, _T("0 height device?") );
2221 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2225 wxSize
wxDC::GetPPI() const
2227 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2229 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2230 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2232 return wxSize(x
, y
);
2235 // For use by wxWidgets only, unless custom units are required.
2236 void wxDC::SetLogicalScale(double x
, double y
)
2238 WXMICROWIN_CHECK_HDC
2240 m_logicalScaleX
= x
;
2241 m_logicalScaleY
= y
;
2244 // ----------------------------------------------------------------------------
2246 // ----------------------------------------------------------------------------
2248 #if wxUSE_DC_CACHEING
2251 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2252 * improve it in due course, either using arrays, or simply storing pointers to one
2253 * entry for the bitmap, and two for the DCs. -- JACS
2256 wxList
wxDC::sm_bitmapCache
;
2257 wxList
wxDC::sm_dcCache
;
2259 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2268 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2277 wxDCCacheEntry::~wxDCCacheEntry()
2280 ::DeleteObject((HBITMAP
) m_bitmap
);
2282 ::DeleteDC((HDC
) m_dc
);
2285 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2287 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2288 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2291 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2293 if (entry
->m_depth
== depth
)
2295 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2297 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2298 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2299 if ( !entry
->m_bitmap
)
2301 wxLogLastError(wxT("CreateCompatibleBitmap"));
2303 entry
->m_width
= w
; entry
->m_height
= h
;
2309 node
= node
->GetNext();
2311 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2314 wxLogLastError(wxT("CreateCompatibleBitmap"));
2316 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2317 AddToBitmapCache(entry
);
2321 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2323 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2324 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2327 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2329 // Don't return the same one as we already have
2330 if (!notThis
|| (notThis
!= entry
))
2332 if (entry
->m_depth
== depth
)
2338 node
= node
->GetNext();
2340 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2343 wxLogLastError(wxT("CreateCompatibleDC"));
2345 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2346 AddToDCCache(entry
);
2350 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2352 sm_bitmapCache
.Append(entry
);
2355 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2357 sm_dcCache
.Append(entry
);
2360 void wxDC::ClearCache()
2362 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2363 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2366 // Clean up cache at app exit
2367 class wxDCModule
: public wxModule
2370 virtual bool OnInit() { return true; }
2371 virtual void OnExit() { wxDC::ClearCache(); }
2374 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2377 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2379 #endif // wxUSE_DC_CACHEING
2381 // ----------------------------------------------------------------------------
2382 // alpha channel support
2383 // ----------------------------------------------------------------------------
2385 static bool AlphaBlt(HDC hdcDst
,
2386 int x
, int y
, int width
, int height
,
2388 const wxBitmap
& bmp
)
2390 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2391 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2393 // do we have AlphaBlend() and company in the headers?
2394 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2395 // yes, now try to see if we have it during run-time
2396 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2397 HDC
,int,int,int,int,
2400 // bitmaps can be drawn only from GUI thread so there is no need to
2401 // protect this static variable from multiple threads
2402 static bool s_triedToLoad
= false;
2403 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2404 if ( !s_triedToLoad
)
2406 s_triedToLoad
= true;
2408 // don't give errors about the DLL being unavailable, we're
2409 // prepared to handle this
2412 wxDynamicLibrary
dll(_T("msimg32.dll"));
2413 if ( dll
.IsLoaded() )
2415 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2416 if ( pfnAlphaBlend
)
2418 // we must keep the DLL loaded if we want to be able to
2419 // call AlphaBlend() so just never unload it at all, not a
2426 if ( pfnAlphaBlend
)
2429 bf
.BlendOp
= AC_SRC_OVER
;
2431 bf
.SourceConstantAlpha
= 0xff;
2432 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2434 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2435 hdcSrc
, 0, 0, width
, height
,
2438 // skip wxAlphaBlend() call below
2442 wxLogLastError(_T("AlphaBlend"));
2444 #endif // defined(AC_SRC_OVER)
2446 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2448 #ifdef wxHAVE_RAW_BITMAP
2449 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2452 #else // !wxHAVE_RAW_BITMAP
2453 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2454 // alpha but at least something will be shown like this)
2457 #endif // wxHAVE_RAW_BITMAP
2461 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2462 #ifdef wxHAVE_RAW_BITMAP
2465 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2467 // get the destination DC pixels
2468 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2470 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2472 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2474 wxLogLastError(_T("BitBlt"));
2477 // combine them with the source bitmap using alpha
2478 wxAlphaPixelData
dataDst(bmpDst
),
2479 dataSrc((wxBitmap
&)bmpSrc
);
2481 wxCHECK_RET( dataDst
&& dataSrc
,
2482 _T("failed to get raw data in wxAlphaBlend") );
2484 wxAlphaPixelData::Iterator
pDst(dataDst
),
2487 for ( int y
= 0; y
< h
; y
++ )
2489 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2490 pSrcRowStart
= pSrc
;
2492 for ( int x
= 0; x
< w
; x
++ )
2494 // note that source bitmap uses premultiplied alpha (as required by
2495 // the real AlphaBlend)
2496 const unsigned beta
= 255 - pSrc
.Alpha();
2498 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2499 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2500 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2506 pDst
= pDstRowStart
;
2507 pSrc
= pSrcRowStart
;
2508 pDst
.OffsetY(dataDst
, 1);
2509 pSrc
.OffsetY(dataSrc
, 1);
2512 // and finally blit them back to the destination DC
2513 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2515 wxLogLastError(_T("BitBlt"));
2519 #endif // #ifdef wxHAVE_RAW_BITMAP