1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/window.h"
35 #include "wx/dialog.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
43 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
44 #include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
46 #include "wx/sysopt.h"
47 #include "wx/dcprint.h"
48 #include "wx/module.h"
49 #include "wx/dynload.h"
51 #ifdef wxHAVE_RAW_BITMAP
52 #include "wx/rawbmp.h"
58 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
67 #define AC_SRC_ALPHA 1
70 /* Quaternary raster codes */
72 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
75 // apparently with MicroWindows it is possible that HDC is 0 so we have to
76 // check for this ourselves
78 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
79 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
81 #define WXMICROWIN_CHECK_HDC
82 #define WXMICROWIN_CHECK_HDC_RET(x)
85 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 static const int VIEWPORT_EXTENT
= 1000;
93 static const int MM_POINTS
= 9;
94 static const int MM_METRIC
= 10;
96 // usually this is defined in math.h
98 static const double M_PI
= 3.14159265358979323846;
101 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
102 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
103 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
105 // ----------------------------------------------------------------------------
106 // macros for logical <-> device coords conversion
107 // ----------------------------------------------------------------------------
110 We currently let Windows do all the translations itself so these macros are
111 not really needed (any more) but keep them to enhance readability of the
112 code by allowing to see where are the logical and where are the device
117 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
118 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
119 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
120 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
122 #define XLOG2DEV(x) (x)
123 #define YLOG2DEV(y) (y)
124 #define XDEV2LOG(x) (x)
125 #define YDEV2LOG(y) (y)
128 // ---------------------------------------------------------------------------
130 // ---------------------------------------------------------------------------
132 // convert degrees to radians
133 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
135 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
137 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
138 // to pass it to this function but as we already have it at the point
139 // of call anyhow we do
141 // return true if we could draw the bitmap in one way or the other, false
143 static bool AlphaBlt(HDC hdcDst
,
144 int x
, int y
, int w
, int h
,
146 const wxBitmap
& bmpSrc
);
148 #ifdef wxHAVE_RAW_BITMAP
149 // our (limited) AlphaBlend() replacement
151 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
154 // ----------------------------------------------------------------------------
156 // ----------------------------------------------------------------------------
158 // instead of duplicating the same code which sets and then restores text
159 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
160 // encapsulate this in a small helper class
162 // wxColourChanger: changes the text colours in the ctor if required and
163 // restores them in the dtor
164 class wxColourChanger
167 wxColourChanger(wxDC
& dc
);
173 COLORREF m_colFgOld
, m_colBgOld
;
177 DECLARE_NO_COPY_CLASS(wxColourChanger
)
180 // this class saves the old stretch blit mode during its life time
181 class StretchBltModeChanger
184 StretchBltModeChanger(HDC hdc
, int mode
)
188 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
190 wxLogLastError(_T("SetStretchBltMode"));
194 ~StretchBltModeChanger()
197 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
198 wxLogLastError(_T("SetStretchBltMode"));
207 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
210 // ===========================================================================
212 // ===========================================================================
214 // ----------------------------------------------------------------------------
216 // ----------------------------------------------------------------------------
218 wxColourChanger
::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
220 const wxBrush
& brush
= dc
.GetBrush();
221 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
223 HDC hdc
= GetHdcOf(dc
);
224 m_colFgOld
= ::GetTextColor(hdc
);
225 m_colBgOld
= ::GetBkColor(hdc
);
227 // note that Windows convention is opposite to wxWindows one, this is
228 // why text colour becomes the background one and vice versa
229 const wxColour
& colFg
= dc
.GetTextForeground();
232 ::SetBkColor(hdc
, colFg
.GetPixel());
235 const wxColour
& colBg
= dc
.GetTextBackground();
238 ::SetTextColor(hdc
, colBg
.GetPixel());
242 dc
.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT
245 // flag which telsl us to undo changes in the dtor
250 // nothing done, nothing to undo
255 wxColourChanger
::~wxColourChanger()
259 // restore the colours we changed
260 HDC hdc
= GetHdcOf(m_dc
);
262 ::SetBkMode(hdc
, TRANSPARENT
);
263 ::SetTextColor(hdc
, m_colFgOld
);
264 ::SetBkColor(hdc
, m_colBgOld
);
268 // ---------------------------------------------------------------------------
270 // ---------------------------------------------------------------------------
272 // Default constructor
283 #endif // wxUSE_PALETTE
293 SelectOldObjects(m_hDC
);
295 // if we own the HDC, we delete it, otherwise we just release it
299 ::DeleteDC(GetHdc());
301 else // we don't own our HDC
305 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
309 // Must have been a wxScreenDC
310 ::ReleaseDC((HWND
) NULL
, GetHdc());
316 // This will select current objects out of the DC,
317 // which is what you have to do before deleting the
319 void wxDC
::SelectOldObjects(WXHDC dc
)
325 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
327 if (m_selectedBitmap
.Ok())
329 m_selectedBitmap
.SetSelectedInto(NULL
);
336 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
341 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
346 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
353 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
356 #endif // wxUSE_PALETTE
359 m_brush
= wxNullBrush
;
362 m_palette
= wxNullPalette
;
363 #endif // wxUSE_PALETTE
365 m_backgroundBrush
= wxNullBrush
;
366 m_selectedBitmap
= wxNullBitmap
;
369 // ---------------------------------------------------------------------------
371 // ---------------------------------------------------------------------------
373 void wxDC
::UpdateClipBox()
378 ::GetClipBox(GetHdc(), &rect
);
380 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
381 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
382 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
383 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
387 wxDC
::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
389 // check if we should try to retrieve the clipping region possibly not set
390 // by our SetClippingRegion() but preset by Windows:this can only happen
391 // when we're associated with an existing HDC usign SetHDC(), see there
392 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
396 if ( !m_clipX1
&& !m_clipX2
)
400 return wxDCBase
::DoGetClippingBox(x
, y
, w
, h
);
403 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
404 void wxDC
::SetClippingHrgn(WXHRGN hrgn
)
406 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
410 // note that we combine the new clipping region with the existing one: this
411 // is compatible with what the other ports do and is the documented
412 // behaviour now (starting with 2.3.3)
413 #if defined(__WXWINCE__)
415 if ( !::GetClipBox(GetHdc(), &rectClip
) )
418 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
419 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
420 rectClip
.right
, rectClip
.bottom
);
422 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
424 ::SelectClipRgn(GetHdc(), hrgnDest
);
427 ::DeleteObject(hrgnClipOld
);
428 ::DeleteObject(hrgnDest
);
430 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
432 wxLogLastError(_T("ExtSelectClipRgn"));
436 #endif // WinCE/!WinCE
443 void wxDC
::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
445 // the region coords are always the device ones, so do the translation
448 // FIXME: possible +/-1 error here, to check!
449 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
451 LogicalToDeviceX(x
+ w
),
452 LogicalToDeviceY(y
+ h
));
455 wxLogLastError(_T("CreateRectRgn"));
459 SetClippingHrgn((WXHRGN
)hrgn
);
461 ::DeleteObject(hrgn
);
465 void wxDC
::DoSetClippingRegionAsRegion(const wxRegion
& region
)
467 SetClippingHrgn(region
.GetHRGN());
470 void wxDC
::DestroyClippingRegion()
474 if (m_clipping
&& m_hDC
)
476 // TODO: this should restore the previous clipping region,
477 // so that OnPaint processing works correctly, and the update
478 // clipping region doesn't get destroyed after the first
479 // DestroyClippingRegion.
480 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
481 ::SelectClipRgn(GetHdc(), rgn
);
485 wxDCBase
::DestroyClippingRegion();
488 // ---------------------------------------------------------------------------
489 // query capabilities
490 // ---------------------------------------------------------------------------
492 bool wxDC
::CanDrawBitmap() const
497 bool wxDC
::CanGetTextExtent() const
499 #ifdef __WXMICROWIN__
500 // TODO Extend MicroWindows' GetDeviceCaps function
503 // What sort of display is it?
504 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
506 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
510 int wxDC
::GetDepth() const
512 WXMICROWIN_CHECK_HDC_RET(16)
514 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
517 // ---------------------------------------------------------------------------
519 // ---------------------------------------------------------------------------
528 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
532 // No, I think we should simply ignore this if printing on e.g.
534 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
535 if (!m_selectedBitmap
.Ok())
538 rect
.left
= 0; rect
.top
= 0;
539 rect
.right
= m_selectedBitmap
.GetWidth();
540 rect
.bottom
= m_selectedBitmap
.GetHeight();
544 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
547 DWORD colour
= ::GetBkColor(GetHdc());
548 HBRUSH brush
= ::CreateSolidBrush(colour
);
549 ::FillRect(GetHdc(), &rect
, brush
);
550 ::DeleteObject(brush
);
552 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
553 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
556 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
558 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
559 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
560 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
561 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
565 bool wxDC
::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
571 WXMICROWIN_CHECK_HDC_RET(false)
573 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
575 style
== wxFLOOD_SURFACE ? FLOODFILLSURFACE
576 : FLOODFILLBORDER
) ) ;
579 // quoting from the MSDN docs:
581 // Following are some of the reasons this function might fail:
583 // * The filling could not be completed.
584 // * The specified point has the boundary color specified by the
585 // crColor parameter (if FLOODFILLBORDER was requested).
586 // * The specified point does not have the color specified by
587 // crColor (if FLOODFILLSURFACE was requested)
588 // * The point is outside the clipping region that is, it is not
589 // visible on the device.
591 wxLogLastError(wxT("ExtFloodFill"));
594 CalcBoundingBox(x
, y
);
600 bool wxDC
::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
602 WXMICROWIN_CHECK_HDC_RET(false)
604 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
606 // get the color of the pixel
607 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
609 wxRGBToColour(*col
, pixelcolor
);
614 void wxDC
::DoCrossHair(wxCoord x
, wxCoord y
)
618 wxCoord x1
= x
-VIEWPORT_EXTENT
;
619 wxCoord y1
= y
-VIEWPORT_EXTENT
;
620 wxCoord x2
= x
+VIEWPORT_EXTENT
;
621 wxCoord y2
= y
+VIEWPORT_EXTENT
;
623 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
624 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
626 CalcBoundingBox(x1
, y1
);
627 CalcBoundingBox(x2
, y2
);
630 void wxDC
::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
634 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
636 CalcBoundingBox(x1
, y1
);
637 CalcBoundingBox(x2
, y2
);
640 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
641 // and ending at (x2, y2)
642 void wxDC
::DoDrawArc(wxCoord x1
, wxCoord y1
,
643 wxCoord x2
, wxCoord y2
,
644 wxCoord xc
, wxCoord yc
)
647 // Slower emulation since WinCE doesn't support Pie and Arc
648 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
649 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
650 if( y1
>yc
) sa
= -sa
; // below center
651 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
652 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
657 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
661 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
662 wxCoord r
= (wxCoord
)radius
;
664 // treat the special case of full circle separately
665 if ( x1
== x2
&& y1
== y2
)
667 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
671 wxCoord xx1
= XLOG2DEV(x1
);
672 wxCoord yy1
= YLOG2DEV(y1
);
673 wxCoord xx2
= XLOG2DEV(x2
);
674 wxCoord yy2
= YLOG2DEV(y2
);
675 wxCoord xxc
= XLOG2DEV(xc
);
676 wxCoord yyc
= YLOG2DEV(yc
);
677 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
679 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
680 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
681 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
682 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
684 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
686 // Have to add 1 to bottom-right corner of rectangle
687 // to make semi-circles look right (crooked line otherwise).
688 // Unfortunately this is not a reliable method, depends
689 // on the size of shape.
690 // TODO: figure out why this happens!
691 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
695 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
698 CalcBoundingBox(xc
- r
, yc
- r
);
699 CalcBoundingBox(xc
+ r
, yc
+ r
);
703 void wxDC
::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
704 wxCoord width
, wxCoord height
)
708 wxCoord x2
= x1
+ width
,
711 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
719 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
721 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
723 #else // Symantec-MicroWin
725 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
726 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
727 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
728 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
729 ::SetROP2(GetHdc(), R2_COPYPEN
);
730 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
731 MoveToEx(GetHdc(), x1
, y1
, NULL
);
732 LineTo(GetHdc(), x2
, y2
);
733 MoveToEx(GetHdc(), x2
, y1
, NULL
);
734 LineTo(GetHdc(), x1
, y2
);
735 ::SelectObject(GetHdc(), hPenOld
);
736 ::SelectObject(GetHdc(), hBrushOld
);
737 ::DeleteObject(blackPen
);
738 #endif // Win32/Symantec-MicroWin
740 CalcBoundingBox(x1
, y1
);
741 CalcBoundingBox(x2
, y2
);
744 void wxDC
::DoDrawPoint(wxCoord x
, wxCoord y
)
748 COLORREF color
= 0x00ffffff;
751 color
= m_pen
.GetColour().GetPixel();
754 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
756 CalcBoundingBox(x
, y
);
759 void wxDC
::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
763 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
765 // Do things less efficiently if we have offsets
766 if (xoffset
!= 0 || yoffset
!= 0)
768 POINT
*cpoints
= new POINT
[n
];
770 for (i
= 0; i
< n
; i
++)
772 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
773 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
775 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
778 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE?ALTERNATE
:WINDING
);
780 (void)Polygon(GetHdc(), cpoints
, n
);
782 SetPolyFillMode(GetHdc(),prev
);
789 for (i
= 0; i
< n
; i
++)
790 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
793 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE?ALTERNATE
:WINDING
);
795 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
797 SetPolyFillMode(GetHdc(),prev
);
803 wxDC
::DoDrawPolyPolygon(int n
,
811 wxDCBase
::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
815 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
817 for (i
= cnt
= 0; i
< n
; i
++)
820 // Do things less efficiently if we have offsets
821 if (xoffset
!= 0 || yoffset
!= 0)
823 POINT
*cpoints
= new POINT
[cnt
];
824 for (i
= 0; i
< cnt
; i
++)
826 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
827 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
829 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
832 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE?ALTERNATE
:WINDING
);
834 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
836 SetPolyFillMode(GetHdc(),prev
);
842 for (i
= 0; i
< cnt
; i
++)
843 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
846 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE?ALTERNATE
:WINDING
);
848 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
850 SetPolyFillMode(GetHdc(),prev
);
857 void wxDC
::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
861 // Do things less efficiently if we have offsets
862 if (xoffset
!= 0 || yoffset
!= 0)
864 POINT
*cpoints
= new POINT
[n
];
866 for (i
= 0; i
< n
; i
++)
868 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
869 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
871 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
873 (void)Polyline(GetHdc(), cpoints
, n
);
879 for (i
= 0; i
< n
; i
++)
880 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
882 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
886 void wxDC
::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
890 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
892 wxCoord x2
= x
+ width
;
893 wxCoord y2
= y
+ height
;
895 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
898 rect
.left
= XLOG2DEV(x
);
899 rect
.top
= YLOG2DEV(y
);
900 rect
.right
= XLOG2DEV(x2
);
901 rect
.bottom
= YLOG2DEV(y2
);
902 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
906 // Windows draws the filled rectangles without outline (i.e. drawn with a
907 // transparent pen) one pixel smaller in both directions and we want them
908 // to have the same size regardless of which pen is used - adjust
910 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
911 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
917 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
921 CalcBoundingBox(x
, y
);
922 CalcBoundingBox(x2
, y2
);
925 void wxDC
::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
929 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
931 // Now, a negative radius value is interpreted to mean
932 // 'the proportion of the smallest X or Y dimension'
936 double smallest
= (width
< height
) ? width
: height
;
937 radius
= (- radius
* smallest
);
940 wxCoord x2
= (x
+width
);
941 wxCoord y2
= (y
+height
);
943 // Windows draws the filled rectangles without outline (i.e. drawn with a
944 // transparent pen) one pixel smaller in both directions and we want them
945 // to have the same size regardless of which pen is used - adjust
946 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
952 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
953 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
955 CalcBoundingBox(x
, y
);
956 CalcBoundingBox(x2
, y2
);
959 void wxDC
::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
963 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
965 wxCoord x2
= (x
+width
);
966 wxCoord y2
= (y
+height
);
968 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
970 CalcBoundingBox(x
, y
);
971 CalcBoundingBox(x2
, y2
);
974 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
975 void wxDC
::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
978 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
983 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
988 int rx1
= XLOG2DEV(x
+w
/2);
989 int ry1
= YLOG2DEV(y
+h
/2);
996 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
997 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
998 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
999 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1001 // draw pie with NULL_PEN first and then outline otherwise a line is
1002 // drawn from the start and end points to the centre
1003 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1006 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1007 rx1
, ry1
, rx2
, ry2
);
1011 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1012 rx1
, ry1
-1, rx2
, ry2
-1);
1015 ::SelectObject(GetHdc(), hpenOld
);
1017 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1018 rx1
, ry1
, rx2
, ry2
);
1020 CalcBoundingBox(x
, y
);
1021 CalcBoundingBox(x2
, y2
);
1025 void wxDC
::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1027 WXMICROWIN_CHECK_HDC
1029 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1032 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1034 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1037 CalcBoundingBox(x
, y
);
1038 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1041 void wxDC
::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1043 WXMICROWIN_CHECK_HDC
1045 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1047 int width
= bmp
.GetWidth(),
1048 height
= bmp
.GetHeight();
1050 HBITMAP hbmpMask
= 0;
1053 HPALETTE oldPal
= 0;
1054 #endif // wxUSE_PALETTE
1056 if ( bmp
.HasAlpha() )
1059 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1061 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1067 wxMask
*mask
= bmp
.GetMask();
1069 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1073 // don't give assert here because this would break existing
1074 // programs - just silently ignore useMask parameter
1081 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1083 // On some systems, MaskBlt succeeds yet is much much slower
1084 // than the wxWindows fall-back implementation. So we need
1085 // to be able to switch this on and off at runtime.
1087 #if wxUSE_SYSTEM_OPTIONS
1088 if (wxSystemOptions
::GetOptionInt(wxT("no-maskblt")) == 0)
1092 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1093 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1095 wxPalette
*pal
= bmp
.GetPalette();
1096 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1098 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1099 ::RealizePalette(hdcMem
);
1101 #endif // wxUSE_PALETTE
1103 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1106 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1110 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1111 #endif // wxUSE_PALETTE
1113 ::SelectObject(hdcMem
, hOldBitmap
);
1120 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1123 memDC
.SelectObject(bmp
);
1125 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1127 memDC
.SelectObject(wxNullBitmap
);
1130 else // no mask, just use BitBlt()
1133 HDC memdc
= ::CreateCompatibleDC( cdc
);
1134 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1136 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1138 COLORREF old_textground
= ::GetTextColor(GetHdc());
1139 COLORREF old_background
= ::GetBkColor(GetHdc());
1140 if (m_textForegroundColour
.Ok())
1142 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1144 if (m_textBackgroundColour
.Ok())
1146 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1150 wxPalette
*pal
= bmp
.GetPalette();
1151 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1153 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1154 ::RealizePalette(memdc
);
1156 #endif // wxUSE_PALETTE
1158 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1159 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1163 ::SelectPalette(memdc
, oldPal
, FALSE
);
1164 #endif // wxUSE_PALETTE
1166 ::SelectObject( memdc
, hOldBitmap
);
1167 ::DeleteDC( memdc
);
1169 ::SetTextColor(GetHdc(), old_textground
);
1170 ::SetBkColor(GetHdc(), old_background
);
1174 void wxDC
::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1176 WXMICROWIN_CHECK_HDC
1178 DrawAnyText(text
, x
, y
);
1180 // update the bounding box
1181 CalcBoundingBox(x
, y
);
1184 GetTextExtent(text
, &w
, &h
);
1185 CalcBoundingBox(x
+ w
, y
+ h
);
1188 void wxDC
::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1190 WXMICROWIN_CHECK_HDC
1192 // prepare for drawing the text
1193 if ( m_textForegroundColour
.Ok() )
1194 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1196 DWORD old_background
= 0;
1197 if ( m_textBackgroundColour
.Ok() )
1199 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1202 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT ? TRANSPARENT
1206 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1207 text
.c_str(), text
.length(), NULL
) == 0 )
1209 wxLogLastError(wxT("TextOut"));
1212 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1213 text
.c_str(), text
.length()) == 0 )
1215 wxLogLastError(wxT("TextOut"));
1219 // restore the old parameters (text foreground colour may be left because
1220 // it never is set to anything else, but background should remain
1221 // transparent even if we just drew an opaque string)
1222 if ( m_textBackgroundColour
.Ok() )
1223 (void)SetBkColor(GetHdc(), old_background
);
1225 SetBkMode(GetHdc(), TRANSPARENT
);
1228 void wxDC
::DoDrawRotatedText(const wxString
& text
,
1229 wxCoord x
, wxCoord y
,
1232 WXMICROWIN_CHECK_HDC
1234 // we test that we have some font because otherwise we should still use the
1235 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1236 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1237 // font for drawing rotated fonts unfortunately)
1238 if ( (angle
== 0.0) && m_font
.Ok() )
1240 DoDrawText(text
, x
, y
);
1242 #ifndef __WXMICROWIN__
1245 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1246 // because it's not TrueType and so can't have non zero
1247 // orientation/escapement under Win9x
1248 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1249 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1251 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1253 wxLogLastError(wxT("GetObject(hfont)"));
1256 // GDI wants the angle in tenth of degree
1257 long angle10
= (long)(angle
* 10);
1258 lf
.lfEscapement
= angle10
;
1259 lf
. lfOrientation
= angle10
;
1261 hfont
= ::CreateFontIndirect(&lf
);
1264 wxLogLastError(wxT("CreateFont"));
1268 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1270 DrawAnyText(text
, x
, y
);
1272 (void)::SelectObject(GetHdc(), hfontOld
);
1273 (void)::DeleteObject(hfont
);
1276 // call the bounding box by adding all four vertices of the rectangle
1277 // containing the text to it (simpler and probably not slower than
1278 // determining which of them is really topmost/leftmost/...)
1280 GetTextExtent(text
, &w
, &h
);
1282 double rad
= DegToRad(angle
);
1284 // "upper left" and "upper right"
1285 CalcBoundingBox(x
, y
);
1286 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1288 // "bottom left" and "bottom right"
1289 x
+= (wxCoord
)(h
*sin(rad
));
1290 y
+= (wxCoord
)(h
*cos(rad
));
1291 CalcBoundingBox(x
, y
);
1292 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1297 // ---------------------------------------------------------------------------
1299 // ---------------------------------------------------------------------------
1303 void wxDC
::DoSelectPalette(bool realize
)
1305 WXMICROWIN_CHECK_HDC
1307 // Set the old object temporarily, in case the assignment deletes an object
1308 // that's not yet selected out.
1311 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1315 if ( m_palette
.Ok() )
1317 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1318 GetHpaletteOf(m_palette
),
1321 m_oldPalette
= (WXHPALETTE
) oldPal
;
1324 ::RealizePalette(GetHdc());
1328 void wxDC
::SetPalette(const wxPalette
& palette
)
1332 m_palette
= palette
;
1333 DoSelectPalette(true);
1337 void wxDC
::InitializePalette()
1339 if ( wxDisplayDepth() <= 8 )
1341 // look for any window or parent that has a custom palette. If any has
1342 // one then we need to use it in drawing operations
1343 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1345 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1346 if ( m_hasCustomPalette
)
1348 m_palette
= win
->GetPalette();
1350 // turn on MSW translation for this palette
1356 #endif // wxUSE_PALETTE
1358 // SetFont/Pen/Brush() really ask to be implemented as a single template
1359 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1361 void wxDC
::SetFont(const wxFont
& font
)
1363 WXMICROWIN_CHECK_HDC
1365 if ( font
== m_font
)
1370 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1371 if ( hfont
== HGDI_ERROR
)
1373 wxLogLastError(_T("SelectObject(font)"));
1378 m_oldFont
= (WXHPEN
)hfont
;
1383 else // invalid font, reset the current font
1387 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1389 wxLogLastError(_T("SelectObject(old font)"));
1395 m_font
= wxNullFont
;
1399 void wxDC
::SetPen(const wxPen
& pen
)
1401 WXMICROWIN_CHECK_HDC
1408 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1409 if ( hpen
== HGDI_ERROR
)
1411 wxLogLastError(_T("SelectObject(pen)"));
1416 m_oldPen
= (WXHPEN
)hpen
;
1421 else // invalid pen, reset the current pen
1425 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1427 wxLogLastError(_T("SelectObject(old pen)"));
1437 void wxDC
::SetBrush(const wxBrush
& brush
)
1439 WXMICROWIN_CHECK_HDC
1441 if ( brush
== m_brush
)
1446 // we must make sure the brush is aligned with the logical coordinates
1447 // before selecting it
1448 wxBitmap
*stipple
= brush
.GetStipple();
1449 if ( stipple
&& stipple
->Ok() )
1451 if ( !::SetBrushOrgEx
1454 m_deviceOriginX
% stipple
->GetWidth(),
1455 m_deviceOriginY
% stipple
->GetHeight(),
1456 NULL
// [out] previous brush origin
1459 wxLogLastError(_T("SetBrushOrgEx()"));
1463 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1464 if ( hbrush
== HGDI_ERROR
)
1466 wxLogLastError(_T("SelectObject(brush)"));
1471 m_oldBrush
= (WXHPEN
)hbrush
;
1476 else // invalid brush, reset the current brush
1480 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1482 wxLogLastError(_T("SelectObject(old brush)"));
1488 m_brush
= wxNullBrush
;
1492 void wxDC
::SetBackground(const wxBrush
& brush
)
1494 WXMICROWIN_CHECK_HDC
1496 m_backgroundBrush
= brush
;
1498 if ( m_backgroundBrush
.Ok() )
1500 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1504 void wxDC
::SetBackgroundMode(int mode
)
1506 WXMICROWIN_CHECK_HDC
1508 m_backgroundMode
= mode
;
1510 // SetBackgroundColour now only refers to text background
1511 // and m_backgroundMode is used there
1514 void wxDC
::SetLogicalFunction(int function
)
1516 WXMICROWIN_CHECK_HDC
1518 m_logicalFunction
= function
;
1523 void wxDC
::SetRop(WXHDC dc
)
1525 if ( !dc
|| m_logicalFunction
< 0 )
1530 switch (m_logicalFunction
)
1532 case wxCLEAR
: rop
= R2_BLACK
; break;
1533 case wxXOR
: rop
= R2_XORPEN
; break;
1534 case wxINVERT
: rop
= R2_NOT
; break;
1535 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1536 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1537 case wxCOPY
: rop
= R2_COPYPEN
; break;
1538 case wxAND
: rop
= R2_MASKPEN
; break;
1539 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1540 case wxNO_OP
: rop
= R2_NOP
; break;
1541 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1542 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1543 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1544 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1545 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1546 case wxOR
: rop
= R2_MERGEPEN
; break;
1547 case wxSET
: rop
= R2_WHITE
; break;
1550 wxFAIL_MSG( wxT("unsupported logical function") );
1554 SetROP2(GetHdc(), rop
);
1557 bool wxDC
::StartDoc(const wxString
& WXUNUSED(message
))
1559 // We might be previewing, so return true to let it continue.
1567 void wxDC
::StartPage()
1571 void wxDC
::EndPage()
1575 // ---------------------------------------------------------------------------
1577 // ---------------------------------------------------------------------------
1579 wxCoord wxDC
::GetCharHeight() const
1581 WXMICROWIN_CHECK_HDC_RET(0)
1583 TEXTMETRIC lpTextMetric
;
1585 GetTextMetrics(GetHdc(), &lpTextMetric
);
1587 return lpTextMetric
.tmHeight
;
1590 wxCoord wxDC
::GetCharWidth() const
1592 WXMICROWIN_CHECK_HDC_RET(0)
1594 TEXTMETRIC lpTextMetric
;
1596 GetTextMetrics(GetHdc(), &lpTextMetric
);
1598 return lpTextMetric
.tmAveCharWidth
;
1601 void wxDC
::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1602 wxCoord
*descent
, wxCoord
*externalLeading
,
1605 #ifdef __WXMICROWIN__
1610 if (descent
) *descent
= 0;
1611 if (externalLeading
) *externalLeading
= 0;
1614 #endif // __WXMICROWIN__
1619 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1621 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1623 else // don't change the font
1631 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1632 GetTextMetrics(GetHdc(), &tm
);
1639 *descent
= tm
.tmDescent
;
1640 if (externalLeading
)
1641 *externalLeading
= tm
.tmExternalLeading
;
1645 ::SelectObject(GetHdc(), hfontOld
);
1650 // Each element of the array will be the width of the string up to and
1651 // including the coresoponding character in text.
1653 bool wxDC
::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1655 static int maxLenText
= -1;
1656 static int maxWidth
= -1;
1659 int stlen
= text
.Length();
1661 if (maxLenText
== -1)
1663 // Win9x and WinNT+ have different limits
1664 int version
= wxGetOsVersion();
1665 maxLenText
= version
== wxWINDOWS_NT ?
65535 : 8192;
1666 maxWidth
= version
== wxWINDOWS_NT ? INT_MAX
: 32767;
1670 widths
.Add(0, stlen
); // fill the array with zeros
1672 if (!::GetTextExtentExPoint(GetHdc(),
1673 text
.c_str(), // string to check
1674 wxMin(stlen
, maxLenText
),
1676 &fit
, // [out] count of chars
1678 &widths
[0], // array to fill
1682 wxLogLastError(wxT("GetTextExtentExPoint"));
1692 void wxDC
::SetMapMode(int mode
)
1694 WXMICROWIN_CHECK_HDC
1696 m_mappingMode
= mode
;
1698 if ( mode
== wxMM_TEXT
)
1701 m_logicalScaleY
= 1.0;
1703 else // need to do some calculations
1705 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1706 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1707 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1708 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1710 if ( (mm_width
== 0) || (mm_height
== 0) )
1712 // we can't calculate mm2pixels[XY] then!
1716 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1717 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1722 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1723 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1727 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1728 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1732 m_logicalScaleX
= mm2pixelsX
;
1733 m_logicalScaleY
= mm2pixelsY
;
1737 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1738 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1742 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1746 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1747 // cases we could do with MM_TEXT and in the remaining 0.9% with
1748 // MM_ISOTROPIC (TODO!)
1750 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1752 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1753 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1755 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1756 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1758 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1759 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1763 void wxDC
::SetUserScale(double x
, double y
)
1765 WXMICROWIN_CHECK_HDC
1768 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1774 SetMapMode(m_mappingMode
);
1778 void wxDC
::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1780 WXMICROWIN_CHECK_HDC
1783 int signX
= xLeftRight ?
1 : -1,
1784 signY
= yBottomUp ?
-1 : 1;
1786 if ( signX
!= m_signX
|| signY
!= m_signY
)
1791 SetMapMode(m_mappingMode
);
1796 void wxDC
::SetSystemScale(double x
, double y
)
1798 WXMICROWIN_CHECK_HDC
1800 if ( x
== m_scaleX
&& y
== m_scaleY
)
1807 SetMapMode(m_mappingMode
);
1811 void wxDC
::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1813 WXMICROWIN_CHECK_HDC
1815 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1818 m_logicalOriginX
= x
;
1819 m_logicalOriginY
= y
;
1822 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1826 void wxDC
::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1828 WXMICROWIN_CHECK_HDC
1830 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1833 m_deviceOriginX
= x
;
1834 m_deviceOriginY
= y
;
1837 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1841 // ---------------------------------------------------------------------------
1842 // coordinates transformations
1843 // ---------------------------------------------------------------------------
1845 wxCoord wxDCBase
::DeviceToLogicalX(wxCoord x
) const
1847 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1850 wxCoord wxDCBase
::DeviceToLogicalXRel(wxCoord x
) const
1852 // axis orientation is not taken into account for conversion of a distance
1853 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1856 wxCoord wxDCBase
::DeviceToLogicalY(wxCoord y
) const
1858 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1861 wxCoord wxDCBase
::DeviceToLogicalYRel(wxCoord y
) const
1863 // axis orientation is not taken into account for conversion of a distance
1864 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1867 wxCoord wxDCBase
::LogicalToDeviceX(wxCoord x
) const
1869 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1872 wxCoord wxDCBase
::LogicalToDeviceXRel(wxCoord x
) const
1874 // axis orientation is not taken into account for conversion of a distance
1875 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1878 wxCoord wxDCBase
::LogicalToDeviceY(wxCoord y
) const
1880 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1883 wxCoord wxDCBase
::LogicalToDeviceYRel(wxCoord y
) const
1885 // axis orientation is not taken into account for conversion of a distance
1886 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1889 // ---------------------------------------------------------------------------
1891 // ---------------------------------------------------------------------------
1893 bool wxDC
::DoBlit(wxCoord xdest
, wxCoord ydest
,
1894 wxCoord width
, wxCoord height
,
1895 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1896 int rop
, bool useMask
,
1897 wxCoord xsrcMask
, wxCoord ysrcMask
)
1899 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1901 WXMICROWIN_CHECK_HDC_RET(false)
1903 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1904 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1906 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1907 GetHdcOf(*source
), bmpSrc
) )
1911 wxMask
*mask
= NULL
;
1914 mask
= bmpSrc
.GetMask();
1916 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1918 // don't give assert here because this would break existing
1919 // programs - just silently ignore useMask parameter
1924 if (xsrcMask
== -1 && ysrcMask
== -1)
1926 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1929 COLORREF old_textground
= ::GetTextColor(GetHdc());
1930 COLORREF old_background
= ::GetBkColor(GetHdc());
1931 if (m_textForegroundColour
.Ok())
1933 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1935 if (m_textBackgroundColour
.Ok())
1937 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1943 case wxXOR
: dwRop
= SRCINVERT
; break;
1944 case wxINVERT
: dwRop
= DSTINVERT
; break;
1945 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1946 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1947 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1948 case wxSET
: dwRop
= WHITENESS
; break;
1949 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1950 case wxAND
: dwRop
= SRCAND
; break;
1951 case wxOR
: dwRop
= SRCPAINT
; break;
1952 case wxEQUIV
: dwRop
= 0x00990066; break;
1953 case wxNAND
: dwRop
= 0x007700E6; break;
1954 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1955 case wxCOPY
: dwRop
= SRCCOPY
; break;
1956 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1957 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1958 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1960 wxFAIL_MSG( wxT("unsupported logical function") );
1964 bool success
= false;
1969 // we want the part of the image corresponding to the mask to be
1970 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1971 // meaning of fg and bg is inverted which corresponds to wxWin notion
1972 // of the mask which is also contrary to the Windows one)
1974 // On some systems, MaskBlt succeeds yet is much much slower
1975 // than the wxWindows fall-back implementation. So we need
1976 // to be able to switch this on and off at runtime.
1977 #if wxUSE_SYSTEM_OPTIONS
1978 if (wxSystemOptions
::GetOptionInt(wxT("no-maskblt")) == 0)
1984 xdest
, ydest
, width
, height
,
1987 (HBITMAP
)mask
->GetMaskBitmap(),
1989 MAKEROP4(dwRop
, DSTCOPY
)
1996 // Blit bitmap with mask
1999 HBITMAP buffer_bmap
;
2001 #if wxUSE_DC_CACHEING
2002 // create a temp buffer bitmap and DCs to access it and the mask
2003 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2004 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2006 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2007 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2009 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2012 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2013 #else // !wxUSE_DC_CACHEING
2014 // create a temp buffer bitmap and DCs to access it and the mask
2015 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2016 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2017 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2018 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2019 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2020 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2022 // copy dest to buffer
2023 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2024 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2026 wxLogLastError(wxT("BitBlt"));
2029 // copy src to buffer using selected raster op
2030 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2031 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2033 wxLogLastError(wxT("BitBlt"));
2036 // set masked area in buffer to BLACK (pixel value 0)
2037 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2038 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2039 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2040 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2042 wxLogLastError(wxT("BitBlt"));
2045 // set unmasked area in dest to BLACK
2046 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2047 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2048 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2049 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2051 wxLogLastError(wxT("BitBlt"));
2053 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2054 ::SetTextColor(GetHdc(), prevCol
);
2056 // OR buffer to dest
2057 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2058 (int)width
, (int)height
,
2059 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2062 wxLogLastError(wxT("BitBlt"));
2065 // tidy up temporary DCs and bitmap
2066 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2067 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2069 #if !wxUSE_DC_CACHEING
2071 ::DeleteDC(dc_mask
);
2072 ::DeleteDC(dc_buffer
);
2073 ::DeleteObject(buffer_bmap
);
2078 else // no mask, just BitBlt() it
2080 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2081 // use StretchBlt() if available and finally fall back to BitBlt()
2083 // FIXME: use appropriate WinCE functions
2085 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2086 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2091 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2093 &ds
) == sizeof(ds
) )
2095 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2097 // Figure out what co-ordinate system we're supposed to specify
2099 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2103 ysrc
= hDIB
- (ysrc
+ height
);
2106 if ( ::StretchDIBits(GetHdc(),
2112 (LPBITMAPINFO
)&ds
.dsBmih
,
2115 ) == (int)GDI_ERROR
)
2117 // On Win9x this API fails most (all?) of the time, so
2118 // logging it becomes quite distracting. Since it falls
2119 // back to the code below this is not really serious, so
2121 //wxLogLastError(wxT("StretchDIBits"));
2130 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2135 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2141 xdest
, ydest
, width
, height
,
2143 xsrc
, ysrc
, width
, height
,
2147 wxLogLastError(_T("StretchBlt"));
2161 (int)width
, (int)height
,
2167 wxLogLastError(_T("BitBlt"));
2176 ::SetTextColor(GetHdc(), old_textground
);
2177 ::SetBkColor(GetHdc(), old_background
);
2182 void wxDC
::DoGetSize(int *w
, int *h
) const
2184 WXMICROWIN_CHECK_HDC
2186 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2187 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2190 void wxDC
::DoGetSizeMM(int *w
, int *h
) const
2192 WXMICROWIN_CHECK_HDC
2194 // if we implement it in terms of DoGetSize() instead of directly using the
2195 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2196 // will also work for wxWindowDC and wxClientDC even though their size is
2197 // not the same as the total size of the screen
2198 int wPixels
, hPixels
;
2199 DoGetSize(&wPixels
, &hPixels
);
2203 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2205 wxCHECK_RET( wTotal
, _T("0 width device?") );
2207 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2212 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2214 wxCHECK_RET( hTotal
, _T("0 height device?") );
2216 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2220 wxSize wxDC
::GetPPI() const
2222 WXMICROWIN_CHECK_HDC_RET(wxSize())
2224 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2225 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2227 return wxSize(x
, y
);
2230 // For use by wxWindows only, unless custom units are required.
2231 void wxDC
::SetLogicalScale(double x
, double y
)
2233 WXMICROWIN_CHECK_HDC
2235 m_logicalScaleX
= x
;
2236 m_logicalScaleY
= y
;
2239 // ----------------------------------------------------------------------------
2241 // ----------------------------------------------------------------------------
2243 #if wxUSE_DC_CACHEING
2246 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2247 * improve it in due course, either using arrays, or simply storing pointers to one
2248 * entry for the bitmap, and two for the DCs. -- JACS
2251 wxList wxDC
::sm_bitmapCache
;
2252 wxList wxDC
::sm_dcCache
;
2254 wxDCCacheEntry
::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2263 wxDCCacheEntry
::wxDCCacheEntry(WXHDC hDC
, int depth
)
2272 wxDCCacheEntry
::~wxDCCacheEntry()
2275 ::DeleteObject((HBITMAP
) m_bitmap
);
2277 ::DeleteDC((HDC
) m_dc
);
2280 wxDCCacheEntry
* wxDC
::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2282 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2283 wxList
::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2286 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2288 if (entry
->m_depth
== depth
)
2290 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2292 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2293 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2294 if ( !entry
->m_bitmap
)
2296 wxLogLastError(wxT("CreateCompatibleBitmap"));
2298 entry
->m_width
= w
; entry
->m_height
= h
;
2304 node
= node
->GetNext();
2306 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2309 wxLogLastError(wxT("CreateCompatibleBitmap"));
2311 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2312 AddToBitmapCache(entry
);
2316 wxDCCacheEntry
* wxDC
::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2318 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2319 wxList
::compatibility_iterator node
= sm_dcCache
.GetFirst();
2322 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2324 // Don't return the same one as we already have
2325 if (!notThis
|| (notThis
!= entry
))
2327 if (entry
->m_depth
== depth
)
2333 node
= node
->GetNext();
2335 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2338 wxLogLastError(wxT("CreateCompatibleDC"));
2340 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2341 AddToDCCache(entry
);
2345 void wxDC
::AddToBitmapCache(wxDCCacheEntry
* entry
)
2347 sm_bitmapCache
.Append(entry
);
2350 void wxDC
::AddToDCCache(wxDCCacheEntry
* entry
)
2352 sm_dcCache
.Append(entry
);
2355 void wxDC
::ClearCache()
2357 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2358 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2361 // Clean up cache at app exit
2362 class wxDCModule
: public wxModule
2365 virtual bool OnInit() { return true; }
2366 virtual void OnExit() { wxDC
::ClearCache(); }
2369 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2372 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2374 #endif // wxUSE_DC_CACHEING
2376 // ----------------------------------------------------------------------------
2377 // alpha channel support
2378 // ----------------------------------------------------------------------------
2380 static bool AlphaBlt(HDC hdcDst
,
2381 int x
, int y
, int width
, int height
,
2383 const wxBitmap
& bmp
)
2385 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2386 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2388 // do we have AlphaBlend() and company in the headers?
2389 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2390 // yes, now try to see if we have it during run-time
2391 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2392 HDC
,int,int,int,int,
2395 // bitmaps can be drawn only from GUI thread so there is no need to
2396 // protect this static variable from multiple threads
2397 static bool s_triedToLoad
= false;
2398 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2399 if ( !s_triedToLoad
)
2401 s_triedToLoad
= true;
2403 // don't give errors about the DLL being unavailable, we're
2404 // prepared to handle this
2407 wxDynamicLibrary
dll(_T("msimg32.dll"));
2408 if ( dll
.IsLoaded() )
2410 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2411 if ( pfnAlphaBlend
)
2413 // we must keep the DLL loaded if we want to be able to
2414 // call AlphaBlend() so just never unload it at all, not a
2421 if ( pfnAlphaBlend
)
2424 bf
.BlendOp
= AC_SRC_OVER
;
2426 bf
.SourceConstantAlpha
= 0xff;
2427 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2429 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2430 hdcSrc
, 0, 0, width
, height
,
2433 // skip wxAlphaBlend() call below
2437 wxLogLastError(_T("AlphaBlend"));
2439 #endif // defined(AC_SRC_OVER)
2441 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2443 #ifdef wxHAVE_RAW_BITMAP
2444 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2447 #else // !wxHAVE_RAW_BITMAP
2448 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2449 // alpha but at least something will be shown like this)
2451 #endif // wxHAVE_RAW_BITMAP
2455 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2456 #ifdef wxHAVE_RAW_BITMAP
2459 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2461 // get the destination DC pixels
2462 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2464 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2466 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2468 wxLogLastError(_T("BitBlt"));
2471 // combine them with the source bitmap using alpha
2472 wxAlphaPixelData
dataDst(bmpDst
),
2473 dataSrc((wxBitmap
&)bmpSrc
);
2475 wxCHECK_RET( dataDst
&& dataSrc
,
2476 _T("failed to get raw data in wxAlphaBlend") );
2478 wxAlphaPixelData
::Iterator
pDst(dataDst
),
2481 for ( int y
= 0; y
< h
; y
++ )
2483 wxAlphaPixelData
::Iterator pDstRowStart
= pDst
,
2484 pSrcRowStart
= pSrc
;
2486 for ( int x
= 0; x
< w
; x
++ )
2488 // note that source bitmap uses premultiplied alpha (as required by
2489 // the real AlphaBlend)
2490 const unsigned beta
= 255 - pSrc
.Alpha();
2492 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2493 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2494 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2500 pDst
= pDstRowStart
;
2501 pSrc
= pSrcRowStart
;
2502 pDst
.OffsetY(dataDst
, 1);
2503 pSrc
.OffsetY(dataSrc
, 1);
2506 // and finally blit them back to the destination DC
2507 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2509 wxLogLastError(_T("BitBlt"));
2513 #endif // #ifdef wxHAVE_RAW_BITMAP