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"
58 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
67 #define AC_SRC_ALPHA 1
70 /* Quaternary raster codes */
72 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
75 // apparently with MicroWindows it is possible that HDC is 0 so we have to
76 // check for this ourselves
78 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
79 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
81 #define WXMICROWIN_CHECK_HDC
82 #define WXMICROWIN_CHECK_HDC_RET(x)
85 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 static const int VIEWPORT_EXTENT
= 1000;
93 static const int MM_POINTS
= 9;
94 static const int MM_METRIC
= 10;
96 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
97 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
98 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
100 // ----------------------------------------------------------------------------
101 // macros for logical <-> device coords conversion
102 // ----------------------------------------------------------------------------
105 We currently let Windows do all the translations itself so these macros are
106 not really needed (any more) but keep them to enhance readability of the
107 code by allowing to see where are the logical and where are the device
112 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
113 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
114 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
115 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
117 #define XLOG2DEV(x) (x)
118 #define YLOG2DEV(y) (y)
119 #define XDEV2LOG(x) (x)
120 #define YDEV2LOG(y) (y)
123 // ---------------------------------------------------------------------------
125 // ---------------------------------------------------------------------------
127 // convert degrees to radians
128 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
130 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
132 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
133 // to pass it to this function but as we already have it at the point
134 // of call anyhow we do
136 // return true if we could draw the bitmap in one way or the other, false
138 static bool AlphaBlt(HDC hdcDst
,
139 int x
, int y
, int w
, int h
,
141 const wxBitmap
& bmpSrc
);
143 #ifdef wxHAVE_RAW_BITMAP
144 // our (limited) AlphaBlend() replacement
146 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
149 // ----------------------------------------------------------------------------
151 // ----------------------------------------------------------------------------
153 // instead of duplicating the same code which sets and then restores text
154 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
155 // encapsulate this in a small helper class
157 // wxColourChanger: changes the text colours in the ctor if required and
158 // restores them in the dtor
159 class wxColourChanger
162 wxColourChanger(wxDC
& dc
);
168 COLORREF m_colFgOld
, m_colBgOld
;
172 DECLARE_NO_COPY_CLASS(wxColourChanger
)
175 // this class saves the old stretch blit mode during its life time
176 class StretchBltModeChanger
179 StretchBltModeChanger(HDC hdc
, int mode
)
183 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
185 wxLogLastError(_T("SetStretchBltMode"));
191 ~StretchBltModeChanger()
194 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
195 wxLogLastError(_T("SetStretchBltMode"));
204 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
207 // ===========================================================================
209 // ===========================================================================
211 // ----------------------------------------------------------------------------
213 // ----------------------------------------------------------------------------
215 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
217 const wxBrush
& brush
= dc
.GetBrush();
218 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
220 HDC hdc
= GetHdcOf(dc
);
221 m_colFgOld
= ::GetTextColor(hdc
);
222 m_colBgOld
= ::GetBkColor(hdc
);
224 // note that Windows convention is opposite to wxWidgets one, this is
225 // why text colour becomes the background one and vice versa
226 const wxColour
& colFg
= dc
.GetTextForeground();
229 ::SetBkColor(hdc
, colFg
.GetPixel());
232 const wxColour
& colBg
= dc
.GetTextBackground();
235 ::SetTextColor(hdc
, colBg
.GetPixel());
239 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
242 // flag which telsl us to undo changes in the dtor
247 // nothing done, nothing to undo
252 wxColourChanger::~wxColourChanger()
256 // restore the colours we changed
257 HDC hdc
= GetHdcOf(m_dc
);
259 ::SetBkMode(hdc
, TRANSPARENT
);
260 ::SetTextColor(hdc
, m_colFgOld
);
261 ::SetBkColor(hdc
, m_colBgOld
);
265 // ---------------------------------------------------------------------------
267 // ---------------------------------------------------------------------------
269 // Default constructor
280 #endif // wxUSE_PALETTE
290 SelectOldObjects(m_hDC
);
292 // if we own the HDC, we delete it, otherwise we just release it
296 ::DeleteDC(GetHdc());
298 else // we don't own our HDC
302 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
306 // Must have been a wxScreenDC
307 ::ReleaseDC((HWND
) NULL
, GetHdc());
313 // This will select current objects out of the DC,
314 // which is what you have to do before deleting the
316 void wxDC::SelectOldObjects(WXHDC dc
)
322 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
324 if (m_selectedBitmap
.Ok())
326 m_selectedBitmap
.SetSelectedInto(NULL
);
333 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
338 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
343 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
350 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
353 #endif // wxUSE_PALETTE
356 m_brush
= wxNullBrush
;
359 m_palette
= wxNullPalette
;
360 #endif // wxUSE_PALETTE
362 m_backgroundBrush
= wxNullBrush
;
363 m_selectedBitmap
= wxNullBitmap
;
366 // ---------------------------------------------------------------------------
368 // ---------------------------------------------------------------------------
370 void wxDC::UpdateClipBox()
375 ::GetClipBox(GetHdc(), &rect
);
377 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
378 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
379 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
380 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
384 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
386 // check if we should try to retrieve the clipping region possibly not set
387 // by our SetClippingRegion() but preset by Windows:this can only happen
388 // when we're associated with an existing HDC usign SetHDC(), see there
389 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
391 wxDC
*self
= wxConstCast(this, wxDC
);
392 self
->UpdateClipBox();
394 if ( !m_clipX1
&& !m_clipX2
)
395 self
->m_clipping
= false;
398 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
401 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
402 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
404 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
408 // note that we combine the new clipping region with the existing one: this
409 // is compatible with what the other ports do and is the documented
410 // behaviour now (starting with 2.3.3)
411 #if defined(__WXWINCE__)
413 if ( !::GetClipBox(GetHdc(), &rectClip
) )
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
)
921 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
925 CalcBoundingBox(x
, y
);
926 CalcBoundingBox(x2
, y2
);
929 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
933 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
935 // Now, a negative radius value is interpreted to mean
936 // 'the proportion of the smallest X or Y dimension'
940 double smallest
= (width
< height
) ? width
: height
;
941 radius
= (- radius
* smallest
);
944 wxCoord x2
= (x
+width
);
945 wxCoord y2
= (y
+height
);
947 // Windows draws the filled rectangles without outline (i.e. drawn with a
948 // transparent pen) one pixel smaller in both directions and we want them
949 // to have the same size regardless of which pen is used - adjust
950 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
956 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
957 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
959 CalcBoundingBox(x
, y
);
960 CalcBoundingBox(x2
, y2
);
963 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
967 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
969 wxCoord x2
= (x
+width
);
970 wxCoord y2
= (y
+height
);
972 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
974 CalcBoundingBox(x
, y
);
975 CalcBoundingBox(x2
, y2
);
978 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
979 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
982 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
987 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
992 int rx1
= XLOG2DEV(x
+w
/2);
993 int ry1
= YLOG2DEV(y
+h
/2);
1000 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1001 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1002 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1003 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1005 // draw pie with NULL_PEN first and then outline otherwise a line is
1006 // drawn from the start and end points to the centre
1007 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1010 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1011 rx1
, ry1
, rx2
, ry2
);
1015 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1016 rx1
, ry1
-1, rx2
, ry2
-1);
1019 ::SelectObject(GetHdc(), hpenOld
);
1021 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1022 rx1
, ry1
, rx2
, ry2
);
1024 CalcBoundingBox(x
, y
);
1025 CalcBoundingBox(x2
, y2
);
1029 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1031 WXMICROWIN_CHECK_HDC
1033 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1036 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1038 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1041 CalcBoundingBox(x
, y
);
1042 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1045 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1047 WXMICROWIN_CHECK_HDC
1049 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1051 int width
= bmp
.GetWidth(),
1052 height
= bmp
.GetHeight();
1054 HBITMAP hbmpMask
= 0;
1057 HPALETTE oldPal
= 0;
1058 #endif // wxUSE_PALETTE
1060 if ( bmp
.HasAlpha() )
1063 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1065 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1071 wxMask
*mask
= bmp
.GetMask();
1073 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1077 // don't give assert here because this would break existing
1078 // programs - just silently ignore useMask parameter
1085 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1087 // On some systems, MaskBlt succeeds yet is much much slower
1088 // than the wxWidgets fall-back implementation. So we need
1089 // to be able to switch this on and off at runtime.
1091 #if wxUSE_SYSTEM_OPTIONS
1092 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1096 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1097 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1099 wxPalette
*pal
= bmp
.GetPalette();
1100 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1102 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1103 ::RealizePalette(hdcMem
);
1105 #endif // wxUSE_PALETTE
1107 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1110 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1114 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1115 #endif // wxUSE_PALETTE
1117 ::SelectObject(hdcMem
, hOldBitmap
);
1124 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1127 memDC
.SelectObject(bmp
);
1129 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1131 memDC
.SelectObject(wxNullBitmap
);
1134 else // no mask, just use BitBlt()
1137 HDC memdc
= ::CreateCompatibleDC( cdc
);
1138 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1140 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1142 COLORREF old_textground
= ::GetTextColor(GetHdc());
1143 COLORREF old_background
= ::GetBkColor(GetHdc());
1144 if (m_textForegroundColour
.Ok())
1146 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1148 if (m_textBackgroundColour
.Ok())
1150 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1154 wxPalette
*pal
= bmp
.GetPalette();
1155 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1157 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1158 ::RealizePalette(memdc
);
1160 #endif // wxUSE_PALETTE
1162 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1163 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1167 ::SelectPalette(memdc
, oldPal
, FALSE
);
1168 #endif // wxUSE_PALETTE
1170 ::SelectObject( memdc
, hOldBitmap
);
1171 ::DeleteDC( memdc
);
1173 ::SetTextColor(GetHdc(), old_textground
);
1174 ::SetBkColor(GetHdc(), old_background
);
1178 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1180 WXMICROWIN_CHECK_HDC
1182 DrawAnyText(text
, x
, y
);
1184 // update the bounding box
1185 CalcBoundingBox(x
, y
);
1188 GetTextExtent(text
, &w
, &h
);
1189 CalcBoundingBox(x
+ w
, y
+ h
);
1192 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1194 WXMICROWIN_CHECK_HDC
1196 // prepare for drawing the text
1197 if ( m_textForegroundColour
.Ok() )
1198 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1200 DWORD old_background
= 0;
1201 if ( m_textBackgroundColour
.Ok() )
1203 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1206 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1210 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1211 text
.c_str(), text
.length(), NULL
) == 0 )
1213 wxLogLastError(wxT("TextOut"));
1216 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1217 text
.c_str(), text
.length()) == 0 )
1219 wxLogLastError(wxT("TextOut"));
1223 // restore the old parameters (text foreground colour may be left because
1224 // it never is set to anything else, but background should remain
1225 // transparent even if we just drew an opaque string)
1226 if ( m_textBackgroundColour
.Ok() )
1227 (void)SetBkColor(GetHdc(), old_background
);
1229 SetBkMode(GetHdc(), TRANSPARENT
);
1232 void wxDC::DoDrawRotatedText(const wxString
& text
,
1233 wxCoord x
, wxCoord y
,
1236 WXMICROWIN_CHECK_HDC
1238 // we test that we have some font because otherwise we should still use the
1239 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1240 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1241 // font for drawing rotated fonts unfortunately)
1242 if ( (angle
== 0.0) && m_font
.Ok() )
1244 DoDrawText(text
, x
, y
);
1246 #ifndef __WXMICROWIN__
1249 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1250 // because it's not TrueType and so can't have non zero
1251 // orientation/escapement under Win9x
1252 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1253 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1255 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1257 wxLogLastError(wxT("GetObject(hfont)"));
1260 // GDI wants the angle in tenth of degree
1261 long angle10
= (long)(angle
* 10);
1262 lf
.lfEscapement
= angle10
;
1263 lf
. lfOrientation
= angle10
;
1265 hfont
= ::CreateFontIndirect(&lf
);
1268 wxLogLastError(wxT("CreateFont"));
1272 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1274 DrawAnyText(text
, x
, y
);
1276 (void)::SelectObject(GetHdc(), hfontOld
);
1277 (void)::DeleteObject(hfont
);
1280 // call the bounding box by adding all four vertices of the rectangle
1281 // containing the text to it (simpler and probably not slower than
1282 // determining which of them is really topmost/leftmost/...)
1284 GetTextExtent(text
, &w
, &h
);
1286 double rad
= DegToRad(angle
);
1288 // "upper left" and "upper right"
1289 CalcBoundingBox(x
, y
);
1290 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1292 // "bottom left" and "bottom right"
1293 x
+= (wxCoord
)(h
*sin(rad
));
1294 y
+= (wxCoord
)(h
*cos(rad
));
1295 CalcBoundingBox(x
, y
);
1296 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1301 // ---------------------------------------------------------------------------
1303 // ---------------------------------------------------------------------------
1307 void wxDC::DoSelectPalette(bool realize
)
1309 WXMICROWIN_CHECK_HDC
1311 // Set the old object temporarily, in case the assignment deletes an object
1312 // that's not yet selected out.
1315 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1319 if ( m_palette
.Ok() )
1321 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1322 GetHpaletteOf(m_palette
),
1325 m_oldPalette
= (WXHPALETTE
) oldPal
;
1328 ::RealizePalette(GetHdc());
1332 void wxDC::SetPalette(const wxPalette
& palette
)
1336 m_palette
= palette
;
1337 DoSelectPalette(true);
1341 void wxDC::InitializePalette()
1343 if ( wxDisplayDepth() <= 8 )
1345 // look for any window or parent that has a custom palette. If any has
1346 // one then we need to use it in drawing operations
1347 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1349 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1350 if ( m_hasCustomPalette
)
1352 m_palette
= win
->GetPalette();
1354 // turn on MSW translation for this palette
1360 #endif // wxUSE_PALETTE
1362 // SetFont/Pen/Brush() really ask to be implemented as a single template
1363 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1365 void wxDC::SetFont(const wxFont
& font
)
1367 WXMICROWIN_CHECK_HDC
1369 if ( font
== m_font
)
1374 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1375 if ( hfont
== HGDI_ERROR
)
1377 wxLogLastError(_T("SelectObject(font)"));
1382 m_oldFont
= (WXHPEN
)hfont
;
1387 else // invalid font, reset the current font
1391 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1393 wxLogLastError(_T("SelectObject(old font)"));
1399 m_font
= wxNullFont
;
1403 void wxDC::SetPen(const wxPen
& pen
)
1405 WXMICROWIN_CHECK_HDC
1412 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1413 if ( hpen
== HGDI_ERROR
)
1415 wxLogLastError(_T("SelectObject(pen)"));
1420 m_oldPen
= (WXHPEN
)hpen
;
1425 else // invalid pen, reset the current pen
1429 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1431 wxLogLastError(_T("SelectObject(old pen)"));
1441 void wxDC::SetBrush(const wxBrush
& brush
)
1443 WXMICROWIN_CHECK_HDC
1445 if ( brush
== m_brush
)
1450 // we must make sure the brush is aligned with the logical coordinates
1451 // before selecting it
1452 wxBitmap
*stipple
= brush
.GetStipple();
1453 if ( stipple
&& stipple
->Ok() )
1455 if ( !::SetBrushOrgEx
1458 m_deviceOriginX
% stipple
->GetWidth(),
1459 m_deviceOriginY
% stipple
->GetHeight(),
1460 NULL
// [out] previous brush origin
1463 wxLogLastError(_T("SetBrushOrgEx()"));
1467 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1468 if ( hbrush
== HGDI_ERROR
)
1470 wxLogLastError(_T("SelectObject(brush)"));
1475 m_oldBrush
= (WXHPEN
)hbrush
;
1480 else // invalid brush, reset the current brush
1484 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1486 wxLogLastError(_T("SelectObject(old brush)"));
1492 m_brush
= wxNullBrush
;
1496 void wxDC::SetBackground(const wxBrush
& brush
)
1498 WXMICROWIN_CHECK_HDC
1500 m_backgroundBrush
= brush
;
1502 if ( m_backgroundBrush
.Ok() )
1504 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1508 void wxDC::SetBackgroundMode(int mode
)
1510 WXMICROWIN_CHECK_HDC
1512 m_backgroundMode
= mode
;
1514 // SetBackgroundColour now only refers to text background
1515 // and m_backgroundMode is used there
1518 void wxDC::SetLogicalFunction(int function
)
1520 WXMICROWIN_CHECK_HDC
1522 m_logicalFunction
= function
;
1527 void wxDC::SetRop(WXHDC dc
)
1529 if ( !dc
|| m_logicalFunction
< 0 )
1534 switch (m_logicalFunction
)
1536 case wxCLEAR
: rop
= R2_BLACK
; break;
1537 case wxXOR
: rop
= R2_XORPEN
; break;
1538 case wxINVERT
: rop
= R2_NOT
; break;
1539 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1540 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1541 case wxCOPY
: rop
= R2_COPYPEN
; break;
1542 case wxAND
: rop
= R2_MASKPEN
; break;
1543 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1544 case wxNO_OP
: rop
= R2_NOP
; break;
1545 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1546 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1547 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1548 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1549 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1550 case wxOR
: rop
= R2_MERGEPEN
; break;
1551 case wxSET
: rop
= R2_WHITE
; break;
1554 wxFAIL_MSG( wxT("unsupported logical function") );
1558 SetROP2(GetHdc(), rop
);
1561 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1563 // We might be previewing, so return true to let it continue.
1571 void wxDC::StartPage()
1575 void wxDC::EndPage()
1579 // ---------------------------------------------------------------------------
1581 // ---------------------------------------------------------------------------
1583 wxCoord
wxDC::GetCharHeight() const
1585 WXMICROWIN_CHECK_HDC_RET(0)
1587 TEXTMETRIC lpTextMetric
;
1589 GetTextMetrics(GetHdc(), &lpTextMetric
);
1591 return lpTextMetric
.tmHeight
;
1594 wxCoord
wxDC::GetCharWidth() const
1596 WXMICROWIN_CHECK_HDC_RET(0)
1598 TEXTMETRIC lpTextMetric
;
1600 GetTextMetrics(GetHdc(), &lpTextMetric
);
1602 return lpTextMetric
.tmAveCharWidth
;
1605 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1606 wxCoord
*descent
, wxCoord
*externalLeading
,
1609 #ifdef __WXMICROWIN__
1614 if (descent
) *descent
= 0;
1615 if (externalLeading
) *externalLeading
= 0;
1618 #endif // __WXMICROWIN__
1623 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1625 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1627 else // don't change the font
1635 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1636 GetTextMetrics(GetHdc(), &tm
);
1643 *descent
= tm
.tmDescent
;
1644 if (externalLeading
)
1645 *externalLeading
= tm
.tmExternalLeading
;
1649 ::SelectObject(GetHdc(), hfontOld
);
1654 // Each element of the array will be the width of the string up to and
1655 // including the coresoponding character in text.
1657 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1659 static int maxLenText
= -1;
1660 static int maxWidth
= -1;
1663 int stlen
= text
.Length();
1665 if (maxLenText
== -1)
1667 // Win9x and WinNT+ have different limits
1668 int version
= wxGetOsVersion();
1669 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1670 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1674 widths
.Add(0, stlen
); // fill the array with zeros
1676 if (!::GetTextExtentExPoint(GetHdc(),
1677 text
.c_str(), // string to check
1678 wxMin(stlen
, maxLenText
),
1680 &fit
, // [out] count of chars
1682 &widths
[0], // array to fill
1686 wxLogLastError(wxT("GetTextExtentExPoint"));
1696 void wxDC::SetMapMode(int mode
)
1698 WXMICROWIN_CHECK_HDC
1700 m_mappingMode
= mode
;
1702 if ( mode
== wxMM_TEXT
)
1705 m_logicalScaleY
= 1.0;
1707 else // need to do some calculations
1709 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1710 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1711 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1712 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1714 if ( (mm_width
== 0) || (mm_height
== 0) )
1716 // we can't calculate mm2pixels[XY] then!
1720 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1721 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1726 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1727 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1731 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1732 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1736 m_logicalScaleX
= mm2pixelsX
;
1737 m_logicalScaleY
= mm2pixelsY
;
1741 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1742 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1746 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1750 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1751 // cases we could do with MM_TEXT and in the remaining 0.9% with
1752 // MM_ISOTROPIC (TODO!)
1754 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1756 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1757 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1759 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1760 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1762 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1763 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1767 void wxDC::SetUserScale(double x
, double y
)
1769 WXMICROWIN_CHECK_HDC
1771 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1777 this->SetMapMode(m_mappingMode
);
1780 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1782 WXMICROWIN_CHECK_HDC
1785 int signX
= xLeftRight
? 1 : -1,
1786 signY
= yBottomUp
? -1 : 1;
1788 if ( signX
!= m_signX
|| signY
!= m_signY
)
1793 SetMapMode(m_mappingMode
);
1796 wxUnusedVar(xLeftRight
);
1797 wxUnusedVar(yBottomUp
);
1801 void wxDC::SetSystemScale(double x
, double y
)
1803 WXMICROWIN_CHECK_HDC
1805 if ( x
== m_scaleX
&& y
== m_scaleY
)
1812 SetMapMode(m_mappingMode
);
1816 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1818 WXMICROWIN_CHECK_HDC
1820 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1823 m_logicalOriginX
= x
;
1824 m_logicalOriginY
= y
;
1827 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1831 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1833 WXMICROWIN_CHECK_HDC
1835 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1838 m_deviceOriginX
= x
;
1839 m_deviceOriginY
= y
;
1842 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1846 // ---------------------------------------------------------------------------
1847 // coordinates transformations
1848 // ---------------------------------------------------------------------------
1850 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1852 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1855 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1857 // axis orientation is not taken into account for conversion of a distance
1858 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1861 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1863 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1866 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1868 // axis orientation is not taken into account for conversion of a distance
1869 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1872 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1874 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1877 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1879 // axis orientation is not taken into account for conversion of a distance
1880 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1883 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1885 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1888 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1890 // axis orientation is not taken into account for conversion of a distance
1891 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1894 // ---------------------------------------------------------------------------
1896 // ---------------------------------------------------------------------------
1898 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1899 wxCoord width
, wxCoord height
,
1900 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1901 int rop
, bool useMask
,
1902 wxCoord xsrcMask
, wxCoord ysrcMask
)
1904 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1906 WXMICROWIN_CHECK_HDC_RET(false)
1908 // if either the source or destination has alpha channel, we must use
1909 // AlphaBlt() as other function don't handle it correctly
1910 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1911 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1912 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1914 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1915 GetHdcOf(*source
), bmpSrc
) )
1919 wxMask
*mask
= NULL
;
1922 mask
= bmpSrc
.GetMask();
1924 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1926 // don't give assert here because this would break existing
1927 // programs - just silently ignore useMask parameter
1932 if (xsrcMask
== -1 && ysrcMask
== -1)
1934 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1937 COLORREF old_textground
= ::GetTextColor(GetHdc());
1938 COLORREF old_background
= ::GetBkColor(GetHdc());
1939 if (m_textForegroundColour
.Ok())
1941 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1943 if (m_textBackgroundColour
.Ok())
1945 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1951 case wxXOR
: dwRop
= SRCINVERT
; break;
1952 case wxINVERT
: dwRop
= DSTINVERT
; break;
1953 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1954 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1955 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1956 case wxSET
: dwRop
= WHITENESS
; break;
1957 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1958 case wxAND
: dwRop
= SRCAND
; break;
1959 case wxOR
: dwRop
= SRCPAINT
; break;
1960 case wxEQUIV
: dwRop
= 0x00990066; break;
1961 case wxNAND
: dwRop
= 0x007700E6; break;
1962 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1963 case wxCOPY
: dwRop
= SRCCOPY
; break;
1964 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1965 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1966 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1968 wxFAIL_MSG( wxT("unsupported logical function") );
1972 bool success
= false;
1977 // we want the part of the image corresponding to the mask to be
1978 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1979 // meaning of fg and bg is inverted which corresponds to wxWin notion
1980 // of the mask which is also contrary to the Windows one)
1982 // On some systems, MaskBlt succeeds yet is much much slower
1983 // than the wxWidgets fall-back implementation. So we need
1984 // to be able to switch this on and off at runtime.
1985 #if wxUSE_SYSTEM_OPTIONS
1986 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1992 xdest
, ydest
, width
, height
,
1995 (HBITMAP
)mask
->GetMaskBitmap(),
1997 MAKEROP4(dwRop
, DSTCOPY
)
2004 // Blit bitmap with mask
2007 HBITMAP buffer_bmap
;
2009 #if wxUSE_DC_CACHEING
2010 // create a temp buffer bitmap and DCs to access it and the mask
2011 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2012 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2014 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2015 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2017 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2020 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2021 #else // !wxUSE_DC_CACHEING
2022 // create a temp buffer bitmap and DCs to access it and the mask
2023 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2024 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2025 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2026 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2027 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2028 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2030 // copy dest to buffer
2031 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2032 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2034 wxLogLastError(wxT("BitBlt"));
2037 // copy src to buffer using selected raster op
2038 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2039 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2041 wxLogLastError(wxT("BitBlt"));
2044 // set masked area in buffer to BLACK (pixel value 0)
2045 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2046 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2047 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2048 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2050 wxLogLastError(wxT("BitBlt"));
2053 // set unmasked area in dest to BLACK
2054 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2055 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2056 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2057 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2059 wxLogLastError(wxT("BitBlt"));
2061 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2062 ::SetTextColor(GetHdc(), prevCol
);
2064 // OR buffer to dest
2065 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2066 (int)width
, (int)height
,
2067 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2070 wxLogLastError(wxT("BitBlt"));
2073 // tidy up temporary DCs and bitmap
2074 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2075 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2077 #if !wxUSE_DC_CACHEING
2079 ::DeleteDC(dc_mask
);
2080 ::DeleteDC(dc_buffer
);
2081 ::DeleteObject(buffer_bmap
);
2086 else // no mask, just BitBlt() it
2088 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2089 // use StretchBlt() if available and finally fall back to BitBlt()
2091 // FIXME: use appropriate WinCE functions
2093 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2094 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2099 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2101 &ds
) == sizeof(ds
) )
2103 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2105 // Figure out what co-ordinate system we're supposed to specify
2107 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2111 ysrc
= hDIB
- (ysrc
+ height
);
2114 if ( ::StretchDIBits(GetHdc(),
2120 (LPBITMAPINFO
)&ds
.dsBmih
,
2123 ) == (int)GDI_ERROR
)
2125 // On Win9x this API fails most (all?) of the time, so
2126 // logging it becomes quite distracting. Since it falls
2127 // back to the code below this is not really serious, so
2129 //wxLogLastError(wxT("StretchDIBits"));
2138 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2143 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2149 xdest
, ydest
, width
, height
,
2151 xsrc
, ysrc
, width
, height
,
2155 wxLogLastError(_T("StretchBlt"));
2169 (int)width
, (int)height
,
2175 wxLogLastError(_T("BitBlt"));
2184 ::SetTextColor(GetHdc(), old_textground
);
2185 ::SetBkColor(GetHdc(), old_background
);
2190 void wxDC::DoGetSize(int *w
, int *h
) const
2192 WXMICROWIN_CHECK_HDC
2194 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2195 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2198 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2200 WXMICROWIN_CHECK_HDC
2202 // if we implement it in terms of DoGetSize() instead of directly using the
2203 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2204 // will also work for wxWindowDC and wxClientDC even though their size is
2205 // not the same as the total size of the screen
2206 int wPixels
, hPixels
;
2207 DoGetSize(&wPixels
, &hPixels
);
2211 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2213 wxCHECK_RET( wTotal
, _T("0 width device?") );
2215 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2220 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2222 wxCHECK_RET( hTotal
, _T("0 height device?") );
2224 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2228 wxSize
wxDC::GetPPI() const
2230 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2232 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2233 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2235 return wxSize(x
, y
);
2238 // For use by wxWidgets only, unless custom units are required.
2239 void wxDC::SetLogicalScale(double x
, double y
)
2241 WXMICROWIN_CHECK_HDC
2243 m_logicalScaleX
= x
;
2244 m_logicalScaleY
= y
;
2247 // ----------------------------------------------------------------------------
2249 // ----------------------------------------------------------------------------
2251 #if wxUSE_DC_CACHEING
2254 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2255 * improve it in due course, either using arrays, or simply storing pointers to one
2256 * entry for the bitmap, and two for the DCs. -- JACS
2259 wxList
wxDC::sm_bitmapCache
;
2260 wxList
wxDC::sm_dcCache
;
2262 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2271 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2280 wxDCCacheEntry::~wxDCCacheEntry()
2283 ::DeleteObject((HBITMAP
) m_bitmap
);
2285 ::DeleteDC((HDC
) m_dc
);
2288 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2290 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2291 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2294 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2296 if (entry
->m_depth
== depth
)
2298 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2300 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2301 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2302 if ( !entry
->m_bitmap
)
2304 wxLogLastError(wxT("CreateCompatibleBitmap"));
2306 entry
->m_width
= w
; entry
->m_height
= h
;
2312 node
= node
->GetNext();
2314 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2317 wxLogLastError(wxT("CreateCompatibleBitmap"));
2319 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2320 AddToBitmapCache(entry
);
2324 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2326 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2327 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2330 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2332 // Don't return the same one as we already have
2333 if (!notThis
|| (notThis
!= entry
))
2335 if (entry
->m_depth
== depth
)
2341 node
= node
->GetNext();
2343 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2346 wxLogLastError(wxT("CreateCompatibleDC"));
2348 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2349 AddToDCCache(entry
);
2353 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2355 sm_bitmapCache
.Append(entry
);
2358 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2360 sm_dcCache
.Append(entry
);
2363 void wxDC::ClearCache()
2365 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2366 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2369 // Clean up cache at app exit
2370 class wxDCModule
: public wxModule
2373 virtual bool OnInit() { return true; }
2374 virtual void OnExit() { wxDC::ClearCache(); }
2377 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2380 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2382 #endif // wxUSE_DC_CACHEING
2384 // ----------------------------------------------------------------------------
2385 // alpha channel support
2386 // ----------------------------------------------------------------------------
2388 static bool AlphaBlt(HDC hdcDst
,
2389 int x
, int y
, int width
, int height
,
2391 const wxBitmap
& bmp
)
2393 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2394 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2396 // do we have AlphaBlend() and company in the headers?
2397 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2398 // yes, now try to see if we have it during run-time
2399 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2400 HDC
,int,int,int,int,
2403 // bitmaps can be drawn only from GUI thread so there is no need to
2404 // protect this static variable from multiple threads
2405 static bool s_triedToLoad
= false;
2406 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2407 if ( !s_triedToLoad
)
2409 s_triedToLoad
= true;
2411 // don't give errors about the DLL being unavailable, we're
2412 // prepared to handle this
2415 wxDynamicLibrary
dll(_T("msimg32.dll"));
2416 if ( dll
.IsLoaded() )
2418 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2419 if ( pfnAlphaBlend
)
2421 // we must keep the DLL loaded if we want to be able to
2422 // call AlphaBlend() so just never unload it at all, not a
2429 if ( pfnAlphaBlend
)
2432 bf
.BlendOp
= AC_SRC_OVER
;
2434 bf
.SourceConstantAlpha
= 0xff;
2435 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2437 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2438 hdcSrc
, 0, 0, width
, height
,
2441 // skip wxAlphaBlend() call below
2445 wxLogLastError(_T("AlphaBlend"));
2447 #endif // defined(AC_SRC_OVER)
2449 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2451 #ifdef wxHAVE_RAW_BITMAP
2452 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2455 #else // !wxHAVE_RAW_BITMAP
2456 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2457 // alpha but at least something will be shown like this)
2460 #endif // wxHAVE_RAW_BITMAP
2464 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2465 #ifdef wxHAVE_RAW_BITMAP
2468 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2470 // get the destination DC pixels
2471 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2473 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2475 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2477 wxLogLastError(_T("BitBlt"));
2480 // combine them with the source bitmap using alpha
2481 wxAlphaPixelData
dataDst(bmpDst
),
2482 dataSrc((wxBitmap
&)bmpSrc
);
2484 wxCHECK_RET( dataDst
&& dataSrc
,
2485 _T("failed to get raw data in wxAlphaBlend") );
2487 wxAlphaPixelData::Iterator
pDst(dataDst
),
2490 for ( int y
= 0; y
< h
; y
++ )
2492 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2493 pSrcRowStart
= pSrc
;
2495 for ( int x
= 0; x
< w
; x
++ )
2497 // note that source bitmap uses premultiplied alpha (as required by
2498 // the real AlphaBlend)
2499 const unsigned beta
= 255 - pSrc
.Alpha();
2501 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2502 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2503 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2509 pDst
= pDstRowStart
;
2510 pSrc
= pSrcRowStart
;
2511 pDst
.OffsetY(dataDst
, 1);
2512 pSrc
.OffsetY(dataSrc
, 1);
2515 // and finally blit them back to the destination DC
2516 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2518 wxLogLastError(_T("BitBlt"));
2522 #endif // #ifdef wxHAVE_RAW_BITMAP