1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
45 #include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
47 #include "wx/sysopt.h"
48 #include "wx/dcprint.h"
49 #include "wx/module.h"
50 #include "wx/dynload.h"
52 #ifdef wxHAVE_RAW_BITMAP
53 #include "wx/rawbmp.h"
59 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
68 #define AC_SRC_ALPHA 1
71 /* Quaternary raster codes */
73 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
76 // apparently with MicroWindows it is possible that HDC is 0 so we have to
77 // check for this ourselves
79 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
80 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
82 #define WXMICROWIN_CHECK_HDC
83 #define WXMICROWIN_CHECK_HDC_RET(x)
86 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
88 // ---------------------------------------------------------------------------
90 // ---------------------------------------------------------------------------
92 static const int VIEWPORT_EXTENT
= 1000;
94 static const int MM_POINTS
= 9;
95 static const int MM_METRIC
= 10;
97 // usually this is defined in math.h
99 static const double M_PI
= 3.14159265358979323846;
102 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
103 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
104 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
106 // ----------------------------------------------------------------------------
107 // macros for logical <-> device coords conversion
108 // ----------------------------------------------------------------------------
111 We currently let Windows do all the translations itself so these macros are
112 not really needed (any more) but keep them to enhance readability of the
113 code by allowing to see where are the logical and where are the device
118 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX+m_deviceOriginX)
119 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY+m_deviceOriginY)
120 #define XDEV2LOG(x) ((x-m_deviceOriginX)*m_signX+m_logicalOriginX)
121 #define YDEV2LOG(y) ((y-m_deviceOriginY)*m_signY+m_logicalOriginY)
123 #define XLOG2DEV(x) (x)
124 #define YLOG2DEV(y) (y)
125 #define XDEV2LOG(x) (x)
126 #define YDEV2LOG(y) (y)
129 // ---------------------------------------------------------------------------
131 // ---------------------------------------------------------------------------
133 // convert degrees to radians
134 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
136 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
138 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
139 // to pass it to this function but as we already have it at the point
140 // of call anyhow we do
142 // return true if we could draw the bitmap in one way or the other, false
144 static bool AlphaBlt(HDC hdcDst
,
145 int x
, int y
, int w
, int h
,
147 const wxBitmap
& bmpSrc
);
149 #ifdef wxHAVE_RAW_BITMAP
150 // our (limited) AlphaBlend() replacement
152 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
155 // ----------------------------------------------------------------------------
157 // ----------------------------------------------------------------------------
159 // instead of duplicating the same code which sets and then restores text
160 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
161 // encapsulate this in a small helper class
163 // wxColourChanger: changes the text colours in the ctor if required and
164 // restores them in the dtor
165 class wxColourChanger
168 wxColourChanger(wxDC
& dc
);
174 COLORREF m_colFgOld
, m_colBgOld
;
178 DECLARE_NO_COPY_CLASS(wxColourChanger
)
181 // this class saves the old stretch blit mode during its life time
182 class StretchBltModeChanger
185 StretchBltModeChanger(HDC hdc
, int mode
)
189 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
191 wxLogLastError(_T("SetStretchBltMode"));
195 ~StretchBltModeChanger()
198 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
199 wxLogLastError(_T("SetStretchBltMode"));
208 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
211 // ===========================================================================
213 // ===========================================================================
215 // ----------------------------------------------------------------------------
217 // ----------------------------------------------------------------------------
219 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
221 const wxBrush
& brush
= dc
.GetBrush();
222 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
224 HDC hdc
= GetHdcOf(dc
);
225 m_colFgOld
= ::GetTextColor(hdc
);
226 m_colBgOld
= ::GetBkColor(hdc
);
228 // note that Windows convention is opposite to wxWidgets one, this is
229 // why text colour becomes the background one and vice versa
230 const wxColour
& colFg
= dc
.GetTextForeground();
233 ::SetBkColor(hdc
, colFg
.GetPixel());
236 const wxColour
& colBg
= dc
.GetTextBackground();
239 ::SetTextColor(hdc
, colBg
.GetPixel());
243 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
246 // flag which telsl us to undo changes in the dtor
251 // nothing done, nothing to undo
256 wxColourChanger::~wxColourChanger()
260 // restore the colours we changed
261 HDC hdc
= GetHdcOf(m_dc
);
263 ::SetBkMode(hdc
, TRANSPARENT
);
264 ::SetTextColor(hdc
, m_colFgOld
);
265 ::SetBkColor(hdc
, m_colBgOld
);
269 // ---------------------------------------------------------------------------
271 // ---------------------------------------------------------------------------
273 // Default constructor
284 #endif // wxUSE_PALETTE
294 SelectOldObjects(m_hDC
);
296 // if we own the HDC, we delete it, otherwise we just release it
300 ::DeleteDC(GetHdc());
302 else // we don't own our HDC
306 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
310 // Must have been a wxScreenDC
311 ::ReleaseDC((HWND
) NULL
, GetHdc());
317 // This will select current objects out of the DC,
318 // which is what you have to do before deleting the
320 void wxDC::SelectOldObjects(WXHDC dc
)
326 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
328 if (m_selectedBitmap
.Ok())
330 m_selectedBitmap
.SetSelectedInto(NULL
);
337 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
342 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
347 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
354 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
357 #endif // wxUSE_PALETTE
360 m_brush
= wxNullBrush
;
363 m_palette
= wxNullPalette
;
364 #endif // wxUSE_PALETTE
366 m_backgroundBrush
= wxNullBrush
;
367 m_selectedBitmap
= wxNullBitmap
;
370 // ---------------------------------------------------------------------------
372 // ---------------------------------------------------------------------------
374 void wxDC::UpdateClipBox()
379 ::GetClipBox(GetHdc(), &rect
);
381 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
382 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
383 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
384 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
388 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
390 // check if we should try to retrieve the clipping region possibly not set
391 // by our SetClippingRegion() but preset by Windows:this can only happen
392 // when we're associated with an existing HDC usign SetHDC(), see there
393 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
395 wxDC
*self
= wxConstCast(this, wxDC
);
396 self
->UpdateClipBox();
398 if ( !m_clipX1
&& !m_clipX2
)
399 self
->m_clipping
= false;
402 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
405 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
406 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
408 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
412 // note that we combine the new clipping region with the existing one: this
413 // is compatible with what the other ports do and is the documented
414 // behaviour now (starting with 2.3.3)
415 #if defined(__WXWINCE__)
417 if ( !::GetClipBox(GetHdc(), &rectClip
) )
420 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
421 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
422 rectClip
.right
, rectClip
.bottom
);
424 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
426 ::SelectClipRgn(GetHdc(), hrgnDest
);
429 ::DeleteObject(hrgnClipOld
);
430 ::DeleteObject(hrgnDest
);
432 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
434 wxLogLastError(_T("ExtSelectClipRgn"));
438 #endif // WinCE/!WinCE
445 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
447 // the region coords are always the device ones, so do the translation
450 // FIXME: possible +/-1 error here, to check!
451 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
453 LogicalToDeviceX(x
+ w
),
454 LogicalToDeviceY(y
+ h
));
457 wxLogLastError(_T("CreateRectRgn"));
461 SetClippingHrgn((WXHRGN
)hrgn
);
463 ::DeleteObject(hrgn
);
467 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
469 SetClippingHrgn(region
.GetHRGN());
472 void wxDC::DestroyClippingRegion()
476 if (m_clipping
&& m_hDC
)
478 // TODO: this should restore the previous clipping region,
479 // so that OnPaint processing works correctly, and the update
480 // clipping region doesn't get destroyed after the first
481 // DestroyClippingRegion.
482 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
483 ::SelectClipRgn(GetHdc(), rgn
);
487 wxDCBase::DestroyClippingRegion();
490 // ---------------------------------------------------------------------------
491 // query capabilities
492 // ---------------------------------------------------------------------------
494 bool wxDC::CanDrawBitmap() const
499 bool wxDC::CanGetTextExtent() const
501 #ifdef __WXMICROWIN__
502 // TODO Extend MicroWindows' GetDeviceCaps function
505 // What sort of display is it?
506 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
508 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
512 int wxDC::GetDepth() const
514 WXMICROWIN_CHECK_HDC_RET(16)
516 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
519 // ---------------------------------------------------------------------------
521 // ---------------------------------------------------------------------------
530 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
534 // No, I think we should simply ignore this if printing on e.g.
536 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
537 if (!m_selectedBitmap
.Ok())
540 rect
.left
= 0; rect
.top
= 0;
541 rect
.right
= m_selectedBitmap
.GetWidth();
542 rect
.bottom
= m_selectedBitmap
.GetHeight();
546 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
549 DWORD colour
= ::GetBkColor(GetHdc());
550 HBRUSH brush
= ::CreateSolidBrush(colour
);
551 ::FillRect(GetHdc(), &rect
, brush
);
552 ::DeleteObject(brush
);
554 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
555 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
558 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
560 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
561 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
562 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
563 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
567 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 (void)Polygon(GetHdc(), cpoints
, n
);
784 SetPolyFillMode(GetHdc(),prev
);
791 for (i
= 0; i
< n
; i
++)
792 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
795 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
797 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
799 SetPolyFillMode(GetHdc(),prev
);
805 wxDC::DoDrawPolyPolygon(int n
,
813 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
817 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
819 for (i
= cnt
= 0; i
< n
; i
++)
822 // Do things less efficiently if we have offsets
823 if (xoffset
!= 0 || yoffset
!= 0)
825 POINT
*cpoints
= new POINT
[cnt
];
826 for (i
= 0; i
< cnt
; i
++)
828 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
829 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
831 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
834 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
836 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
838 SetPolyFillMode(GetHdc(),prev
);
844 for (i
= 0; i
< cnt
; i
++)
845 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
848 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
850 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
852 SetPolyFillMode(GetHdc(),prev
);
859 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
863 // Do things less efficiently if we have offsets
864 if (xoffset
!= 0 || yoffset
!= 0)
866 POINT
*cpoints
= new POINT
[n
];
868 for (i
= 0; i
< n
; i
++)
870 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
871 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
873 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
875 (void)Polyline(GetHdc(), cpoints
, n
);
881 for (i
= 0; i
< n
; i
++)
882 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
884 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
888 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
892 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
894 wxCoord x2
= x
+ width
;
895 wxCoord y2
= y
+ height
;
897 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
900 rect
.left
= XLOG2DEV(x
);
901 rect
.top
= YLOG2DEV(y
);
902 rect
.right
= XLOG2DEV(x2
);
903 rect
.bottom
= YLOG2DEV(y2
);
904 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
908 // Windows draws the filled rectangles without outline (i.e. drawn with a
909 // transparent pen) one pixel smaller in both directions and we want them
910 // to have the same size regardless of which pen is used - adjust
912 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
913 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
919 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
923 CalcBoundingBox(x
, y
);
924 CalcBoundingBox(x2
, y2
);
927 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
931 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
933 // Now, a negative radius value is interpreted to mean
934 // 'the proportion of the smallest X or Y dimension'
938 double smallest
= (width
< height
) ? width
: height
;
939 radius
= (- radius
* smallest
);
942 wxCoord x2
= (x
+width
);
943 wxCoord y2
= (y
+height
);
945 // Windows draws the filled rectangles without outline (i.e. drawn with a
946 // transparent pen) one pixel smaller in both directions and we want them
947 // to have the same size regardless of which pen is used - adjust
948 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
954 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
955 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
957 CalcBoundingBox(x
, y
);
958 CalcBoundingBox(x2
, y2
);
961 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
965 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
967 wxCoord x2
= (x
+width
);
968 wxCoord y2
= (y
+height
);
970 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
972 CalcBoundingBox(x
, y
);
973 CalcBoundingBox(x2
, y2
);
976 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
977 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
980 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
985 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
990 int rx1
= XLOG2DEV(x
+w
/2);
991 int ry1
= YLOG2DEV(y
+h
/2);
998 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
999 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1000 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1001 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1003 // draw pie with NULL_PEN first and then outline otherwise a line is
1004 // drawn from the start and end points to the centre
1005 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1008 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1009 rx1
, ry1
, rx2
, ry2
);
1013 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1014 rx1
, ry1
-1, rx2
, ry2
-1);
1017 ::SelectObject(GetHdc(), hpenOld
);
1019 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1020 rx1
, ry1
, rx2
, ry2
);
1022 CalcBoundingBox(x
, y
);
1023 CalcBoundingBox(x2
, y2
);
1027 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1029 WXMICROWIN_CHECK_HDC
1031 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1034 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1036 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1039 CalcBoundingBox(x
, y
);
1040 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1043 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1045 WXMICROWIN_CHECK_HDC
1047 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1049 int width
= bmp
.GetWidth(),
1050 height
= bmp
.GetHeight();
1052 HBITMAP hbmpMask
= 0;
1055 HPALETTE oldPal
= 0;
1056 #endif // wxUSE_PALETTE
1058 if ( bmp
.HasAlpha() )
1061 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1063 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1069 wxMask
*mask
= bmp
.GetMask();
1071 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1075 // don't give assert here because this would break existing
1076 // programs - just silently ignore useMask parameter
1083 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1085 // On some systems, MaskBlt succeeds yet is much much slower
1086 // than the wxWidgets fall-back implementation. So we need
1087 // to be able to switch this on and off at runtime.
1089 #if wxUSE_SYSTEM_OPTIONS
1090 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1094 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1095 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1097 wxPalette
*pal
= bmp
.GetPalette();
1098 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1100 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1101 ::RealizePalette(hdcMem
);
1103 #endif // wxUSE_PALETTE
1105 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1108 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1112 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1113 #endif // wxUSE_PALETTE
1115 ::SelectObject(hdcMem
, hOldBitmap
);
1122 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1125 memDC
.SelectObject(bmp
);
1127 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1129 memDC
.SelectObject(wxNullBitmap
);
1132 else // no mask, just use BitBlt()
1135 HDC memdc
= ::CreateCompatibleDC( cdc
);
1136 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1138 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1140 COLORREF old_textground
= ::GetTextColor(GetHdc());
1141 COLORREF old_background
= ::GetBkColor(GetHdc());
1142 if (m_textForegroundColour
.Ok())
1144 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1146 if (m_textBackgroundColour
.Ok())
1148 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1152 wxPalette
*pal
= bmp
.GetPalette();
1153 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1155 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1156 ::RealizePalette(memdc
);
1158 #endif // wxUSE_PALETTE
1160 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1161 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1165 ::SelectPalette(memdc
, oldPal
, FALSE
);
1166 #endif // wxUSE_PALETTE
1168 ::SelectObject( memdc
, hOldBitmap
);
1169 ::DeleteDC( memdc
);
1171 ::SetTextColor(GetHdc(), old_textground
);
1172 ::SetBkColor(GetHdc(), old_background
);
1176 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1178 WXMICROWIN_CHECK_HDC
1180 DrawAnyText(text
, x
, y
);
1182 // update the bounding box
1183 CalcBoundingBox(x
, y
);
1186 GetTextExtent(text
, &w
, &h
);
1187 CalcBoundingBox(x
+ w
, y
+ h
);
1190 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1192 WXMICROWIN_CHECK_HDC
1194 // prepare for drawing the text
1195 if ( m_textForegroundColour
.Ok() )
1196 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1198 DWORD old_background
= 0;
1199 if ( m_textBackgroundColour
.Ok() )
1201 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1204 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1208 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1209 text
.c_str(), text
.length(), NULL
) == 0 )
1211 wxLogLastError(wxT("TextOut"));
1214 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1215 text
.c_str(), text
.length()) == 0 )
1217 wxLogLastError(wxT("TextOut"));
1221 // restore the old parameters (text foreground colour may be left because
1222 // it never is set to anything else, but background should remain
1223 // transparent even if we just drew an opaque string)
1224 if ( m_textBackgroundColour
.Ok() )
1225 (void)SetBkColor(GetHdc(), old_background
);
1227 SetBkMode(GetHdc(), TRANSPARENT
);
1230 void wxDC::DoDrawRotatedText(const wxString
& text
,
1231 wxCoord x
, wxCoord y
,
1234 WXMICROWIN_CHECK_HDC
1236 // we test that we have some font because otherwise we should still use the
1237 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1238 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1239 // font for drawing rotated fonts unfortunately)
1240 if ( (angle
== 0.0) && m_font
.Ok() )
1242 DoDrawText(text
, x
, y
);
1244 #ifndef __WXMICROWIN__
1247 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1248 // because it's not TrueType and so can't have non zero
1249 // orientation/escapement under Win9x
1250 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1251 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1253 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1255 wxLogLastError(wxT("GetObject(hfont)"));
1258 // GDI wants the angle in tenth of degree
1259 long angle10
= (long)(angle
* 10);
1260 lf
.lfEscapement
= angle10
;
1261 lf
. lfOrientation
= angle10
;
1263 hfont
= ::CreateFontIndirect(&lf
);
1266 wxLogLastError(wxT("CreateFont"));
1270 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1272 DrawAnyText(text
, x
, y
);
1274 (void)::SelectObject(GetHdc(), hfontOld
);
1275 (void)::DeleteObject(hfont
);
1278 // call the bounding box by adding all four vertices of the rectangle
1279 // containing the text to it (simpler and probably not slower than
1280 // determining which of them is really topmost/leftmost/...)
1282 GetTextExtent(text
, &w
, &h
);
1284 double rad
= DegToRad(angle
);
1286 // "upper left" and "upper right"
1287 CalcBoundingBox(x
, y
);
1288 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1290 // "bottom left" and "bottom right"
1291 x
+= (wxCoord
)(h
*sin(rad
));
1292 y
+= (wxCoord
)(h
*cos(rad
));
1293 CalcBoundingBox(x
, y
);
1294 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1299 // ---------------------------------------------------------------------------
1301 // ---------------------------------------------------------------------------
1305 void wxDC::DoSelectPalette(bool realize
)
1307 WXMICROWIN_CHECK_HDC
1309 // Set the old object temporarily, in case the assignment deletes an object
1310 // that's not yet selected out.
1313 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1317 if ( m_palette
.Ok() )
1319 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1320 GetHpaletteOf(m_palette
),
1323 m_oldPalette
= (WXHPALETTE
) oldPal
;
1326 ::RealizePalette(GetHdc());
1330 void wxDC::SetPalette(const wxPalette
& palette
)
1334 m_palette
= palette
;
1335 DoSelectPalette(true);
1339 void wxDC::InitializePalette()
1341 if ( wxDisplayDepth() <= 8 )
1343 // look for any window or parent that has a custom palette. If any has
1344 // one then we need to use it in drawing operations
1345 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1347 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1348 if ( m_hasCustomPalette
)
1350 m_palette
= win
->GetPalette();
1352 // turn on MSW translation for this palette
1358 #endif // wxUSE_PALETTE
1360 // SetFont/Pen/Brush() really ask to be implemented as a single template
1361 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1363 void wxDC::SetFont(const wxFont
& font
)
1365 WXMICROWIN_CHECK_HDC
1367 if ( font
== m_font
)
1372 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1373 if ( hfont
== HGDI_ERROR
)
1375 wxLogLastError(_T("SelectObject(font)"));
1380 m_oldFont
= (WXHPEN
)hfont
;
1385 else // invalid font, reset the current font
1389 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1391 wxLogLastError(_T("SelectObject(old font)"));
1397 m_font
= wxNullFont
;
1401 void wxDC::SetPen(const wxPen
& pen
)
1403 WXMICROWIN_CHECK_HDC
1410 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1411 if ( hpen
== HGDI_ERROR
)
1413 wxLogLastError(_T("SelectObject(pen)"));
1418 m_oldPen
= (WXHPEN
)hpen
;
1423 else // invalid pen, reset the current pen
1427 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1429 wxLogLastError(_T("SelectObject(old pen)"));
1439 void wxDC::SetBrush(const wxBrush
& brush
)
1441 WXMICROWIN_CHECK_HDC
1443 if ( brush
== m_brush
)
1448 // we must make sure the brush is aligned with the logical coordinates
1449 // before selecting it
1450 wxBitmap
*stipple
= brush
.GetStipple();
1451 if ( stipple
&& stipple
->Ok() )
1453 if ( !::SetBrushOrgEx
1456 m_deviceOriginX
% stipple
->GetWidth(),
1457 m_deviceOriginY
% stipple
->GetHeight(),
1458 NULL
// [out] previous brush origin
1461 wxLogLastError(_T("SetBrushOrgEx()"));
1465 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1466 if ( hbrush
== HGDI_ERROR
)
1468 wxLogLastError(_T("SelectObject(brush)"));
1473 m_oldBrush
= (WXHPEN
)hbrush
;
1478 else // invalid brush, reset the current brush
1482 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1484 wxLogLastError(_T("SelectObject(old brush)"));
1490 m_brush
= wxNullBrush
;
1494 void wxDC::SetBackground(const wxBrush
& brush
)
1496 WXMICROWIN_CHECK_HDC
1498 m_backgroundBrush
= brush
;
1500 if ( m_backgroundBrush
.Ok() )
1502 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1506 void wxDC::SetBackgroundMode(int mode
)
1508 WXMICROWIN_CHECK_HDC
1510 m_backgroundMode
= mode
;
1512 // SetBackgroundColour now only refers to text background
1513 // and m_backgroundMode is used there
1516 void wxDC::SetLogicalFunction(int function
)
1518 WXMICROWIN_CHECK_HDC
1520 m_logicalFunction
= function
;
1525 void wxDC::SetRop(WXHDC dc
)
1527 if ( !dc
|| m_logicalFunction
< 0 )
1532 switch (m_logicalFunction
)
1534 case wxCLEAR
: rop
= R2_BLACK
; break;
1535 case wxXOR
: rop
= R2_XORPEN
; break;
1536 case wxINVERT
: rop
= R2_NOT
; break;
1537 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1538 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1539 case wxCOPY
: rop
= R2_COPYPEN
; break;
1540 case wxAND
: rop
= R2_MASKPEN
; break;
1541 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1542 case wxNO_OP
: rop
= R2_NOP
; break;
1543 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1544 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1545 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1546 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1547 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1548 case wxOR
: rop
= R2_MERGEPEN
; break;
1549 case wxSET
: rop
= R2_WHITE
; break;
1552 wxFAIL_MSG( wxT("unsupported logical function") );
1556 SetROP2(GetHdc(), rop
);
1559 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1561 // We might be previewing, so return true to let it continue.
1569 void wxDC::StartPage()
1573 void wxDC::EndPage()
1577 // ---------------------------------------------------------------------------
1579 // ---------------------------------------------------------------------------
1581 wxCoord
wxDC::GetCharHeight() const
1583 WXMICROWIN_CHECK_HDC_RET(0)
1585 TEXTMETRIC lpTextMetric
;
1587 GetTextMetrics(GetHdc(), &lpTextMetric
);
1589 return lpTextMetric
.tmHeight
;
1592 wxCoord
wxDC::GetCharWidth() const
1594 WXMICROWIN_CHECK_HDC_RET(0)
1596 TEXTMETRIC lpTextMetric
;
1598 GetTextMetrics(GetHdc(), &lpTextMetric
);
1600 return lpTextMetric
.tmAveCharWidth
;
1603 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1604 wxCoord
*descent
, wxCoord
*externalLeading
,
1607 #ifdef __WXMICROWIN__
1612 if (descent
) *descent
= 0;
1613 if (externalLeading
) *externalLeading
= 0;
1616 #endif // __WXMICROWIN__
1621 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1623 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1625 else // don't change the font
1633 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1634 GetTextMetrics(GetHdc(), &tm
);
1641 *descent
= tm
.tmDescent
;
1642 if (externalLeading
)
1643 *externalLeading
= tm
.tmExternalLeading
;
1647 ::SelectObject(GetHdc(), hfontOld
);
1652 // Each element of the array will be the width of the string up to and
1653 // including the coresoponding character in text.
1655 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1657 static int maxLenText
= -1;
1658 static int maxWidth
= -1;
1661 int stlen
= text
.Length();
1663 if (maxLenText
== -1)
1665 // Win9x and WinNT+ have different limits
1666 int version
= wxGetOsVersion();
1667 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1668 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1672 widths
.Add(0, stlen
); // fill the array with zeros
1674 if (!::GetTextExtentExPoint(GetHdc(),
1675 text
.c_str(), // string to check
1676 wxMin(stlen
, maxLenText
),
1678 &fit
, // [out] count of chars
1680 &widths
[0], // array to fill
1684 wxLogLastError(wxT("GetTextExtentExPoint"));
1694 void wxDC::SetMapMode(int mode
)
1696 WXMICROWIN_CHECK_HDC
1698 m_mappingMode
= mode
;
1700 if ( mode
== wxMM_TEXT
)
1703 m_logicalScaleY
= 1.0;
1705 else // need to do some calculations
1707 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1708 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1709 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1710 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1712 if ( (mm_width
== 0) || (mm_height
== 0) )
1714 // we can't calculate mm2pixels[XY] then!
1718 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1719 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1724 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1725 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1729 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1730 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1734 m_logicalScaleX
= mm2pixelsX
;
1735 m_logicalScaleY
= mm2pixelsY
;
1739 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1740 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1744 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1748 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1749 // cases we could do with MM_TEXT and in the remaining 0.9% with
1750 // MM_ISOTROPIC (TODO!)
1752 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1754 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1755 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1757 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1758 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1760 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1761 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1765 void wxDC::SetUserScale(double x
, double y
)
1767 WXMICROWIN_CHECK_HDC
1769 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1775 this->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 wxWidgets 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 wxWidgets 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