1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/sysopt.h"
45 #include "wx/dcprint.h"
46 #include "wx/module.h"
47 #include "wx/dynload.h"
49 #ifdef wxHAVE_RAW_BITMAP
50 #include "wx/rawbmp.h"
55 #include "wx/msw/wrapcdlg.h"
61 #define AC_SRC_ALPHA 1
64 /* Quaternary raster codes */
66 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
69 // apparently with MicroWindows it is possible that HDC is 0 so we have to
70 // check for this ourselves
72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
75 #define WXMICROWIN_CHECK_HDC
76 #define WXMICROWIN_CHECK_HDC_RET(x)
79 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 static const int MM_POINTS
= 9;
88 static const int MM_METRIC
= 10;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
107 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
108 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
109 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
111 #define XLOG2DEV(x) (x)
112 #define YLOG2DEV(y) (y)
113 #define XDEV2LOG(x) (x)
114 #define YDEV2LOG(y) (y)
117 // ---------------------------------------------------------------------------
119 // ---------------------------------------------------------------------------
121 // convert degrees to radians
122 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
124 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
126 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
127 // to pass it to this function but as we already have it at the point
128 // of call anyhow we do
130 // return true if we could draw the bitmap in one way or the other, false
132 static bool AlphaBlt(HDC hdcDst
,
133 int x
, int y
, int w
, int h
,
134 int srcX
, int srcY
, HDC hdcSrc
,
135 const wxBitmap
& bmpSrc
);
137 #ifdef wxHAVE_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement
140 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmp
);
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
147 // instead of duplicating the same code which sets and then restores text
148 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
149 // encapsulate this in a small helper class
151 // wxColourChanger: changes the text colours in the ctor if required and
152 // restores them in the dtor
153 class wxColourChanger
156 wxColourChanger(wxDC
& dc
);
162 COLORREF m_colFgOld
, m_colBgOld
;
166 DECLARE_NO_COPY_CLASS(wxColourChanger
)
169 // this class saves the old stretch blit mode during its life time
170 class StretchBltModeChanger
173 StretchBltModeChanger(HDC hdc
, int mode
)
177 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
179 wxLogLastError(_T("SetStretchBltMode"));
185 ~StretchBltModeChanger()
188 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
189 wxLogLastError(_T("SetStretchBltMode"));
198 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
201 // ===========================================================================
203 // ===========================================================================
205 // ----------------------------------------------------------------------------
207 // ----------------------------------------------------------------------------
209 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
211 const wxBrush
& brush
= dc
.GetBrush();
212 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
214 HDC hdc
= GetHdcOf(dc
);
215 m_colFgOld
= ::GetTextColor(hdc
);
216 m_colBgOld
= ::GetBkColor(hdc
);
218 // note that Windows convention is opposite to wxWidgets one, this is
219 // why text colour becomes the background one and vice versa
220 const wxColour
& colFg
= dc
.GetTextForeground();
223 ::SetBkColor(hdc
, colFg
.GetPixel());
226 const wxColour
& colBg
= dc
.GetTextBackground();
229 ::SetTextColor(hdc
, colBg
.GetPixel());
233 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
236 // flag which telsl us to undo changes in the dtor
241 // nothing done, nothing to undo
246 wxColourChanger::~wxColourChanger()
250 // restore the colours we changed
251 HDC hdc
= GetHdcOf(m_dc
);
253 ::SetBkMode(hdc
, TRANSPARENT
);
254 ::SetTextColor(hdc
, m_colFgOld
);
255 ::SetBkColor(hdc
, m_colBgOld
);
259 // ---------------------------------------------------------------------------
261 // ---------------------------------------------------------------------------
263 // Default constructor
274 #endif // wxUSE_PALETTE
284 SelectOldObjects(m_hDC
);
286 // if we own the HDC, we delete it, otherwise we just release it
290 ::DeleteDC(GetHdc());
292 else // we don't own our HDC
296 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
300 // Must have been a wxScreenDC
301 ::ReleaseDC((HWND
) NULL
, GetHdc());
307 // This will select current objects out of the DC,
308 // which is what you have to do before deleting the
310 void wxDC::SelectOldObjects(WXHDC dc
)
316 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
318 if (m_selectedBitmap
.Ok())
320 m_selectedBitmap
.SetSelectedInto(NULL
);
327 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
332 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
337 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
344 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
347 #endif // wxUSE_PALETTE
350 m_brush
= wxNullBrush
;
353 m_palette
= wxNullPalette
;
354 #endif // wxUSE_PALETTE
356 m_backgroundBrush
= wxNullBrush
;
357 m_selectedBitmap
= wxNullBitmap
;
360 // ---------------------------------------------------------------------------
362 // ---------------------------------------------------------------------------
364 void wxDC::UpdateClipBox()
369 ::GetClipBox(GetHdc(), &rect
);
371 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
372 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
373 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
374 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
378 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
380 // check if we should try to retrieve the clipping region possibly not set
381 // by our SetClippingRegion() but preset by Windows:this can only happen
382 // when we're associated with an existing HDC usign SetHDC(), see there
383 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
385 wxDC
*self
= wxConstCast(this, wxDC
);
386 self
->UpdateClipBox();
388 if ( !m_clipX1
&& !m_clipX2
)
389 self
->m_clipping
= false;
392 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
395 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
396 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
398 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
402 // note that we combine the new clipping region with the existing one: this
403 // is compatible with what the other ports do and is the documented
404 // behaviour now (starting with 2.3.3)
405 #if defined(__WXWINCE__)
407 if ( !::GetClipBox(GetHdc(), &rectClip
) )
410 // GetClipBox returns logical coordinates, so transform to device
411 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
412 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
413 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
414 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
416 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
417 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
418 rectClip
.right
, rectClip
.bottom
);
420 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
422 ::SelectClipRgn(GetHdc(), hrgnDest
);
425 ::DeleteObject(hrgnClipOld
);
426 ::DeleteObject(hrgnDest
);
428 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
430 wxLogLastError(_T("ExtSelectClipRgn"));
434 #endif // WinCE/!WinCE
441 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
443 // the region coords are always the device ones, so do the translation
446 // FIXME: possible +/-1 error here, to check!
447 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
449 LogicalToDeviceX(x
+ w
),
450 LogicalToDeviceY(y
+ h
));
453 wxLogLastError(_T("CreateRectRgn"));
457 SetClippingHrgn((WXHRGN
)hrgn
);
459 ::DeleteObject(hrgn
);
463 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
465 SetClippingHrgn(region
.GetHRGN());
468 void wxDC::DestroyClippingRegion()
472 if (m_clipping
&& m_hDC
)
474 // TODO: this should restore the previous clipping region,
475 // so that OnPaint processing works correctly, and the update
476 // clipping region doesn't get destroyed after the first
477 // DestroyClippingRegion.
478 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
479 ::SelectClipRgn(GetHdc(), rgn
);
483 wxDCBase::DestroyClippingRegion();
486 // ---------------------------------------------------------------------------
487 // query capabilities
488 // ---------------------------------------------------------------------------
490 bool wxDC::CanDrawBitmap() const
495 bool wxDC::CanGetTextExtent() const
497 #ifdef __WXMICROWIN__
498 // TODO Extend MicroWindows' GetDeviceCaps function
501 // What sort of display is it?
502 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
504 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
508 int wxDC::GetDepth() const
510 WXMICROWIN_CHECK_HDC_RET(16)
512 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
515 // ---------------------------------------------------------------------------
517 // ---------------------------------------------------------------------------
526 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
530 // No, I think we should simply ignore this if printing on e.g.
532 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
533 if (!m_selectedBitmap
.Ok())
536 rect
.left
= 0; rect
.top
= 0;
537 rect
.right
= m_selectedBitmap
.GetWidth();
538 rect
.bottom
= m_selectedBitmap
.GetHeight();
542 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
545 DWORD colour
= ::GetBkColor(GetHdc());
546 HBRUSH brush
= ::CreateSolidBrush(colour
);
547 ::FillRect(GetHdc(), &rect
, brush
);
548 ::DeleteObject(brush
);
551 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
552 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
554 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
556 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
557 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
558 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
559 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
563 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
573 WXMICROWIN_CHECK_HDC_RET(false)
575 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
577 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
578 : FLOODFILLBORDER
) ) ;
581 // quoting from the MSDN docs:
583 // Following are some of the reasons this function might fail:
585 // * The filling could not be completed.
586 // * The specified point has the boundary color specified by the
587 // crColor parameter (if FLOODFILLBORDER was requested).
588 // * The specified point does not have the color specified by
589 // crColor (if FLOODFILLSURFACE was requested)
590 // * The point is outside the clipping region that is, it is not
591 // visible on the device.
593 wxLogLastError(wxT("ExtFloodFill"));
596 CalcBoundingBox(x
, y
);
602 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
604 WXMICROWIN_CHECK_HDC_RET(false)
606 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
608 // get the color of the pixel
609 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
611 wxRGBToColour(*col
, pixelcolor
);
616 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
620 wxCoord x1
= x
-VIEWPORT_EXTENT
;
621 wxCoord y1
= y
-VIEWPORT_EXTENT
;
622 wxCoord x2
= x
+VIEWPORT_EXTENT
;
623 wxCoord y2
= y
+VIEWPORT_EXTENT
;
625 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
626 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
628 CalcBoundingBox(x1
, y1
);
629 CalcBoundingBox(x2
, y2
);
632 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
636 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
638 CalcBoundingBox(x1
, y1
);
639 CalcBoundingBox(x2
, y2
);
642 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
643 // and ending at (x2, y2)
644 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
645 wxCoord x2
, wxCoord y2
,
646 wxCoord xc
, wxCoord yc
)
649 // Slower emulation since WinCE doesn't support Pie and Arc
650 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
651 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
652 if( y1
>yc
) sa
= -sa
; // below center
653 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
654 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
659 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
663 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
664 wxCoord r
= (wxCoord
)radius
;
666 // treat the special case of full circle separately
667 if ( x1
== x2
&& y1
== y2
)
669 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
673 wxCoord xx1
= XLOG2DEV(x1
);
674 wxCoord yy1
= YLOG2DEV(y1
);
675 wxCoord xx2
= XLOG2DEV(x2
);
676 wxCoord yy2
= YLOG2DEV(y2
);
677 wxCoord xxc
= XLOG2DEV(xc
);
678 wxCoord yyc
= YLOG2DEV(yc
);
679 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
681 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
682 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
683 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
684 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
686 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
688 // Have to add 1 to bottom-right corner of rectangle
689 // to make semi-circles look right (crooked line otherwise).
690 // Unfortunately this is not a reliable method, depends
691 // on the size of shape.
692 // TODO: figure out why this happens!
693 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
697 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
700 CalcBoundingBox(xc
- r
, yc
- r
);
701 CalcBoundingBox(xc
+ r
, yc
+ r
);
705 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
706 wxCoord width
, wxCoord height
)
710 wxCoord x2
= x1
+ width
,
713 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
721 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
723 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
725 #else // Symantec-MicroWin
727 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
728 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
729 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
730 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
731 ::SetROP2(GetHdc(), R2_COPYPEN
);
732 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
733 MoveToEx(GetHdc(), x1
, y1
, NULL
);
734 LineTo(GetHdc(), x2
, y2
);
735 MoveToEx(GetHdc(), x2
, y1
, NULL
);
736 LineTo(GetHdc(), x1
, y2
);
737 ::SelectObject(GetHdc(), hPenOld
);
738 ::SelectObject(GetHdc(), hBrushOld
);
739 ::DeleteObject(blackPen
);
740 #endif // Win32/Symantec-MicroWin
742 CalcBoundingBox(x1
, y1
);
743 CalcBoundingBox(x2
, y2
);
746 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
750 COLORREF color
= 0x00ffffff;
753 color
= m_pen
.GetColour().GetPixel();
756 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
758 CalcBoundingBox(x
, y
);
761 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
765 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
767 // Do things less efficiently if we have offsets
768 if (xoffset
!= 0 || yoffset
!= 0)
770 POINT
*cpoints
= new POINT
[n
];
772 for (i
= 0; i
< n
; i
++)
774 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
775 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
777 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
780 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
782 wxUnusedVar(fillStyle
);
784 (void)Polygon(GetHdc(), cpoints
, n
);
786 SetPolyFillMode(GetHdc(),prev
);
793 for (i
= 0; i
< n
; i
++)
794 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
797 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
799 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
801 SetPolyFillMode(GetHdc(),prev
);
807 wxDC::DoDrawPolyPolygon(int n
,
815 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
819 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
821 for (i
= cnt
= 0; i
< n
; i
++)
824 // Do things less efficiently if we have offsets
825 if (xoffset
!= 0 || yoffset
!= 0)
827 POINT
*cpoints
= new POINT
[cnt
];
828 for (i
= 0; i
< cnt
; i
++)
830 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
831 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
833 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
836 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
838 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
840 SetPolyFillMode(GetHdc(),prev
);
846 for (i
= 0; i
< cnt
; i
++)
847 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
850 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
852 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
854 SetPolyFillMode(GetHdc(),prev
);
861 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
865 // Do things less efficiently if we have offsets
866 if (xoffset
!= 0 || yoffset
!= 0)
868 POINT
*cpoints
= new POINT
[n
];
870 for (i
= 0; i
< n
; i
++)
872 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
873 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
875 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
877 (void)Polyline(GetHdc(), cpoints
, n
);
883 for (i
= 0; i
< n
; i
++)
884 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
886 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
890 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
894 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
896 wxCoord x2
= x
+ width
;
897 wxCoord y2
= y
+ height
;
899 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
902 rect
.left
= XLOG2DEV(x
);
903 rect
.top
= YLOG2DEV(y
);
904 rect
.right
= XLOG2DEV(x2
);
905 rect
.bottom
= YLOG2DEV(y2
);
906 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
910 // Windows draws the filled rectangles without outline (i.e. drawn with a
911 // transparent pen) one pixel smaller in both directions and we want them
912 // to have the same size regardless of which pen is used - adjust
914 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
915 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
917 // Apparently not needed for WinCE (see e.g. Life! demo)
924 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
928 CalcBoundingBox(x
, y
);
929 CalcBoundingBox(x2
, y2
);
932 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
936 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
938 // Now, a negative radius value is interpreted to mean
939 // 'the proportion of the smallest X or Y dimension'
943 double smallest
= (width
< height
) ? width
: height
;
944 radius
= (- radius
* smallest
);
947 wxCoord x2
= (x
+width
);
948 wxCoord y2
= (y
+height
);
950 // Windows draws the filled rectangles without outline (i.e. drawn with a
951 // transparent pen) one pixel smaller in both directions and we want them
952 // to have the same size regardless of which pen is used - adjust
953 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
959 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
960 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
962 CalcBoundingBox(x
, y
);
963 CalcBoundingBox(x2
, y2
);
966 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
970 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
972 wxCoord x2
= (x
+width
);
973 wxCoord y2
= (y
+height
);
975 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
977 CalcBoundingBox(x
, y
);
978 CalcBoundingBox(x2
, y2
);
981 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
982 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
985 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
990 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
995 int rx1
= XLOG2DEV(x
+w
/2);
996 int ry1
= YLOG2DEV(y
+h
/2);
1003 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1004 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1005 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1006 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1008 // draw pie with NULL_PEN first and then outline otherwise a line is
1009 // drawn from the start and end points to the centre
1010 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1013 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1014 rx1
, ry1
, rx2
, ry2
);
1018 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1019 rx1
, ry1
-1, rx2
, ry2
-1);
1022 ::SelectObject(GetHdc(), hpenOld
);
1024 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1025 rx1
, ry1
, rx2
, ry2
);
1027 CalcBoundingBox(x
, y
);
1028 CalcBoundingBox(x2
, y2
);
1032 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1034 WXMICROWIN_CHECK_HDC
1036 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1039 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1041 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1044 CalcBoundingBox(x
, y
);
1045 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1048 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1050 WXMICROWIN_CHECK_HDC
1052 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1054 int width
= bmp
.GetWidth(),
1055 height
= bmp
.GetHeight();
1057 HBITMAP hbmpMask
= 0;
1060 HPALETTE oldPal
= 0;
1061 #endif // wxUSE_PALETTE
1063 if ( bmp
.HasAlpha() )
1066 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1068 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1074 wxMask
*mask
= bmp
.GetMask();
1076 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1080 // don't give assert here because this would break existing
1081 // programs - just silently ignore useMask parameter
1088 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1090 // On some systems, MaskBlt succeeds yet is much much slower
1091 // than the wxWidgets fall-back implementation. So we need
1092 // to be able to switch this on and off at runtime.
1094 #if wxUSE_SYSTEM_OPTIONS
1095 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1099 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1100 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1102 wxPalette
*pal
= bmp
.GetPalette();
1103 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1105 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1106 ::RealizePalette(hdcMem
);
1108 #endif // wxUSE_PALETTE
1110 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1113 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1117 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1118 #endif // wxUSE_PALETTE
1120 ::SelectObject(hdcMem
, hOldBitmap
);
1127 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1130 memDC
.SelectObject(bmp
);
1132 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1134 memDC
.SelectObject(wxNullBitmap
);
1137 else // no mask, just use BitBlt()
1140 HDC memdc
= ::CreateCompatibleDC( cdc
);
1141 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1143 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1145 COLORREF old_textground
= ::GetTextColor(GetHdc());
1146 COLORREF old_background
= ::GetBkColor(GetHdc());
1147 if (m_textForegroundColour
.Ok())
1149 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1151 if (m_textBackgroundColour
.Ok())
1153 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1157 wxPalette
*pal
= bmp
.GetPalette();
1158 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1160 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1161 ::RealizePalette(memdc
);
1163 #endif // wxUSE_PALETTE
1165 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1166 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1170 ::SelectPalette(memdc
, oldPal
, FALSE
);
1171 #endif // wxUSE_PALETTE
1173 ::SelectObject( memdc
, hOldBitmap
);
1174 ::DeleteDC( memdc
);
1176 ::SetTextColor(GetHdc(), old_textground
);
1177 ::SetBkColor(GetHdc(), old_background
);
1181 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1183 WXMICROWIN_CHECK_HDC
1185 DrawAnyText(text
, x
, y
);
1187 // update the bounding box
1188 CalcBoundingBox(x
, y
);
1191 GetTextExtent(text
, &w
, &h
);
1192 CalcBoundingBox(x
+ w
, y
+ h
);
1195 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1197 WXMICROWIN_CHECK_HDC
1199 // prepare for drawing the text
1200 if ( m_textForegroundColour
.Ok() )
1201 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1203 DWORD old_background
= 0;
1204 if ( m_textBackgroundColour
.Ok() )
1206 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1209 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1213 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1214 text
.c_str(), text
.length(), NULL
) == 0 )
1216 wxLogLastError(wxT("TextOut"));
1219 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1220 text
.c_str(), text
.length()) == 0 )
1222 wxLogLastError(wxT("TextOut"));
1226 // restore the old parameters (text foreground colour may be left because
1227 // it never is set to anything else, but background should remain
1228 // transparent even if we just drew an opaque string)
1229 if ( m_textBackgroundColour
.Ok() )
1230 (void)SetBkColor(GetHdc(), old_background
);
1232 SetBkMode(GetHdc(), TRANSPARENT
);
1235 void wxDC::DoDrawRotatedText(const wxString
& text
,
1236 wxCoord x
, wxCoord y
,
1239 WXMICROWIN_CHECK_HDC
1241 // we test that we have some font because otherwise we should still use the
1242 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1243 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1244 // font for drawing rotated fonts unfortunately)
1245 if ( (angle
== 0.0) && m_font
.Ok() )
1247 DoDrawText(text
, x
, y
);
1249 #ifndef __WXMICROWIN__
1252 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1253 // because it's not TrueType and so can't have non zero
1254 // orientation/escapement under Win9x
1255 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1256 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1258 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1260 wxLogLastError(wxT("GetObject(hfont)"));
1263 // GDI wants the angle in tenth of degree
1264 long angle10
= (long)(angle
* 10);
1265 lf
.lfEscapement
= angle10
;
1266 lf
. lfOrientation
= angle10
;
1268 hfont
= ::CreateFontIndirect(&lf
);
1271 wxLogLastError(wxT("CreateFont"));
1275 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1277 DrawAnyText(text
, x
, y
);
1279 (void)::SelectObject(GetHdc(), hfontOld
);
1280 (void)::DeleteObject(hfont
);
1283 // call the bounding box by adding all four vertices of the rectangle
1284 // containing the text to it (simpler and probably not slower than
1285 // determining which of them is really topmost/leftmost/...)
1287 GetTextExtent(text
, &w
, &h
);
1289 double rad
= DegToRad(angle
);
1291 // "upper left" and "upper right"
1292 CalcBoundingBox(x
, y
);
1293 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1295 // "bottom left" and "bottom right"
1296 x
+= (wxCoord
)(h
*sin(rad
));
1297 y
+= (wxCoord
)(h
*cos(rad
));
1298 CalcBoundingBox(x
, y
);
1299 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1304 // ---------------------------------------------------------------------------
1306 // ---------------------------------------------------------------------------
1310 void wxDC::DoSelectPalette(bool realize
)
1312 WXMICROWIN_CHECK_HDC
1314 // Set the old object temporarily, in case the assignment deletes an object
1315 // that's not yet selected out.
1318 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1322 if ( m_palette
.Ok() )
1324 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1325 GetHpaletteOf(m_palette
),
1328 m_oldPalette
= (WXHPALETTE
) oldPal
;
1331 ::RealizePalette(GetHdc());
1335 void wxDC::SetPalette(const wxPalette
& palette
)
1339 m_palette
= palette
;
1340 DoSelectPalette(true);
1344 void wxDC::InitializePalette()
1346 if ( wxDisplayDepth() <= 8 )
1348 // look for any window or parent that has a custom palette. If any has
1349 // one then we need to use it in drawing operations
1350 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1352 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1353 if ( m_hasCustomPalette
)
1355 m_palette
= win
->GetPalette();
1357 // turn on MSW translation for this palette
1363 #endif // wxUSE_PALETTE
1365 // SetFont/Pen/Brush() really ask to be implemented as a single template
1366 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1368 void wxDC::SetFont(const wxFont
& font
)
1370 WXMICROWIN_CHECK_HDC
1372 if ( font
== m_font
)
1377 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1378 if ( hfont
== HGDI_ERROR
)
1380 wxLogLastError(_T("SelectObject(font)"));
1385 m_oldFont
= (WXHPEN
)hfont
;
1390 else // invalid font, reset the current font
1394 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1396 wxLogLastError(_T("SelectObject(old font)"));
1402 m_font
= wxNullFont
;
1406 void wxDC::SetPen(const wxPen
& pen
)
1408 WXMICROWIN_CHECK_HDC
1415 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1416 if ( hpen
== HGDI_ERROR
)
1418 wxLogLastError(_T("SelectObject(pen)"));
1423 m_oldPen
= (WXHPEN
)hpen
;
1428 else // invalid pen, reset the current pen
1432 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1434 wxLogLastError(_T("SelectObject(old pen)"));
1444 void wxDC::SetBrush(const wxBrush
& brush
)
1446 WXMICROWIN_CHECK_HDC
1448 if ( brush
== m_brush
)
1453 // we must make sure the brush is aligned with the logical coordinates
1454 // before selecting it
1455 wxBitmap
*stipple
= brush
.GetStipple();
1456 if ( stipple
&& stipple
->Ok() )
1458 if ( !::SetBrushOrgEx
1461 m_deviceOriginX
% stipple
->GetWidth(),
1462 m_deviceOriginY
% stipple
->GetHeight(),
1463 NULL
// [out] previous brush origin
1466 wxLogLastError(_T("SetBrushOrgEx()"));
1470 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1471 if ( hbrush
== HGDI_ERROR
)
1473 wxLogLastError(_T("SelectObject(brush)"));
1478 m_oldBrush
= (WXHPEN
)hbrush
;
1483 else // invalid brush, reset the current brush
1487 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1489 wxLogLastError(_T("SelectObject(old brush)"));
1495 m_brush
= wxNullBrush
;
1499 void wxDC::SetBackground(const wxBrush
& brush
)
1501 WXMICROWIN_CHECK_HDC
1503 m_backgroundBrush
= brush
;
1505 if ( m_backgroundBrush
.Ok() )
1507 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1511 void wxDC::SetBackgroundMode(int mode
)
1513 WXMICROWIN_CHECK_HDC
1515 m_backgroundMode
= mode
;
1517 // SetBackgroundColour now only refers to text background
1518 // and m_backgroundMode is used there
1521 void wxDC::SetLogicalFunction(int function
)
1523 WXMICROWIN_CHECK_HDC
1525 m_logicalFunction
= function
;
1530 void wxDC::SetRop(WXHDC dc
)
1532 if ( !dc
|| m_logicalFunction
< 0 )
1537 switch (m_logicalFunction
)
1539 case wxCLEAR
: rop
= R2_BLACK
; break;
1540 case wxXOR
: rop
= R2_XORPEN
; break;
1541 case wxINVERT
: rop
= R2_NOT
; break;
1542 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1543 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1544 case wxCOPY
: rop
= R2_COPYPEN
; break;
1545 case wxAND
: rop
= R2_MASKPEN
; break;
1546 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1547 case wxNO_OP
: rop
= R2_NOP
; break;
1548 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1549 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1550 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1551 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1552 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1553 case wxOR
: rop
= R2_MERGEPEN
; break;
1554 case wxSET
: rop
= R2_WHITE
; break;
1557 wxFAIL_MSG( wxT("unsupported logical function") );
1561 SetROP2(GetHdc(), rop
);
1564 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1566 // We might be previewing, so return true to let it continue.
1574 void wxDC::StartPage()
1578 void wxDC::EndPage()
1582 // ---------------------------------------------------------------------------
1584 // ---------------------------------------------------------------------------
1586 wxCoord
wxDC::GetCharHeight() const
1588 WXMICROWIN_CHECK_HDC_RET(0)
1590 TEXTMETRIC lpTextMetric
;
1592 GetTextMetrics(GetHdc(), &lpTextMetric
);
1594 return lpTextMetric
.tmHeight
;
1597 wxCoord
wxDC::GetCharWidth() const
1599 WXMICROWIN_CHECK_HDC_RET(0)
1601 TEXTMETRIC lpTextMetric
;
1603 GetTextMetrics(GetHdc(), &lpTextMetric
);
1605 return lpTextMetric
.tmAveCharWidth
;
1608 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1609 wxCoord
*descent
, wxCoord
*externalLeading
,
1612 #ifdef __WXMICROWIN__
1617 if (descent
) *descent
= 0;
1618 if (externalLeading
) *externalLeading
= 0;
1621 #endif // __WXMICROWIN__
1626 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1628 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1630 else // don't change the font
1638 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1639 GetTextMetrics(GetHdc(), &tm
);
1646 *descent
= tm
.tmDescent
;
1647 if (externalLeading
)
1648 *externalLeading
= tm
.tmExternalLeading
;
1652 ::SelectObject(GetHdc(), hfontOld
);
1657 // Each element of the array will be the width of the string up to and
1658 // including the coresoponding character in text.
1660 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1662 static int maxLenText
= -1;
1663 static int maxWidth
= -1;
1666 int stlen
= text
.Length();
1668 if (maxLenText
== -1)
1670 // Win9x and WinNT+ have different limits
1671 int version
= wxGetOsVersion();
1672 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1673 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1677 widths
.Add(0, stlen
); // fill the array with zeros
1679 if (!::GetTextExtentExPoint(GetHdc(),
1680 text
.c_str(), // string to check
1681 wxMin(stlen
, maxLenText
),
1683 &fit
, // [out] count of chars
1685 &widths
[0], // array to fill
1689 wxLogLastError(wxT("GetTextExtentExPoint"));
1699 void wxDC::SetMapMode(int mode
)
1701 WXMICROWIN_CHECK_HDC
1703 m_mappingMode
= mode
;
1705 if ( mode
== wxMM_TEXT
)
1708 m_logicalScaleY
= 1.0;
1710 else // need to do some calculations
1712 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1713 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1714 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1715 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1717 if ( (mm_width
== 0) || (mm_height
== 0) )
1719 // we can't calculate mm2pixels[XY] then!
1723 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1724 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1729 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1730 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1734 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1735 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1739 m_logicalScaleX
= mm2pixelsX
;
1740 m_logicalScaleY
= mm2pixelsY
;
1744 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1745 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1749 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1753 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1754 // cases we could do with MM_TEXT and in the remaining 0.9% with
1755 // MM_ISOTROPIC (TODO!)
1757 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1759 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1760 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1762 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1763 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1765 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1766 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1770 void wxDC::SetUserScale(double x
, double y
)
1772 WXMICROWIN_CHECK_HDC
1774 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1780 this->SetMapMode(m_mappingMode
);
1783 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1785 WXMICROWIN_CHECK_HDC
1788 int signX
= xLeftRight
? 1 : -1,
1789 signY
= yBottomUp
? -1 : 1;
1791 if ( signX
!= m_signX
|| signY
!= m_signY
)
1796 SetMapMode(m_mappingMode
);
1799 wxUnusedVar(xLeftRight
);
1800 wxUnusedVar(yBottomUp
);
1804 void wxDC::SetSystemScale(double x
, double y
)
1806 WXMICROWIN_CHECK_HDC
1808 if ( x
== m_scaleX
&& y
== m_scaleY
)
1815 SetMapMode(m_mappingMode
);
1819 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1821 WXMICROWIN_CHECK_HDC
1823 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1826 m_logicalOriginX
= x
;
1827 m_logicalOriginY
= y
;
1830 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1834 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1836 WXMICROWIN_CHECK_HDC
1838 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1841 m_deviceOriginX
= x
;
1842 m_deviceOriginY
= y
;
1844 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1847 // ---------------------------------------------------------------------------
1848 // coordinates transformations
1849 // ---------------------------------------------------------------------------
1851 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1853 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1856 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1858 // axis orientation is not taken into account for conversion of a distance
1859 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1862 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1864 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1867 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1869 // axis orientation is not taken into account for conversion of a distance
1870 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1873 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1875 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1878 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1880 // axis orientation is not taken into account for conversion of a distance
1881 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1884 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1886 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1889 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1891 // axis orientation is not taken into account for conversion of a distance
1892 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1895 // ---------------------------------------------------------------------------
1897 // ---------------------------------------------------------------------------
1899 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1900 wxCoord width
, wxCoord height
,
1901 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1902 int rop
, bool useMask
,
1903 wxCoord xsrcMask
, wxCoord ysrcMask
)
1905 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1907 WXMICROWIN_CHECK_HDC_RET(false)
1909 // if either the source or destination has alpha channel, we must use
1910 // AlphaBlt() as other function don't handle it correctly
1911 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1912 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1913 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1915 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1916 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
1920 wxMask
*mask
= NULL
;
1923 mask
= bmpSrc
.GetMask();
1925 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1927 // don't give assert here because this would break existing
1928 // programs - just silently ignore useMask parameter
1933 if (xsrcMask
== -1 && ysrcMask
== -1)
1935 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1938 COLORREF old_textground
= ::GetTextColor(GetHdc());
1939 COLORREF old_background
= ::GetBkColor(GetHdc());
1940 if (m_textForegroundColour
.Ok())
1942 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1944 if (m_textBackgroundColour
.Ok())
1946 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1952 case wxXOR
: dwRop
= SRCINVERT
; break;
1953 case wxINVERT
: dwRop
= DSTINVERT
; break;
1954 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1955 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1956 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1957 case wxSET
: dwRop
= WHITENESS
; break;
1958 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1959 case wxAND
: dwRop
= SRCAND
; break;
1960 case wxOR
: dwRop
= SRCPAINT
; break;
1961 case wxEQUIV
: dwRop
= 0x00990066; break;
1962 case wxNAND
: dwRop
= 0x007700E6; break;
1963 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1964 case wxCOPY
: dwRop
= SRCCOPY
; break;
1965 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1966 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1967 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1969 wxFAIL_MSG( wxT("unsupported logical function") );
1973 bool success
= false;
1978 // we want the part of the image corresponding to the mask to be
1979 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1980 // meaning of fg and bg is inverted which corresponds to wxWin notion
1981 // of the mask which is also contrary to the Windows one)
1983 // On some systems, MaskBlt succeeds yet is much much slower
1984 // than the wxWidgets fall-back implementation. So we need
1985 // to be able to switch this on and off at runtime.
1986 #if wxUSE_SYSTEM_OPTIONS
1987 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1993 xdest
, ydest
, width
, height
,
1996 (HBITMAP
)mask
->GetMaskBitmap(),
1998 MAKEROP4(dwRop
, DSTCOPY
)
2005 // Blit bitmap with mask
2008 HBITMAP buffer_bmap
;
2010 #if wxUSE_DC_CACHEING
2011 // create a temp buffer bitmap and DCs to access it and the mask
2012 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2013 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2015 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2016 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2018 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2021 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2022 #else // !wxUSE_DC_CACHEING
2023 // create a temp buffer bitmap and DCs to access it and the mask
2024 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2025 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2026 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2027 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2028 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2029 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2031 // copy dest to buffer
2032 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2033 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2035 wxLogLastError(wxT("BitBlt"));
2038 // copy src to buffer using selected raster op
2039 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2040 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2042 wxLogLastError(wxT("BitBlt"));
2045 // set masked area in buffer to BLACK (pixel value 0)
2046 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2047 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2048 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2049 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2051 wxLogLastError(wxT("BitBlt"));
2054 // set unmasked area in dest to BLACK
2055 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2056 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2057 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2058 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2060 wxLogLastError(wxT("BitBlt"));
2062 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2063 ::SetTextColor(GetHdc(), prevCol
);
2065 // OR buffer to dest
2066 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2067 (int)width
, (int)height
,
2068 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2071 wxLogLastError(wxT("BitBlt"));
2074 // tidy up temporary DCs and bitmap
2075 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2076 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2078 #if !wxUSE_DC_CACHEING
2080 ::DeleteDC(dc_mask
);
2081 ::DeleteDC(dc_buffer
);
2082 ::DeleteObject(buffer_bmap
);
2087 else // no mask, just BitBlt() it
2089 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2090 // use StretchBlt() if available and finally fall back to BitBlt()
2092 // FIXME: use appropriate WinCE functions
2094 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2095 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2100 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2102 &ds
) == sizeof(ds
) )
2104 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2106 // Figure out what co-ordinate system we're supposed to specify
2108 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2112 ysrc
= hDIB
- (ysrc
+ height
);
2115 if ( ::StretchDIBits(GetHdc(),
2121 (LPBITMAPINFO
)&ds
.dsBmih
,
2124 ) == (int)GDI_ERROR
)
2126 // On Win9x this API fails most (all?) of the time, so
2127 // logging it becomes quite distracting. Since it falls
2128 // back to the code below this is not really serious, so
2130 //wxLogLastError(wxT("StretchDIBits"));
2139 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2144 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2150 xdest
, ydest
, width
, height
,
2152 xsrc
, ysrc
, width
, height
,
2156 wxLogLastError(_T("StretchBlt"));
2170 (int)width
, (int)height
,
2176 wxLogLastError(_T("BitBlt"));
2185 ::SetTextColor(GetHdc(), old_textground
);
2186 ::SetBkColor(GetHdc(), old_background
);
2191 void wxDC::DoGetSize(int *w
, int *h
) const
2193 WXMICROWIN_CHECK_HDC
2195 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2196 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2199 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2201 WXMICROWIN_CHECK_HDC
2203 // if we implement it in terms of DoGetSize() instead of directly using the
2204 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2205 // will also work for wxWindowDC and wxClientDC even though their size is
2206 // not the same as the total size of the screen
2207 int wPixels
, hPixels
;
2208 DoGetSize(&wPixels
, &hPixels
);
2212 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2214 wxCHECK_RET( wTotal
, _T("0 width device?") );
2216 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2221 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2223 wxCHECK_RET( hTotal
, _T("0 height device?") );
2225 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2229 wxSize
wxDC::GetPPI() const
2231 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2233 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2234 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2236 return wxSize(x
, y
);
2239 // For use by wxWidgets only, unless custom units are required.
2240 void wxDC::SetLogicalScale(double x
, double y
)
2242 WXMICROWIN_CHECK_HDC
2244 m_logicalScaleX
= x
;
2245 m_logicalScaleY
= y
;
2248 // ----------------------------------------------------------------------------
2250 // ----------------------------------------------------------------------------
2252 #if wxUSE_DC_CACHEING
2255 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2256 * improve it in due course, either using arrays, or simply storing pointers to one
2257 * entry for the bitmap, and two for the DCs. -- JACS
2260 wxList
wxDC::sm_bitmapCache
;
2261 wxList
wxDC::sm_dcCache
;
2263 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2272 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2281 wxDCCacheEntry::~wxDCCacheEntry()
2284 ::DeleteObject((HBITMAP
) m_bitmap
);
2286 ::DeleteDC((HDC
) m_dc
);
2289 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2291 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2292 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2295 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2297 if (entry
->m_depth
== depth
)
2299 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2301 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2302 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2303 if ( !entry
->m_bitmap
)
2305 wxLogLastError(wxT("CreateCompatibleBitmap"));
2307 entry
->m_width
= w
; entry
->m_height
= h
;
2313 node
= node
->GetNext();
2315 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2318 wxLogLastError(wxT("CreateCompatibleBitmap"));
2320 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2321 AddToBitmapCache(entry
);
2325 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2327 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2328 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2331 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2333 // Don't return the same one as we already have
2334 if (!notThis
|| (notThis
!= entry
))
2336 if (entry
->m_depth
== depth
)
2342 node
= node
->GetNext();
2344 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2347 wxLogLastError(wxT("CreateCompatibleDC"));
2349 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2350 AddToDCCache(entry
);
2354 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2356 sm_bitmapCache
.Append(entry
);
2359 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2361 sm_dcCache
.Append(entry
);
2364 void wxDC::ClearCache()
2366 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2367 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2370 // Clean up cache at app exit
2371 class wxDCModule
: public wxModule
2374 virtual bool OnInit() { return true; }
2375 virtual void OnExit() { wxDC::ClearCache(); }
2378 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2381 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2383 #endif // wxUSE_DC_CACHEING
2385 // ----------------------------------------------------------------------------
2386 // alpha channel support
2387 // ----------------------------------------------------------------------------
2389 static bool AlphaBlt(HDC hdcDst
,
2390 int x
, int y
, int width
, int height
,
2391 int srcX
, int srcY
, HDC hdcSrc
,
2392 const wxBitmap
& bmp
)
2394 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2395 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2397 // do we have AlphaBlend() and company in the headers?
2398 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2399 // yes, now try to see if we have it during run-time
2400 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2401 HDC
,int,int,int,int,
2404 // bitmaps can be drawn only from GUI thread so there is no need to
2405 // protect this static variable from multiple threads
2406 static bool s_triedToLoad
= false;
2407 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2408 if ( !s_triedToLoad
)
2410 s_triedToLoad
= true;
2412 // don't give errors about the DLL being unavailable, we're
2413 // prepared to handle this
2416 wxDynamicLibrary
dll(_T("msimg32.dll"));
2417 if ( dll
.IsLoaded() )
2419 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2420 if ( pfnAlphaBlend
)
2422 // we must keep the DLL loaded if we want to be able to
2423 // call AlphaBlend() so just never unload it at all, not a
2430 if ( pfnAlphaBlend
)
2433 bf
.BlendOp
= AC_SRC_OVER
;
2435 bf
.SourceConstantAlpha
= 0xff;
2436 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2438 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2439 hdcSrc
, srcX
, srcY
, width
, height
,
2442 // skip wxAlphaBlend() call below
2446 wxLogLastError(_T("AlphaBlend"));
2448 #endif // defined(AC_SRC_OVER)
2450 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2452 #ifdef wxHAVE_RAW_BITMAP
2453 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2456 #else // !wxHAVE_RAW_BITMAP
2457 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2458 // alpha but at least something will be shown like this)
2461 #endif // wxHAVE_RAW_BITMAP
2465 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2466 #ifdef wxHAVE_RAW_BITMAP
2469 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2471 // get the destination DC pixels
2472 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2474 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2476 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2478 wxLogLastError(_T("BitBlt"));
2481 // combine them with the source bitmap using alpha
2482 wxAlphaPixelData
dataDst(bmpDst
),
2483 dataSrc((wxBitmap
&)bmpSrc
);
2485 wxCHECK_RET( dataDst
&& dataSrc
,
2486 _T("failed to get raw data in wxAlphaBlend") );
2488 wxAlphaPixelData::Iterator
pDst(dataDst
),
2491 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2493 for ( int y
= 0; y
< h
; y
++ )
2495 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2496 pSrcRowStart
= pSrc
;
2498 for ( int x
= 0; x
< w
; x
++ )
2500 // note that source bitmap uses premultiplied alpha (as required by
2501 // the real AlphaBlend)
2502 const unsigned beta
= 255 - pSrc
.Alpha();
2504 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2505 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2506 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2512 pDst
= pDstRowStart
;
2513 pSrc
= pSrcRowStart
;
2514 pDst
.OffsetY(dataDst
, 1);
2515 pSrc
.OffsetY(dataSrc
, 1);
2518 // and finally blit them back to the destination DC
2519 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2521 wxLogLastError(_T("BitBlt"));
2525 #endif // #ifdef wxHAVE_RAW_BITMAP