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