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
)
915 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
919 CalcBoundingBox(x
, y
);
920 CalcBoundingBox(x2
, y2
);
923 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
927 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
929 // Now, a negative radius value is interpreted to mean
930 // 'the proportion of the smallest X or Y dimension'
934 double smallest
= (width
< height
) ? width
: height
;
935 radius
= (- radius
* smallest
);
938 wxCoord x2
= (x
+width
);
939 wxCoord y2
= (y
+height
);
941 // Windows draws the filled rectangles without outline (i.e. drawn with a
942 // transparent pen) one pixel smaller in both directions and we want them
943 // to have the same size regardless of which pen is used - adjust
944 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
950 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
951 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
953 CalcBoundingBox(x
, y
);
954 CalcBoundingBox(x2
, y2
);
957 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
961 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
963 wxCoord x2
= (x
+width
);
964 wxCoord y2
= (y
+height
);
966 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
968 CalcBoundingBox(x
, y
);
969 CalcBoundingBox(x2
, y2
);
972 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
973 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
976 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
981 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
986 int rx1
= XLOG2DEV(x
+w
/2);
987 int ry1
= YLOG2DEV(y
+h
/2);
994 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
995 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
996 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
997 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
999 // draw pie with NULL_PEN first and then outline otherwise a line is
1000 // drawn from the start and end points to the centre
1001 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1004 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1005 rx1
, ry1
, rx2
, ry2
);
1009 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1010 rx1
, ry1
-1, rx2
, ry2
-1);
1013 ::SelectObject(GetHdc(), hpenOld
);
1015 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1016 rx1
, ry1
, rx2
, ry2
);
1018 CalcBoundingBox(x
, y
);
1019 CalcBoundingBox(x2
, y2
);
1023 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1025 WXMICROWIN_CHECK_HDC
1027 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1030 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1032 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1035 CalcBoundingBox(x
, y
);
1036 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1039 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1041 WXMICROWIN_CHECK_HDC
1043 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1045 int width
= bmp
.GetWidth(),
1046 height
= bmp
.GetHeight();
1048 HBITMAP hbmpMask
= 0;
1051 HPALETTE oldPal
= 0;
1052 #endif // wxUSE_PALETTE
1054 if ( bmp
.HasAlpha() )
1057 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1059 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1065 wxMask
*mask
= bmp
.GetMask();
1067 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1071 // don't give assert here because this would break existing
1072 // programs - just silently ignore useMask parameter
1079 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1081 // On some systems, MaskBlt succeeds yet is much much slower
1082 // than the wxWidgets fall-back implementation. So we need
1083 // to be able to switch this on and off at runtime.
1085 #if wxUSE_SYSTEM_OPTIONS
1086 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1090 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1091 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1093 wxPalette
*pal
= bmp
.GetPalette();
1094 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1096 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1097 ::RealizePalette(hdcMem
);
1099 #endif // wxUSE_PALETTE
1101 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1104 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1108 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1109 #endif // wxUSE_PALETTE
1111 ::SelectObject(hdcMem
, hOldBitmap
);
1118 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1121 memDC
.SelectObject(bmp
);
1123 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1125 memDC
.SelectObject(wxNullBitmap
);
1128 else // no mask, just use BitBlt()
1131 HDC memdc
= ::CreateCompatibleDC( cdc
);
1132 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1134 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1136 COLORREF old_textground
= ::GetTextColor(GetHdc());
1137 COLORREF old_background
= ::GetBkColor(GetHdc());
1138 if (m_textForegroundColour
.Ok())
1140 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1142 if (m_textBackgroundColour
.Ok())
1144 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1148 wxPalette
*pal
= bmp
.GetPalette();
1149 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1151 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1152 ::RealizePalette(memdc
);
1154 #endif // wxUSE_PALETTE
1156 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1157 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1161 ::SelectPalette(memdc
, oldPal
, FALSE
);
1162 #endif // wxUSE_PALETTE
1164 ::SelectObject( memdc
, hOldBitmap
);
1165 ::DeleteDC( memdc
);
1167 ::SetTextColor(GetHdc(), old_textground
);
1168 ::SetBkColor(GetHdc(), old_background
);
1172 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1174 WXMICROWIN_CHECK_HDC
1176 DrawAnyText(text
, x
, y
);
1178 // update the bounding box
1179 CalcBoundingBox(x
, y
);
1182 GetTextExtent(text
, &w
, &h
);
1183 CalcBoundingBox(x
+ w
, y
+ h
);
1186 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1188 WXMICROWIN_CHECK_HDC
1190 // prepare for drawing the text
1191 if ( m_textForegroundColour
.Ok() )
1192 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1194 DWORD old_background
= 0;
1195 if ( m_textBackgroundColour
.Ok() )
1197 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1200 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1204 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1205 text
.c_str(), text
.length(), NULL
) == 0 )
1207 wxLogLastError(wxT("TextOut"));
1210 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1211 text
.c_str(), text
.length()) == 0 )
1213 wxLogLastError(wxT("TextOut"));
1217 // restore the old parameters (text foreground colour may be left because
1218 // it never is set to anything else, but background should remain
1219 // transparent even if we just drew an opaque string)
1220 if ( m_textBackgroundColour
.Ok() )
1221 (void)SetBkColor(GetHdc(), old_background
);
1223 SetBkMode(GetHdc(), TRANSPARENT
);
1226 void wxDC::DoDrawRotatedText(const wxString
& text
,
1227 wxCoord x
, wxCoord y
,
1230 WXMICROWIN_CHECK_HDC
1232 // we test that we have some font because otherwise we should still use the
1233 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1234 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1235 // font for drawing rotated fonts unfortunately)
1236 if ( (angle
== 0.0) && m_font
.Ok() )
1238 DoDrawText(text
, x
, y
);
1240 #ifndef __WXMICROWIN__
1243 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1244 // because it's not TrueType and so can't have non zero
1245 // orientation/escapement under Win9x
1246 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1247 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1249 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1251 wxLogLastError(wxT("GetObject(hfont)"));
1254 // GDI wants the angle in tenth of degree
1255 long angle10
= (long)(angle
* 10);
1256 lf
.lfEscapement
= angle10
;
1257 lf
. lfOrientation
= angle10
;
1259 hfont
= ::CreateFontIndirect(&lf
);
1262 wxLogLastError(wxT("CreateFont"));
1266 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1268 DrawAnyText(text
, x
, y
);
1270 (void)::SelectObject(GetHdc(), hfontOld
);
1271 (void)::DeleteObject(hfont
);
1274 // call the bounding box by adding all four vertices of the rectangle
1275 // containing the text to it (simpler and probably not slower than
1276 // determining which of them is really topmost/leftmost/...)
1278 GetTextExtent(text
, &w
, &h
);
1280 double rad
= DegToRad(angle
);
1282 // "upper left" and "upper right"
1283 CalcBoundingBox(x
, y
);
1284 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1286 // "bottom left" and "bottom right"
1287 x
+= (wxCoord
)(h
*sin(rad
));
1288 y
+= (wxCoord
)(h
*cos(rad
));
1289 CalcBoundingBox(x
, y
);
1290 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1295 // ---------------------------------------------------------------------------
1297 // ---------------------------------------------------------------------------
1301 void wxDC::DoSelectPalette(bool realize
)
1303 WXMICROWIN_CHECK_HDC
1305 // Set the old object temporarily, in case the assignment deletes an object
1306 // that's not yet selected out.
1309 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1313 if ( m_palette
.Ok() )
1315 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1316 GetHpaletteOf(m_palette
),
1319 m_oldPalette
= (WXHPALETTE
) oldPal
;
1322 ::RealizePalette(GetHdc());
1326 void wxDC::SetPalette(const wxPalette
& palette
)
1330 m_palette
= palette
;
1331 DoSelectPalette(true);
1335 void wxDC::InitializePalette()
1337 if ( wxDisplayDepth() <= 8 )
1339 // look for any window or parent that has a custom palette. If any has
1340 // one then we need to use it in drawing operations
1341 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1343 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1344 if ( m_hasCustomPalette
)
1346 m_palette
= win
->GetPalette();
1348 // turn on MSW translation for this palette
1354 #endif // wxUSE_PALETTE
1356 // SetFont/Pen/Brush() really ask to be implemented as a single template
1357 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1359 void wxDC::SetFont(const wxFont
& font
)
1361 WXMICROWIN_CHECK_HDC
1363 if ( font
== m_font
)
1368 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1369 if ( hfont
== HGDI_ERROR
)
1371 wxLogLastError(_T("SelectObject(font)"));
1376 m_oldFont
= (WXHPEN
)hfont
;
1381 else // invalid font, reset the current font
1385 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1387 wxLogLastError(_T("SelectObject(old font)"));
1393 m_font
= wxNullFont
;
1397 void wxDC::SetPen(const wxPen
& pen
)
1399 WXMICROWIN_CHECK_HDC
1406 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1407 if ( hpen
== HGDI_ERROR
)
1409 wxLogLastError(_T("SelectObject(pen)"));
1414 m_oldPen
= (WXHPEN
)hpen
;
1419 else // invalid pen, reset the current pen
1423 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1425 wxLogLastError(_T("SelectObject(old pen)"));
1435 void wxDC::SetBrush(const wxBrush
& brush
)
1437 WXMICROWIN_CHECK_HDC
1439 if ( brush
== m_brush
)
1444 // we must make sure the brush is aligned with the logical coordinates
1445 // before selecting it
1446 wxBitmap
*stipple
= brush
.GetStipple();
1447 if ( stipple
&& stipple
->Ok() )
1449 if ( !::SetBrushOrgEx
1452 m_deviceOriginX
% stipple
->GetWidth(),
1453 m_deviceOriginY
% stipple
->GetHeight(),
1454 NULL
// [out] previous brush origin
1457 wxLogLastError(_T("SetBrushOrgEx()"));
1461 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1462 if ( hbrush
== HGDI_ERROR
)
1464 wxLogLastError(_T("SelectObject(brush)"));
1469 m_oldBrush
= (WXHPEN
)hbrush
;
1474 else // invalid brush, reset the current brush
1478 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1480 wxLogLastError(_T("SelectObject(old brush)"));
1486 m_brush
= wxNullBrush
;
1490 void wxDC::SetBackground(const wxBrush
& brush
)
1492 WXMICROWIN_CHECK_HDC
1494 m_backgroundBrush
= brush
;
1496 if ( m_backgroundBrush
.Ok() )
1498 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1502 void wxDC::SetBackgroundMode(int mode
)
1504 WXMICROWIN_CHECK_HDC
1506 m_backgroundMode
= mode
;
1508 // SetBackgroundColour now only refers to text background
1509 // and m_backgroundMode is used there
1512 void wxDC::SetLogicalFunction(int function
)
1514 WXMICROWIN_CHECK_HDC
1516 m_logicalFunction
= function
;
1521 void wxDC::SetRop(WXHDC dc
)
1523 if ( !dc
|| m_logicalFunction
< 0 )
1528 switch (m_logicalFunction
)
1530 case wxCLEAR
: rop
= R2_BLACK
; break;
1531 case wxXOR
: rop
= R2_XORPEN
; break;
1532 case wxINVERT
: rop
= R2_NOT
; break;
1533 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1534 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1535 case wxCOPY
: rop
= R2_COPYPEN
; break;
1536 case wxAND
: rop
= R2_MASKPEN
; break;
1537 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1538 case wxNO_OP
: rop
= R2_NOP
; break;
1539 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1540 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1541 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1542 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1543 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1544 case wxOR
: rop
= R2_MERGEPEN
; break;
1545 case wxSET
: rop
= R2_WHITE
; break;
1548 wxFAIL_MSG( wxT("unsupported logical function") );
1552 SetROP2(GetHdc(), rop
);
1555 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1557 // We might be previewing, so return true to let it continue.
1565 void wxDC::StartPage()
1569 void wxDC::EndPage()
1573 // ---------------------------------------------------------------------------
1575 // ---------------------------------------------------------------------------
1577 wxCoord
wxDC::GetCharHeight() const
1579 WXMICROWIN_CHECK_HDC_RET(0)
1581 TEXTMETRIC lpTextMetric
;
1583 GetTextMetrics(GetHdc(), &lpTextMetric
);
1585 return lpTextMetric
.tmHeight
;
1588 wxCoord
wxDC::GetCharWidth() const
1590 WXMICROWIN_CHECK_HDC_RET(0)
1592 TEXTMETRIC lpTextMetric
;
1594 GetTextMetrics(GetHdc(), &lpTextMetric
);
1596 return lpTextMetric
.tmAveCharWidth
;
1599 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1600 wxCoord
*descent
, wxCoord
*externalLeading
,
1603 #ifdef __WXMICROWIN__
1608 if (descent
) *descent
= 0;
1609 if (externalLeading
) *externalLeading
= 0;
1612 #endif // __WXMICROWIN__
1617 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1619 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1621 else // don't change the font
1629 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1630 GetTextMetrics(GetHdc(), &tm
);
1637 *descent
= tm
.tmDescent
;
1638 if (externalLeading
)
1639 *externalLeading
= tm
.tmExternalLeading
;
1643 ::SelectObject(GetHdc(), hfontOld
);
1648 // Each element of the array will be the width of the string up to and
1649 // including the coresoponding character in text.
1651 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1653 static int maxLenText
= -1;
1654 static int maxWidth
= -1;
1657 int stlen
= text
.Length();
1659 if (maxLenText
== -1)
1661 // Win9x and WinNT+ have different limits
1662 int version
= wxGetOsVersion();
1663 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1664 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1668 widths
.Add(0, stlen
); // fill the array with zeros
1670 if (!::GetTextExtentExPoint(GetHdc(),
1671 text
.c_str(), // string to check
1672 wxMin(stlen
, maxLenText
),
1674 &fit
, // [out] count of chars
1676 &widths
[0], // array to fill
1680 wxLogLastError(wxT("GetTextExtentExPoint"));
1690 void wxDC::SetMapMode(int mode
)
1692 WXMICROWIN_CHECK_HDC
1694 m_mappingMode
= mode
;
1696 if ( mode
== wxMM_TEXT
)
1699 m_logicalScaleY
= 1.0;
1701 else // need to do some calculations
1703 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1704 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1705 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1706 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1708 if ( (mm_width
== 0) || (mm_height
== 0) )
1710 // we can't calculate mm2pixels[XY] then!
1714 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1715 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1720 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1721 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1725 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1726 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1730 m_logicalScaleX
= mm2pixelsX
;
1731 m_logicalScaleY
= mm2pixelsY
;
1735 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1736 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1740 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1744 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1745 // cases we could do with MM_TEXT and in the remaining 0.9% with
1746 // MM_ISOTROPIC (TODO!)
1748 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1750 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1751 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1753 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1754 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1756 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1757 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1761 void wxDC::SetUserScale(double x
, double y
)
1763 WXMICROWIN_CHECK_HDC
1765 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1771 this->SetMapMode(m_mappingMode
);
1774 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1776 WXMICROWIN_CHECK_HDC
1779 int signX
= xLeftRight
? 1 : -1,
1780 signY
= yBottomUp
? -1 : 1;
1782 if ( signX
!= m_signX
|| signY
!= m_signY
)
1787 SetMapMode(m_mappingMode
);
1790 wxUnusedVar(xLeftRight
);
1791 wxUnusedVar(yBottomUp
);
1795 void wxDC::SetSystemScale(double x
, double y
)
1797 WXMICROWIN_CHECK_HDC
1799 if ( x
== m_scaleX
&& y
== m_scaleY
)
1806 SetMapMode(m_mappingMode
);
1810 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1812 WXMICROWIN_CHECK_HDC
1814 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1817 m_logicalOriginX
= x
;
1818 m_logicalOriginY
= y
;
1821 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1825 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1827 WXMICROWIN_CHECK_HDC
1829 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1832 m_deviceOriginX
= x
;
1833 m_deviceOriginY
= y
;
1836 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1840 // ---------------------------------------------------------------------------
1841 // coordinates transformations
1842 // ---------------------------------------------------------------------------
1844 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1846 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1849 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1851 // axis orientation is not taken into account for conversion of a distance
1852 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1855 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1857 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1860 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1862 // axis orientation is not taken into account for conversion of a distance
1863 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1866 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1868 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1871 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1873 // axis orientation is not taken into account for conversion of a distance
1874 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1877 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1879 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1882 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1884 // axis orientation is not taken into account for conversion of a distance
1885 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1888 // ---------------------------------------------------------------------------
1890 // ---------------------------------------------------------------------------
1892 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1893 wxCoord width
, wxCoord height
,
1894 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1895 int rop
, bool useMask
,
1896 wxCoord xsrcMask
, wxCoord ysrcMask
)
1898 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1900 WXMICROWIN_CHECK_HDC_RET(false)
1902 // if either the source or destination has alpha channel, we must use
1903 // AlphaBlt() as other function don't handle it correctly
1904 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1905 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1906 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1908 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1909 GetHdcOf(*source
), bmpSrc
) )
1913 wxMask
*mask
= NULL
;
1916 mask
= bmpSrc
.GetMask();
1918 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1920 // don't give assert here because this would break existing
1921 // programs - just silently ignore useMask parameter
1926 if (xsrcMask
== -1 && ysrcMask
== -1)
1928 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1931 COLORREF old_textground
= ::GetTextColor(GetHdc());
1932 COLORREF old_background
= ::GetBkColor(GetHdc());
1933 if (m_textForegroundColour
.Ok())
1935 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1937 if (m_textBackgroundColour
.Ok())
1939 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1945 case wxXOR
: dwRop
= SRCINVERT
; break;
1946 case wxINVERT
: dwRop
= DSTINVERT
; break;
1947 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1948 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1949 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1950 case wxSET
: dwRop
= WHITENESS
; break;
1951 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1952 case wxAND
: dwRop
= SRCAND
; break;
1953 case wxOR
: dwRop
= SRCPAINT
; break;
1954 case wxEQUIV
: dwRop
= 0x00990066; break;
1955 case wxNAND
: dwRop
= 0x007700E6; break;
1956 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1957 case wxCOPY
: dwRop
= SRCCOPY
; break;
1958 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1959 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1960 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1962 wxFAIL_MSG( wxT("unsupported logical function") );
1966 bool success
= false;
1971 // we want the part of the image corresponding to the mask to be
1972 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1973 // meaning of fg and bg is inverted which corresponds to wxWin notion
1974 // of the mask which is also contrary to the Windows one)
1976 // On some systems, MaskBlt succeeds yet is much much slower
1977 // than the wxWidgets fall-back implementation. So we need
1978 // to be able to switch this on and off at runtime.
1979 #if wxUSE_SYSTEM_OPTIONS
1980 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1986 xdest
, ydest
, width
, height
,
1989 (HBITMAP
)mask
->GetMaskBitmap(),
1991 MAKEROP4(dwRop
, DSTCOPY
)
1998 // Blit bitmap with mask
2001 HBITMAP buffer_bmap
;
2003 #if wxUSE_DC_CACHEING
2004 // create a temp buffer bitmap and DCs to access it and the mask
2005 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2006 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2008 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2009 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2011 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2014 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2015 #else // !wxUSE_DC_CACHEING
2016 // create a temp buffer bitmap and DCs to access it and the mask
2017 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2018 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2019 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2020 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2021 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2022 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2024 // copy dest to buffer
2025 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2026 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2028 wxLogLastError(wxT("BitBlt"));
2031 // copy src to buffer using selected raster op
2032 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2033 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2035 wxLogLastError(wxT("BitBlt"));
2038 // set masked area in buffer to BLACK (pixel value 0)
2039 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2040 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2041 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2042 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2044 wxLogLastError(wxT("BitBlt"));
2047 // set unmasked area in dest to BLACK
2048 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2049 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2050 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2051 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2053 wxLogLastError(wxT("BitBlt"));
2055 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2056 ::SetTextColor(GetHdc(), prevCol
);
2058 // OR buffer to dest
2059 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2060 (int)width
, (int)height
,
2061 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2064 wxLogLastError(wxT("BitBlt"));
2067 // tidy up temporary DCs and bitmap
2068 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2069 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2071 #if !wxUSE_DC_CACHEING
2073 ::DeleteDC(dc_mask
);
2074 ::DeleteDC(dc_buffer
);
2075 ::DeleteObject(buffer_bmap
);
2080 else // no mask, just BitBlt() it
2082 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2083 // use StretchBlt() if available and finally fall back to BitBlt()
2085 // FIXME: use appropriate WinCE functions
2087 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2088 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2093 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2095 &ds
) == sizeof(ds
) )
2097 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2099 // Figure out what co-ordinate system we're supposed to specify
2101 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2105 ysrc
= hDIB
- (ysrc
+ height
);
2108 if ( ::StretchDIBits(GetHdc(),
2114 (LPBITMAPINFO
)&ds
.dsBmih
,
2117 ) == (int)GDI_ERROR
)
2119 // On Win9x this API fails most (all?) of the time, so
2120 // logging it becomes quite distracting. Since it falls
2121 // back to the code below this is not really serious, so
2123 //wxLogLastError(wxT("StretchDIBits"));
2132 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2137 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2143 xdest
, ydest
, width
, height
,
2145 xsrc
, ysrc
, width
, height
,
2149 wxLogLastError(_T("StretchBlt"));
2163 (int)width
, (int)height
,
2169 wxLogLastError(_T("BitBlt"));
2178 ::SetTextColor(GetHdc(), old_textground
);
2179 ::SetBkColor(GetHdc(), old_background
);
2184 void wxDC::DoGetSize(int *w
, int *h
) const
2186 WXMICROWIN_CHECK_HDC
2188 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2189 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2192 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2194 WXMICROWIN_CHECK_HDC
2196 // if we implement it in terms of DoGetSize() instead of directly using the
2197 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2198 // will also work for wxWindowDC and wxClientDC even though their size is
2199 // not the same as the total size of the screen
2200 int wPixels
, hPixels
;
2201 DoGetSize(&wPixels
, &hPixels
);
2205 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2207 wxCHECK_RET( wTotal
, _T("0 width device?") );
2209 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2214 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2216 wxCHECK_RET( hTotal
, _T("0 height device?") );
2218 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2222 wxSize
wxDC::GetPPI() const
2224 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2226 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2227 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2229 return wxSize(x
, y
);
2232 // For use by wxWidgets only, unless custom units are required.
2233 void wxDC::SetLogicalScale(double x
, double y
)
2235 WXMICROWIN_CHECK_HDC
2237 m_logicalScaleX
= x
;
2238 m_logicalScaleY
= y
;
2241 // ----------------------------------------------------------------------------
2243 // ----------------------------------------------------------------------------
2245 #if wxUSE_DC_CACHEING
2248 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2249 * improve it in due course, either using arrays, or simply storing pointers to one
2250 * entry for the bitmap, and two for the DCs. -- JACS
2253 wxList
wxDC::sm_bitmapCache
;
2254 wxList
wxDC::sm_dcCache
;
2256 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2265 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2274 wxDCCacheEntry::~wxDCCacheEntry()
2277 ::DeleteObject((HBITMAP
) m_bitmap
);
2279 ::DeleteDC((HDC
) m_dc
);
2282 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2284 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2285 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2288 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2290 if (entry
->m_depth
== depth
)
2292 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2294 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2295 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2296 if ( !entry
->m_bitmap
)
2298 wxLogLastError(wxT("CreateCompatibleBitmap"));
2300 entry
->m_width
= w
; entry
->m_height
= h
;
2306 node
= node
->GetNext();
2308 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2311 wxLogLastError(wxT("CreateCompatibleBitmap"));
2313 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2314 AddToBitmapCache(entry
);
2318 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2320 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2321 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2324 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2326 // Don't return the same one as we already have
2327 if (!notThis
|| (notThis
!= entry
))
2329 if (entry
->m_depth
== depth
)
2335 node
= node
->GetNext();
2337 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2340 wxLogLastError(wxT("CreateCompatibleDC"));
2342 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2343 AddToDCCache(entry
);
2347 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2349 sm_bitmapCache
.Append(entry
);
2352 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2354 sm_dcCache
.Append(entry
);
2357 void wxDC::ClearCache()
2359 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2360 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2363 // Clean up cache at app exit
2364 class wxDCModule
: public wxModule
2367 virtual bool OnInit() { return true; }
2368 virtual void OnExit() { wxDC::ClearCache(); }
2371 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2374 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2376 #endif // wxUSE_DC_CACHEING
2378 // ----------------------------------------------------------------------------
2379 // alpha channel support
2380 // ----------------------------------------------------------------------------
2382 static bool AlphaBlt(HDC hdcDst
,
2383 int x
, int y
, int width
, int height
,
2385 const wxBitmap
& bmp
)
2387 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2388 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2390 // do we have AlphaBlend() and company in the headers?
2391 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2392 // yes, now try to see if we have it during run-time
2393 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2394 HDC
,int,int,int,int,
2397 // bitmaps can be drawn only from GUI thread so there is no need to
2398 // protect this static variable from multiple threads
2399 static bool s_triedToLoad
= false;
2400 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2401 if ( !s_triedToLoad
)
2403 s_triedToLoad
= true;
2405 // don't give errors about the DLL being unavailable, we're
2406 // prepared to handle this
2409 wxDynamicLibrary
dll(_T("msimg32.dll"));
2410 if ( dll
.IsLoaded() )
2412 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2413 if ( pfnAlphaBlend
)
2415 // we must keep the DLL loaded if we want to be able to
2416 // call AlphaBlend() so just never unload it at all, not a
2423 if ( pfnAlphaBlend
)
2426 bf
.BlendOp
= AC_SRC_OVER
;
2428 bf
.SourceConstantAlpha
= 0xff;
2429 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2431 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2432 hdcSrc
, 0, 0, width
, height
,
2435 // skip wxAlphaBlend() call below
2439 wxLogLastError(_T("AlphaBlend"));
2441 #endif // defined(AC_SRC_OVER)
2443 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2445 #ifdef wxHAVE_RAW_BITMAP
2446 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2449 #else // !wxHAVE_RAW_BITMAP
2450 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2451 // alpha but at least something will be shown like this)
2454 #endif // wxHAVE_RAW_BITMAP
2458 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2459 #ifdef wxHAVE_RAW_BITMAP
2462 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2464 // get the destination DC pixels
2465 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2467 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2469 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2471 wxLogLastError(_T("BitBlt"));
2474 // combine them with the source bitmap using alpha
2475 wxAlphaPixelData
dataDst(bmpDst
),
2476 dataSrc((wxBitmap
&)bmpSrc
);
2478 wxCHECK_RET( dataDst
&& dataSrc
,
2479 _T("failed to get raw data in wxAlphaBlend") );
2481 wxAlphaPixelData::Iterator
pDst(dataDst
),
2484 for ( int y
= 0; y
< h
; y
++ )
2486 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2487 pSrcRowStart
= pSrc
;
2489 for ( int x
= 0; x
< w
; x
++ )
2491 // note that source bitmap uses premultiplied alpha (as required by
2492 // the real AlphaBlend)
2493 const unsigned beta
= 255 - pSrc
.Alpha();
2495 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2496 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2497 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2503 pDst
= pDstRowStart
;
2504 pSrc
= pSrcRowStart
;
2505 pDst
.OffsetY(dataDst
, 1);
2506 pSrc
.OffsetY(dataSrc
, 1);
2509 // and finally blit them back to the destination DC
2510 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2512 wxLogLastError(_T("BitBlt"));
2516 #endif // #ifdef wxHAVE_RAW_BITMAP