1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/window.h"
35 #include "wx/dialog.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
43 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
44 #include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
46 #include "wx/sysopt.h"
47 #include "wx/dcprint.h"
48 #include "wx/module.h"
49 #include "wx/dynload.h"
51 #ifdef wxHAVE_RAW_BITMAP
52 #include "wx/rawbmp.h"
58 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
67 #define AC_SRC_ALPHA 1
70 /* Quaternary raster codes */
72 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
75 // apparently with MicroWindows it is possible that HDC is 0 so we have to
76 // check for this ourselves
78 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
79 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
81 #define WXMICROWIN_CHECK_HDC
82 #define WXMICROWIN_CHECK_HDC_RET(x)
85 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 static const int VIEWPORT_EXTENT
= 1000;
93 static const int MM_POINTS
= 9;
94 static const int MM_METRIC
= 10;
96 // usually this is defined in math.h
98 static const double M_PI
= 3.14159265358979323846;
101 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
102 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
103 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
105 // ----------------------------------------------------------------------------
106 // macros for logical <-> device coords conversion
107 // ----------------------------------------------------------------------------
110 We currently let Windows do all the translations itself so these macros are
111 not really needed (any more) but keep them to enhance readability of the
112 code by allowing to see where are the logical and where are the device
117 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
118 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
119 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
120 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
122 #define XLOG2DEV(x) (x)
123 #define YLOG2DEV(y) (y)
124 #define XDEV2LOG(x) (x)
125 #define YDEV2LOG(y) (y)
128 // ---------------------------------------------------------------------------
130 // ---------------------------------------------------------------------------
132 // convert degrees to radians
133 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
135 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
137 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
138 // to pass it to this function but as we already have it at the point
139 // of call anyhow we do
141 // return true if we could draw the bitmap in one way or the other, false
143 static bool AlphaBlt(HDC hdcDst
,
144 int x
, int y
, int w
, int h
,
146 const wxBitmap
& bmpSrc
);
148 #ifdef wxHAVE_RAW_BITMAP
149 // our (limited) AlphaBlend() replacement
151 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
154 // ----------------------------------------------------------------------------
156 // ----------------------------------------------------------------------------
158 // instead of duplicating the same code which sets and then restores text
159 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
160 // encapsulate this in a small helper class
162 // wxColourChanger: changes the text colours in the ctor if required and
163 // restores them in the dtor
164 class wxColourChanger
167 wxColourChanger(wxDC
& dc
);
173 COLORREF m_colFgOld
, m_colBgOld
;
177 DECLARE_NO_COPY_CLASS(wxColourChanger
)
180 // this class saves the old stretch blit mode during its life time
181 class StretchBltModeChanger
184 StretchBltModeChanger(HDC hdc
, int mode
)
188 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
190 wxLogLastError(_T("SetStretchBltMode"));
194 ~StretchBltModeChanger()
197 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
198 wxLogLastError(_T("SetStretchBltMode"));
207 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
210 // ===========================================================================
212 // ===========================================================================
214 // ----------------------------------------------------------------------------
216 // ----------------------------------------------------------------------------
218 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
220 const wxBrush
& brush
= dc
.GetBrush();
221 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
223 HDC hdc
= GetHdcOf(dc
);
224 m_colFgOld
= ::GetTextColor(hdc
);
225 m_colBgOld
= ::GetBkColor(hdc
);
227 // note that Windows convention is opposite to wxWidgets one, this is
228 // why text colour becomes the background one and vice versa
229 const wxColour
& colFg
= dc
.GetTextForeground();
232 ::SetBkColor(hdc
, colFg
.GetPixel());
235 const wxColour
& colBg
= dc
.GetTextBackground();
238 ::SetTextColor(hdc
, colBg
.GetPixel());
242 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
245 // flag which telsl us to undo changes in the dtor
250 // nothing done, nothing to undo
255 wxColourChanger::~wxColourChanger()
259 // restore the colours we changed
260 HDC hdc
= GetHdcOf(m_dc
);
262 ::SetBkMode(hdc
, TRANSPARENT
);
263 ::SetTextColor(hdc
, m_colFgOld
);
264 ::SetBkColor(hdc
, m_colBgOld
);
268 // ---------------------------------------------------------------------------
270 // ---------------------------------------------------------------------------
272 // Default constructor
283 #endif // wxUSE_PALETTE
293 SelectOldObjects(m_hDC
);
295 // if we own the HDC, we delete it, otherwise we just release it
299 ::DeleteDC(GetHdc());
301 else // we don't own our HDC
305 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
309 // Must have been a wxScreenDC
310 ::ReleaseDC((HWND
) NULL
, GetHdc());
316 // This will select current objects out of the DC,
317 // which is what you have to do before deleting the
319 void wxDC::SelectOldObjects(WXHDC dc
)
325 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
327 if (m_selectedBitmap
.Ok())
329 m_selectedBitmap
.SetSelectedInto(NULL
);
336 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
341 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
346 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
353 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
356 #endif // wxUSE_PALETTE
359 m_brush
= wxNullBrush
;
362 m_palette
= wxNullPalette
;
363 #endif // wxUSE_PALETTE
365 m_backgroundBrush
= wxNullBrush
;
366 m_selectedBitmap
= wxNullBitmap
;
369 // ---------------------------------------------------------------------------
371 // ---------------------------------------------------------------------------
373 void wxDC::UpdateClipBox()
378 ::GetClipBox(GetHdc(), &rect
);
380 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
381 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
382 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
383 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
387 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
389 // check if we should try to retrieve the clipping region possibly not set
390 // by our SetClippingRegion() but preset by Windows:this can only happen
391 // when we're associated with an existing HDC usign SetHDC(), see there
392 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
394 wxDC
*self
= wxConstCast(this, wxDC
);
395 self
->UpdateClipBox();
397 if ( !m_clipX1
&& !m_clipX2
)
398 self
->m_clipping
= false;
401 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
404 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
405 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
407 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
411 // note that we combine the new clipping region with the existing one: this
412 // is compatible with what the other ports do and is the documented
413 // behaviour now (starting with 2.3.3)
414 #if defined(__WXWINCE__)
416 if ( !::GetClipBox(GetHdc(), &rectClip
) )
419 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
420 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
421 rectClip
.right
, rectClip
.bottom
);
423 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
425 ::SelectClipRgn(GetHdc(), hrgnDest
);
428 ::DeleteObject(hrgnClipOld
);
429 ::DeleteObject(hrgnDest
);
431 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
433 wxLogLastError(_T("ExtSelectClipRgn"));
437 #endif // WinCE/!WinCE
444 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
446 // the region coords are always the device ones, so do the translation
449 // FIXME: possible +/-1 error here, to check!
450 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
452 LogicalToDeviceX(x
+ w
),
453 LogicalToDeviceY(y
+ h
));
456 wxLogLastError(_T("CreateRectRgn"));
460 SetClippingHrgn((WXHRGN
)hrgn
);
462 ::DeleteObject(hrgn
);
466 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
468 SetClippingHrgn(region
.GetHRGN());
471 void wxDC::DestroyClippingRegion()
475 if (m_clipping
&& m_hDC
)
477 // TODO: this should restore the previous clipping region,
478 // so that OnPaint processing works correctly, and the update
479 // clipping region doesn't get destroyed after the first
480 // DestroyClippingRegion.
481 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
482 ::SelectClipRgn(GetHdc(), rgn
);
486 wxDCBase::DestroyClippingRegion();
489 // ---------------------------------------------------------------------------
490 // query capabilities
491 // ---------------------------------------------------------------------------
493 bool wxDC::CanDrawBitmap() const
498 bool wxDC::CanGetTextExtent() const
500 #ifdef __WXMICROWIN__
501 // TODO Extend MicroWindows' GetDeviceCaps function
504 // What sort of display is it?
505 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
507 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
511 int wxDC::GetDepth() const
513 WXMICROWIN_CHECK_HDC_RET(16)
515 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
518 // ---------------------------------------------------------------------------
520 // ---------------------------------------------------------------------------
529 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
533 // No, I think we should simply ignore this if printing on e.g.
535 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
536 if (!m_selectedBitmap
.Ok())
539 rect
.left
= 0; rect
.top
= 0;
540 rect
.right
= m_selectedBitmap
.GetWidth();
541 rect
.bottom
= m_selectedBitmap
.GetHeight();
545 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
548 DWORD colour
= ::GetBkColor(GetHdc());
549 HBRUSH brush
= ::CreateSolidBrush(colour
);
550 ::FillRect(GetHdc(), &rect
, brush
);
551 ::DeleteObject(brush
);
553 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
554 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
557 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
559 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
560 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
561 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
562 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
566 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
572 WXMICROWIN_CHECK_HDC_RET(false)
574 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
576 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
577 : FLOODFILLBORDER
) ) ;
580 // quoting from the MSDN docs:
582 // Following are some of the reasons this function might fail:
584 // * The filling could not be completed.
585 // * The specified point has the boundary color specified by the
586 // crColor parameter (if FLOODFILLBORDER was requested).
587 // * The specified point does not have the color specified by
588 // crColor (if FLOODFILLSURFACE was requested)
589 // * The point is outside the clipping region that is, it is not
590 // visible on the device.
592 wxLogLastError(wxT("ExtFloodFill"));
595 CalcBoundingBox(x
, y
);
601 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
603 WXMICROWIN_CHECK_HDC_RET(false)
605 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
607 // get the color of the pixel
608 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
610 wxRGBToColour(*col
, pixelcolor
);
615 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
619 wxCoord x1
= x
-VIEWPORT_EXTENT
;
620 wxCoord y1
= y
-VIEWPORT_EXTENT
;
621 wxCoord x2
= x
+VIEWPORT_EXTENT
;
622 wxCoord y2
= y
+VIEWPORT_EXTENT
;
624 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
625 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
627 CalcBoundingBox(x1
, y1
);
628 CalcBoundingBox(x2
, y2
);
631 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
635 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
637 CalcBoundingBox(x1
, y1
);
638 CalcBoundingBox(x2
, y2
);
641 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
642 // and ending at (x2, y2)
643 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
644 wxCoord x2
, wxCoord y2
,
645 wxCoord xc
, wxCoord yc
)
648 // Slower emulation since WinCE doesn't support Pie and Arc
649 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
650 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
651 if( y1
>yc
) sa
= -sa
; // below center
652 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
653 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
658 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
662 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
663 wxCoord r
= (wxCoord
)radius
;
665 // treat the special case of full circle separately
666 if ( x1
== x2
&& y1
== y2
)
668 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
672 wxCoord xx1
= XLOG2DEV(x1
);
673 wxCoord yy1
= YLOG2DEV(y1
);
674 wxCoord xx2
= XLOG2DEV(x2
);
675 wxCoord yy2
= YLOG2DEV(y2
);
676 wxCoord xxc
= XLOG2DEV(xc
);
677 wxCoord yyc
= YLOG2DEV(yc
);
678 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
680 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
681 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
682 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
683 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
685 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
687 // Have to add 1 to bottom-right corner of rectangle
688 // to make semi-circles look right (crooked line otherwise).
689 // Unfortunately this is not a reliable method, depends
690 // on the size of shape.
691 // TODO: figure out why this happens!
692 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
696 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
699 CalcBoundingBox(xc
- r
, yc
- r
);
700 CalcBoundingBox(xc
+ r
, yc
+ r
);
704 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
705 wxCoord width
, wxCoord height
)
709 wxCoord x2
= x1
+ width
,
712 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
720 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
722 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
724 #else // Symantec-MicroWin
726 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
727 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
728 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
729 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
730 ::SetROP2(GetHdc(), R2_COPYPEN
);
731 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
732 MoveToEx(GetHdc(), x1
, y1
, NULL
);
733 LineTo(GetHdc(), x2
, y2
);
734 MoveToEx(GetHdc(), x2
, y1
, NULL
);
735 LineTo(GetHdc(), x1
, y2
);
736 ::SelectObject(GetHdc(), hPenOld
);
737 ::SelectObject(GetHdc(), hBrushOld
);
738 ::DeleteObject(blackPen
);
739 #endif // Win32/Symantec-MicroWin
741 CalcBoundingBox(x1
, y1
);
742 CalcBoundingBox(x2
, y2
);
745 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
749 COLORREF color
= 0x00ffffff;
752 color
= m_pen
.GetColour().GetPixel();
755 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
757 CalcBoundingBox(x
, y
);
760 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
764 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
766 // Do things less efficiently if we have offsets
767 if (xoffset
!= 0 || yoffset
!= 0)
769 POINT
*cpoints
= new POINT
[n
];
771 for (i
= 0; i
< n
; i
++)
773 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
774 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
776 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
779 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
781 (void)Polygon(GetHdc(), cpoints
, n
);
783 SetPolyFillMode(GetHdc(),prev
);
790 for (i
= 0; i
< n
; i
++)
791 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
794 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
796 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
798 SetPolyFillMode(GetHdc(),prev
);
804 wxDC::DoDrawPolyPolygon(int n
,
812 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
816 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
818 for (i
= cnt
= 0; i
< n
; i
++)
821 // Do things less efficiently if we have offsets
822 if (xoffset
!= 0 || yoffset
!= 0)
824 POINT
*cpoints
= new POINT
[cnt
];
825 for (i
= 0; i
< cnt
; i
++)
827 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
828 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
830 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
833 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
835 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
837 SetPolyFillMode(GetHdc(),prev
);
843 for (i
= 0; i
< cnt
; i
++)
844 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
847 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
849 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
851 SetPolyFillMode(GetHdc(),prev
);
858 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
862 // Do things less efficiently if we have offsets
863 if (xoffset
!= 0 || yoffset
!= 0)
865 POINT
*cpoints
= new POINT
[n
];
867 for (i
= 0; i
< n
; i
++)
869 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
870 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
872 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
874 (void)Polyline(GetHdc(), cpoints
, n
);
880 for (i
= 0; i
< n
; i
++)
881 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
883 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
887 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
891 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
893 wxCoord x2
= x
+ width
;
894 wxCoord y2
= y
+ height
;
896 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
899 rect
.left
= XLOG2DEV(x
);
900 rect
.top
= YLOG2DEV(y
);
901 rect
.right
= XLOG2DEV(x2
);
902 rect
.bottom
= YLOG2DEV(y2
);
903 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
907 // Windows draws the filled rectangles without outline (i.e. drawn with a
908 // transparent pen) one pixel smaller in both directions and we want them
909 // to have the same size regardless of which pen is used - adjust
911 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
912 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
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(h
*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(h
*sin(rad
)), y
+ wxCoord(h
*cos(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
1769 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1775 SetMapMode(m_mappingMode
);
1779 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1781 WXMICROWIN_CHECK_HDC
1784 int signX
= xLeftRight
? 1 : -1,
1785 signY
= yBottomUp
? -1 : 1;
1787 if ( signX
!= m_signX
|| signY
!= m_signY
)
1792 SetMapMode(m_mappingMode
);
1797 void wxDC::SetSystemScale(double x
, double y
)
1799 WXMICROWIN_CHECK_HDC
1801 if ( x
== m_scaleX
&& y
== m_scaleY
)
1808 SetMapMode(m_mappingMode
);
1812 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1814 WXMICROWIN_CHECK_HDC
1816 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1819 m_logicalOriginX
= x
;
1820 m_logicalOriginY
= y
;
1823 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1827 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1829 WXMICROWIN_CHECK_HDC
1831 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1834 m_deviceOriginX
= x
;
1835 m_deviceOriginY
= y
;
1838 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1842 // ---------------------------------------------------------------------------
1843 // coordinates transformations
1844 // ---------------------------------------------------------------------------
1846 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1848 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1851 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1853 // axis orientation is not taken into account for conversion of a distance
1854 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1857 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1859 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1862 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1864 // axis orientation is not taken into account for conversion of a distance
1865 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1868 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1870 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1873 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1875 // axis orientation is not taken into account for conversion of a distance
1876 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1879 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1881 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1884 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1886 // axis orientation is not taken into account for conversion of a distance
1887 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1890 // ---------------------------------------------------------------------------
1892 // ---------------------------------------------------------------------------
1894 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1895 wxCoord width
, wxCoord height
,
1896 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1897 int rop
, bool useMask
,
1898 wxCoord xsrcMask
, wxCoord ysrcMask
)
1900 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1902 WXMICROWIN_CHECK_HDC_RET(false)
1904 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1905 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1907 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1908 GetHdcOf(*source
), bmpSrc
) )
1912 wxMask
*mask
= NULL
;
1915 mask
= bmpSrc
.GetMask();
1917 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1919 // don't give assert here because this would break existing
1920 // programs - just silently ignore useMask parameter
1925 if (xsrcMask
== -1 && ysrcMask
== -1)
1927 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1930 COLORREF old_textground
= ::GetTextColor(GetHdc());
1931 COLORREF old_background
= ::GetBkColor(GetHdc());
1932 if (m_textForegroundColour
.Ok())
1934 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1936 if (m_textBackgroundColour
.Ok())
1938 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1944 case wxXOR
: dwRop
= SRCINVERT
; break;
1945 case wxINVERT
: dwRop
= DSTINVERT
; break;
1946 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1947 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1948 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1949 case wxSET
: dwRop
= WHITENESS
; break;
1950 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1951 case wxAND
: dwRop
= SRCAND
; break;
1952 case wxOR
: dwRop
= SRCPAINT
; break;
1953 case wxEQUIV
: dwRop
= 0x00990066; break;
1954 case wxNAND
: dwRop
= 0x007700E6; break;
1955 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1956 case wxCOPY
: dwRop
= SRCCOPY
; break;
1957 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1958 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1959 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1961 wxFAIL_MSG( wxT("unsupported logical function") );
1965 bool success
= false;
1970 // we want the part of the image corresponding to the mask to be
1971 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1972 // meaning of fg and bg is inverted which corresponds to wxWin notion
1973 // of the mask which is also contrary to the Windows one)
1975 // On some systems, MaskBlt succeeds yet is much much slower
1976 // than the wxWidgets fall-back implementation. So we need
1977 // to be able to switch this on and off at runtime.
1978 #if wxUSE_SYSTEM_OPTIONS
1979 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1985 xdest
, ydest
, width
, height
,
1988 (HBITMAP
)mask
->GetMaskBitmap(),
1990 MAKEROP4(dwRop
, DSTCOPY
)
1997 // Blit bitmap with mask
2000 HBITMAP buffer_bmap
;
2002 #if wxUSE_DC_CACHEING
2003 // create a temp buffer bitmap and DCs to access it and the mask
2004 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2005 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2007 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2008 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2010 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2013 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2014 #else // !wxUSE_DC_CACHEING
2015 // create a temp buffer bitmap and DCs to access it and the mask
2016 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2017 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2018 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2019 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2020 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2021 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2023 // copy dest to buffer
2024 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2025 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2027 wxLogLastError(wxT("BitBlt"));
2030 // copy src to buffer using selected raster op
2031 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2032 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2034 wxLogLastError(wxT("BitBlt"));
2037 // set masked area in buffer to BLACK (pixel value 0)
2038 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2039 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2040 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2041 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2043 wxLogLastError(wxT("BitBlt"));
2046 // set unmasked area in dest to BLACK
2047 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2048 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2049 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2050 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2052 wxLogLastError(wxT("BitBlt"));
2054 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2055 ::SetTextColor(GetHdc(), prevCol
);
2057 // OR buffer to dest
2058 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2059 (int)width
, (int)height
,
2060 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2063 wxLogLastError(wxT("BitBlt"));
2066 // tidy up temporary DCs and bitmap
2067 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2068 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2070 #if !wxUSE_DC_CACHEING
2072 ::DeleteDC(dc_mask
);
2073 ::DeleteDC(dc_buffer
);
2074 ::DeleteObject(buffer_bmap
);
2079 else // no mask, just BitBlt() it
2081 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2082 // use StretchBlt() if available and finally fall back to BitBlt()
2084 // FIXME: use appropriate WinCE functions
2086 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2087 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2092 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2094 &ds
) == sizeof(ds
) )
2096 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2098 // Figure out what co-ordinate system we're supposed to specify
2100 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2104 ysrc
= hDIB
- (ysrc
+ height
);
2107 if ( ::StretchDIBits(GetHdc(),
2113 (LPBITMAPINFO
)&ds
.dsBmih
,
2116 ) == (int)GDI_ERROR
)
2118 // On Win9x this API fails most (all?) of the time, so
2119 // logging it becomes quite distracting. Since it falls
2120 // back to the code below this is not really serious, so
2122 //wxLogLastError(wxT("StretchDIBits"));
2131 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2136 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2142 xdest
, ydest
, width
, height
,
2144 xsrc
, ysrc
, width
, height
,
2148 wxLogLastError(_T("StretchBlt"));
2162 (int)width
, (int)height
,
2168 wxLogLastError(_T("BitBlt"));
2177 ::SetTextColor(GetHdc(), old_textground
);
2178 ::SetBkColor(GetHdc(), old_background
);
2183 void wxDC::DoGetSize(int *w
, int *h
) const
2185 WXMICROWIN_CHECK_HDC
2187 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2188 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2191 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2193 WXMICROWIN_CHECK_HDC
2195 // if we implement it in terms of DoGetSize() instead of directly using the
2196 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2197 // will also work for wxWindowDC and wxClientDC even though their size is
2198 // not the same as the total size of the screen
2199 int wPixels
, hPixels
;
2200 DoGetSize(&wPixels
, &hPixels
);
2204 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2206 wxCHECK_RET( wTotal
, _T("0 width device?") );
2208 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2213 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2215 wxCHECK_RET( hTotal
, _T("0 height device?") );
2217 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2221 wxSize
wxDC::GetPPI() const
2223 WXMICROWIN_CHECK_HDC_RET(wxSize())
2225 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2226 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2228 return wxSize(x
, y
);
2231 // For use by wxWidgets only, unless custom units are required.
2232 void wxDC::SetLogicalScale(double x
, double y
)
2234 WXMICROWIN_CHECK_HDC
2236 m_logicalScaleX
= x
;
2237 m_logicalScaleY
= y
;
2240 // ----------------------------------------------------------------------------
2242 // ----------------------------------------------------------------------------
2244 #if wxUSE_DC_CACHEING
2247 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2248 * improve it in due course, either using arrays, or simply storing pointers to one
2249 * entry for the bitmap, and two for the DCs. -- JACS
2252 wxList
wxDC::sm_bitmapCache
;
2253 wxList
wxDC::sm_dcCache
;
2255 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2264 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2273 wxDCCacheEntry::~wxDCCacheEntry()
2276 ::DeleteObject((HBITMAP
) m_bitmap
);
2278 ::DeleteDC((HDC
) m_dc
);
2281 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2283 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2284 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2287 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2289 if (entry
->m_depth
== depth
)
2291 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2293 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2294 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2295 if ( !entry
->m_bitmap
)
2297 wxLogLastError(wxT("CreateCompatibleBitmap"));
2299 entry
->m_width
= w
; entry
->m_height
= h
;
2305 node
= node
->GetNext();
2307 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2310 wxLogLastError(wxT("CreateCompatibleBitmap"));
2312 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2313 AddToBitmapCache(entry
);
2317 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2319 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2320 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2323 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2325 // Don't return the same one as we already have
2326 if (!notThis
|| (notThis
!= entry
))
2328 if (entry
->m_depth
== depth
)
2334 node
= node
->GetNext();
2336 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2339 wxLogLastError(wxT("CreateCompatibleDC"));
2341 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2342 AddToDCCache(entry
);
2346 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2348 sm_bitmapCache
.Append(entry
);
2351 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2353 sm_dcCache
.Append(entry
);
2356 void wxDC::ClearCache()
2358 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2359 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2362 // Clean up cache at app exit
2363 class wxDCModule
: public wxModule
2366 virtual bool OnInit() { return true; }
2367 virtual void OnExit() { wxDC::ClearCache(); }
2370 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2373 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2375 #endif // wxUSE_DC_CACHEING
2377 // ----------------------------------------------------------------------------
2378 // alpha channel support
2379 // ----------------------------------------------------------------------------
2381 static bool AlphaBlt(HDC hdcDst
,
2382 int x
, int y
, int width
, int height
,
2384 const wxBitmap
& bmp
)
2386 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2387 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2389 // do we have AlphaBlend() and company in the headers?
2390 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2391 // yes, now try to see if we have it during run-time
2392 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2393 HDC
,int,int,int,int,
2396 // bitmaps can be drawn only from GUI thread so there is no need to
2397 // protect this static variable from multiple threads
2398 static bool s_triedToLoad
= false;
2399 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2400 if ( !s_triedToLoad
)
2402 s_triedToLoad
= true;
2404 // don't give errors about the DLL being unavailable, we're
2405 // prepared to handle this
2408 wxDynamicLibrary
dll(_T("msimg32.dll"));
2409 if ( dll
.IsLoaded() )
2411 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2412 if ( pfnAlphaBlend
)
2414 // we must keep the DLL loaded if we want to be able to
2415 // call AlphaBlend() so just never unload it at all, not a
2422 if ( pfnAlphaBlend
)
2425 bf
.BlendOp
= AC_SRC_OVER
;
2427 bf
.SourceConstantAlpha
= 0xff;
2428 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2430 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2431 hdcSrc
, 0, 0, width
, height
,
2434 // skip wxAlphaBlend() call below
2438 wxLogLastError(_T("AlphaBlend"));
2440 #endif // defined(AC_SRC_OVER)
2442 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2444 #ifdef wxHAVE_RAW_BITMAP
2445 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2448 #else // !wxHAVE_RAW_BITMAP
2449 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2450 // alpha but at least something will be shown like this)
2452 #endif // wxHAVE_RAW_BITMAP
2456 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2457 #ifdef wxHAVE_RAW_BITMAP
2460 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2462 // get the destination DC pixels
2463 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2465 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2467 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2469 wxLogLastError(_T("BitBlt"));
2472 // combine them with the source bitmap using alpha
2473 wxAlphaPixelData
dataDst(bmpDst
),
2474 dataSrc((wxBitmap
&)bmpSrc
);
2476 wxCHECK_RET( dataDst
&& dataSrc
,
2477 _T("failed to get raw data in wxAlphaBlend") );
2479 wxAlphaPixelData::Iterator
pDst(dataDst
),
2482 for ( int y
= 0; y
< h
; y
++ )
2484 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2485 pSrcRowStart
= pSrc
;
2487 for ( int x
= 0; x
< w
; x
++ )
2489 // note that source bitmap uses premultiplied alpha (as required by
2490 // the real AlphaBlend)
2491 const unsigned beta
= 255 - pSrc
.Alpha();
2493 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2494 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2495 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2501 pDst
= pDstRowStart
;
2502 pSrc
= pSrcRowStart
;
2503 pDst
.OffsetY(dataDst
, 1);
2504 pSrc
.OffsetY(dataSrc
, 1);
2507 // and finally blit them back to the destination DC
2508 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2510 wxLogLastError(_T("BitBlt"));
2514 #endif // #ifdef wxHAVE_RAW_BITMAP