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>
45 #include "wx/sysopt.h"
46 #include "wx/dcprint.h"
47 #include "wx/module.h"
48 #include "wx/dynload.h"
50 #ifdef wxHAVE_RAW_BITMAP
51 #include "wx/rawbmp.h"
57 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
66 #define AC_SRC_ALPHA 1
69 /* Quaternary raster codes */
71 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
74 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
76 // ---------------------------------------------------------------------------
78 // ---------------------------------------------------------------------------
80 static const int VIEWPORT_EXTENT
= 1000;
82 static const int MM_POINTS
= 9;
83 static const int MM_METRIC
= 10;
85 // usually this is defined in math.h
87 static const double M_PI
= 3.14159265358979323846;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) (x)
107 #define YLOG2DEV(y) (y)
110 #define XDEV2LOG(x) (x)
111 #define YDEV2LOG(y) (y)
113 // ---------------------------------------------------------------------------
115 // ---------------------------------------------------------------------------
117 // convert degrees to radians
118 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
120 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
122 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
123 // to pass it to this function but as we already have it at the point
124 // of call anyhow we do
126 // return true if we could draw the bitmap in one way or the other, false
128 static bool AlphaBlt(HDC hdcDst
,
129 int x
, int y
, int w
, int h
,
131 const wxBitmap
& bmpSrc
);
133 #ifdef wxHAVE_RAW_BITMAP
134 // our (limited) AlphaBlend() replacement
136 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 // instead of duplicating the same code which sets and then restores text
144 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
145 // encapsulate this in a small helper class
147 // wxColourChanger: changes the text colours in the ctor if required and
148 // restores them in the dtor
149 class wxColourChanger
152 wxColourChanger(wxDC
& dc
);
158 COLORREF m_colFgOld
, m_colBgOld
;
162 DECLARE_NO_COPY_CLASS(wxColourChanger
)
165 // this class saves the old stretch blit mode during its life time
166 class StretchBltModeChanger
169 StretchBltModeChanger(HDC hdc
, int mode
)
173 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
175 wxLogLastError(_T("SetStretchBltMode"));
179 ~StretchBltModeChanger()
182 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
183 wxLogLastError(_T("SetStretchBltMode"));
192 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
195 // ===========================================================================
197 // ===========================================================================
199 // ----------------------------------------------------------------------------
201 // ----------------------------------------------------------------------------
203 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
205 const wxBrush
& brush
= dc
.GetBrush();
206 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
208 HDC hdc
= GetHdcOf(dc
);
209 m_colFgOld
= ::GetTextColor(hdc
);
210 m_colBgOld
= ::GetBkColor(hdc
);
212 // note that Windows convention is opposite to wxWindows one, this is
213 // why text colour becomes the background one and vice versa
214 const wxColour
& colFg
= dc
.GetTextForeground();
217 ::SetBkColor(hdc
, colFg
.GetPixel());
220 const wxColour
& colBg
= dc
.GetTextBackground();
223 ::SetTextColor(hdc
, colBg
.GetPixel());
227 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
230 // flag which telsl us to undo changes in the dtor
235 // nothing done, nothing to undo
240 wxColourChanger::~wxColourChanger()
244 // restore the colours we changed
245 HDC hdc
= GetHdcOf(m_dc
);
247 ::SetBkMode(hdc
, TRANSPARENT
);
248 ::SetTextColor(hdc
, m_colFgOld
);
249 ::SetBkColor(hdc
, m_colBgOld
);
253 // ---------------------------------------------------------------------------
255 // ---------------------------------------------------------------------------
257 // Default constructor
268 #endif // wxUSE_PALETTE
278 SelectOldObjects(m_hDC
);
280 // if we own the HDC, we delete it, otherwise we just release it
284 ::DeleteDC(GetHdc());
286 else // we don't own our HDC
290 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
294 // Must have been a wxScreenDC
295 ::ReleaseDC((HWND
) NULL
, GetHdc());
301 // This will select current objects out of the DC,
302 // which is what you have to do before deleting the
304 void wxDC::SelectOldObjects(WXHDC dc
)
310 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
312 if (m_selectedBitmap
.Ok())
314 m_selectedBitmap
.SetSelectedInto(NULL
);
321 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
326 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
331 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
338 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
341 #endif // wxUSE_PALETTE
344 m_brush
= wxNullBrush
;
347 m_palette
= wxNullPalette
;
348 #endif // wxUSE_PALETTE
350 m_backgroundBrush
= wxNullBrush
;
351 m_selectedBitmap
= wxNullBitmap
;
354 // ---------------------------------------------------------------------------
356 // ---------------------------------------------------------------------------
358 void wxDC::UpdateClipBox()
360 #ifdef __WXMICROWIN__
361 if (!GetHDC()) return;
365 ::GetClipBox(GetHdc(), &rect
);
367 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
368 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
369 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
370 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
373 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
374 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
376 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
378 #ifdef __WXMICROWIN__
379 if (!GetHdc()) return;
380 #endif // __WXMICROWIN__
382 // note that we combine the new clipping region with the existing one: this
383 // is compatible with what the other ports do and is the documented
384 // behaviour now (starting with 2.3.3)
385 #if defined(__WIN16__) || defined(__WXWINCE__)
387 if ( !::GetClipBox(GetHdc(), &rectClip
) )
390 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
391 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
392 rectClip
.right
, rectClip
.bottom
);
394 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
396 ::SelectClipRgn(GetHdc(), hrgnDest
);
399 ::DeleteObject(hrgnClipOld
);
400 ::DeleteObject(hrgnDest
);
402 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
404 wxLogLastError(_T("ExtSelectClipRgn"));
415 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
417 // the region coords are always the device ones, so do the translation
420 // FIXME: possible +/-1 error here, to check!
421 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
423 LogicalToDeviceX(x
+ w
),
424 LogicalToDeviceY(y
+ h
));
427 wxLogLastError(_T("CreateRectRgn"));
431 SetClippingHrgn((WXHRGN
)hrgn
);
433 ::DeleteObject(hrgn
);
437 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
439 SetClippingHrgn(region
.GetHRGN());
442 void wxDC::DestroyClippingRegion()
444 #ifdef __WXMICROWIN__
445 if (!GetHDC()) return;
448 if (m_clipping
&& m_hDC
)
450 // TODO: this should restore the previous clipping region,
451 // so that OnPaint processing works correctly, and the update
452 // clipping region doesn't get destroyed after the first
453 // DestroyClippingRegion.
454 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
455 ::SelectClipRgn(GetHdc(), rgn
);
462 // ---------------------------------------------------------------------------
463 // query capabilities
464 // ---------------------------------------------------------------------------
466 bool wxDC::CanDrawBitmap() const
471 bool wxDC::CanGetTextExtent() const
473 #ifdef __WXMICROWIN__
474 // TODO Extend MicroWindows' GetDeviceCaps function
477 // What sort of display is it?
478 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
480 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
484 int wxDC::GetDepth() const
486 #ifdef __WXMICROWIN__
487 if (!GetHDC()) return 16;
490 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
493 // ---------------------------------------------------------------------------
495 // ---------------------------------------------------------------------------
499 #ifdef __WXMICROWIN__
500 if (!GetHDC()) return;
506 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
510 // No, I think we should simply ignore this if printing on e.g.
512 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
513 if (!m_selectedBitmap
.Ok())
516 rect
.left
= 0; rect
.top
= 0;
517 rect
.right
= m_selectedBitmap
.GetWidth();
518 rect
.bottom
= m_selectedBitmap
.GetHeight();
522 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
525 DWORD colour
= ::GetBkColor(GetHdc());
526 HBRUSH brush
= ::CreateSolidBrush(colour
);
527 ::FillRect(GetHdc(), &rect
, brush
);
528 ::DeleteObject(brush
);
530 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
531 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
534 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
536 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
537 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
538 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
539 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
543 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
549 #ifdef __WXMICROWIN__
550 if (!GetHDC()) return FALSE
;
553 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
555 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
556 : FLOODFILLBORDER
) ) ;
559 // quoting from the MSDN docs:
561 // Following are some of the reasons this function might fail:
563 // * The filling could not be completed.
564 // * The specified point has the boundary color specified by the
565 // crColor parameter (if FLOODFILLBORDER was requested).
566 // * The specified point does not have the color specified by
567 // crColor (if FLOODFILLSURFACE was requested)
568 // * The point is outside the clipping region that is, it is not
569 // visible on the device.
571 wxLogLastError(wxT("ExtFloodFill"));
574 CalcBoundingBox(x
, y
);
580 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
582 #ifdef __WXMICROWIN__
583 if (!GetHDC()) return FALSE
;
586 wxCHECK_MSG( col
, FALSE
, _T("NULL colour parameter in wxDC::GetPixel") );
588 // get the color of the pixel
589 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
591 wxRGBToColour(*col
, pixelcolor
);
596 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
598 #ifdef __WXMICROWIN__
599 if (!GetHDC()) return;
602 wxCoord x1
= x
-VIEWPORT_EXTENT
;
603 wxCoord y1
= y
-VIEWPORT_EXTENT
;
604 wxCoord x2
= x
+VIEWPORT_EXTENT
;
605 wxCoord y2
= y
+VIEWPORT_EXTENT
;
607 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
608 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
610 CalcBoundingBox(x1
, y1
);
611 CalcBoundingBox(x2
, y2
);
614 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
616 #ifdef __WXMICROWIN__
617 if (!GetHDC()) return;
620 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
622 CalcBoundingBox(x1
, y1
);
623 CalcBoundingBox(x2
, y2
);
626 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
627 // and ending at (x2, y2)
628 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
629 wxCoord x2
, wxCoord y2
,
630 wxCoord xc
, wxCoord yc
)
633 // Slower emulation since WinCE doesn't support Pie and Arc
634 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
635 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
636 if( y1
>yc
) sa
= -sa
; // below center
637 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
638 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
641 #ifdef __WXMICROWIN__
642 if (!GetHDC()) return;
645 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
649 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
650 wxCoord r
= (wxCoord
)radius
;
652 // treat the special case of full circle separately
653 if ( x1
== x2
&& y1
== y2
)
655 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
659 wxCoord xx1
= XLOG2DEV(x1
);
660 wxCoord yy1
= YLOG2DEV(y1
);
661 wxCoord xx2
= XLOG2DEV(x2
);
662 wxCoord yy2
= YLOG2DEV(y2
);
663 wxCoord xxc
= XLOG2DEV(xc
);
664 wxCoord yyc
= YLOG2DEV(yc
);
665 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
667 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
668 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
669 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
670 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
672 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
674 // Have to add 1 to bottom-right corner of rectangle
675 // to make semi-circles look right (crooked line otherwise).
676 // Unfortunately this is not a reliable method, depends
677 // on the size of shape.
678 // TODO: figure out why this happens!
679 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
683 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
686 CalcBoundingBox(xc
- r
, yc
- r
);
687 CalcBoundingBox(xc
+ r
, yc
+ r
);
691 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
692 wxCoord width
, wxCoord height
)
694 #ifdef __WXMICROWIN__
695 if (!GetHDC()) return;
698 wxCoord x2
= x1
+ width
,
701 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
709 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
711 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
714 // In WIN16, draw a cross
715 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
716 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
717 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
718 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
719 ::SetROP2(GetHdc(), R2_COPYPEN
);
720 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
721 MoveToEx(GetHdc(), x1
, y1
, NULL
);
722 LineTo(GetHdc(), x2
, y2
);
723 MoveToEx(GetHdc(), x2
, y1
, NULL
);
724 LineTo(GetHdc(), x1
, y2
);
725 ::SelectObject(GetHdc(), hPenOld
);
726 ::SelectObject(GetHdc(), hBrushOld
);
727 ::DeleteObject(blackPen
);
730 CalcBoundingBox(x1
, y1
);
731 CalcBoundingBox(x2
, y2
);
734 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
736 #ifdef __WXMICROWIN__
737 if (!GetHDC()) return;
740 COLORREF color
= 0x00ffffff;
743 color
= m_pen
.GetColour().GetPixel();
746 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
748 CalcBoundingBox(x
, y
);
751 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
753 #ifdef __WXMICROWIN__
754 if (!GetHDC()) return;
757 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
759 // Do things less efficiently if we have offsets
760 if (xoffset
!= 0 || yoffset
!= 0)
762 POINT
*cpoints
= new POINT
[n
];
764 for (i
= 0; i
< n
; i
++)
766 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
767 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
769 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
772 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
774 (void)Polygon(GetHdc(), cpoints
, n
);
776 SetPolyFillMode(GetHdc(),prev
);
783 for (i
= 0; i
< n
; i
++)
784 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
787 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
789 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
791 SetPolyFillMode(GetHdc(),prev
);
797 wxDC::DoDrawPolyPolygon(int n
,
804 #ifdef __WXMICROWIN__
805 if (!GetHDC()) return;
808 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
810 for (i
= cnt
= 0; i
< n
; i
++)
813 // Do things less efficiently if we have offsets
814 if (xoffset
!= 0 || yoffset
!= 0)
816 POINT
*cpoints
= new POINT
[cnt
];
817 for (i
= 0; i
< cnt
; i
++)
819 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
820 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
822 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
824 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
825 (void)PolyPolygon(GetHdc(), cpoints
, start
, n
);
826 SetPolyFillMode(GetHdc(),prev
);
831 for (i
= 0; i
< cnt
; i
++)
832 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
834 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
835 (void)PolyPolygon(GetHdc(), (POINT
*) points
, start
, n
);
836 SetPolyFillMode(GetHdc(),prev
);
840 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
842 #ifdef __WXMICROWIN__
843 if (!GetHDC()) return;
846 // Do things less efficiently if we have offsets
847 if (xoffset
!= 0 || yoffset
!= 0)
849 POINT
*cpoints
= new POINT
[n
];
851 for (i
= 0; i
< n
; i
++)
853 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
854 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
856 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
858 (void)Polyline(GetHdc(), cpoints
, n
);
864 for (i
= 0; i
< n
; i
++)
865 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
867 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
871 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
873 #ifdef __WXMICROWIN__
874 if (!GetHDC()) return;
877 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
879 wxCoord x2
= x
+ width
;
880 wxCoord y2
= y
+ height
;
882 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
885 rect
.left
= XLOG2DEV(x
);
886 rect
.top
= YLOG2DEV(y
);
887 rect
.right
= XLOG2DEV(x2
);
888 rect
.bottom
= YLOG2DEV(y2
);
889 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
893 // Windows draws the filled rectangles without outline (i.e. drawn with a
894 // transparent pen) one pixel smaller in both directions and we want them
895 // to have the same size regardless of which pen is used - adjust
897 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
898 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
904 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
908 CalcBoundingBox(x
, y
);
909 CalcBoundingBox(x2
, y2
);
912 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
914 #ifdef __WXMICROWIN__
915 if (!GetHDC()) return;
918 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
920 // Now, a negative radius value is interpreted to mean
921 // 'the proportion of the smallest X or Y dimension'
925 double smallest
= (width
< height
) ? width
: height
;
926 radius
= (- radius
* smallest
);
929 wxCoord x2
= (x
+width
);
930 wxCoord y2
= (y
+height
);
932 // Windows draws the filled rectangles without outline (i.e. drawn with a
933 // transparent pen) one pixel smaller in both directions and we want them
934 // to have the same size regardless of which pen is used - adjust
935 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
941 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
942 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
944 CalcBoundingBox(x
, y
);
945 CalcBoundingBox(x2
, y2
);
948 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
950 #ifdef __WXMICROWIN__
951 if (!GetHDC()) return;
954 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
956 wxCoord x2
= (x
+width
);
957 wxCoord y2
= (y
+height
);
959 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
961 CalcBoundingBox(x
, y
);
962 CalcBoundingBox(x2
, y2
);
965 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
966 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
969 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
972 #ifdef __WXMICROWIN__
973 if (!GetHDC()) return;
976 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
981 int rx1
= XLOG2DEV(x
+w
/2);
982 int ry1
= YLOG2DEV(y
+h
/2);
989 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
990 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
991 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
992 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
994 // draw pie with NULL_PEN first and then outline otherwise a line is
995 // drawn from the start and end points to the centre
996 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
999 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1000 rx1
, ry1
, rx2
, ry2
);
1004 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1005 rx1
, ry1
-1, rx2
, ry2
-1);
1008 ::SelectObject(GetHdc(), hpenOld
);
1010 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1011 rx1
, ry1
, rx2
, ry2
);
1013 CalcBoundingBox(x
, y
);
1014 CalcBoundingBox(x2
, y2
);
1018 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1020 #ifdef __WXMICROWIN__
1021 if (!GetHDC()) return;
1024 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1027 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1029 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1032 CalcBoundingBox(x
, y
);
1033 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1036 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1038 #ifdef __WXMICROWIN__
1039 if (!GetHDC()) return;
1042 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1044 int width
= bmp
.GetWidth(),
1045 height
= bmp
.GetHeight();
1047 HBITMAP hbmpMask
= 0;
1050 HPALETTE oldPal
= 0;
1051 #endif // wxUSE_PALETTE
1053 if ( bmp
.HasAlpha() )
1056 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1058 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1064 wxMask
*mask
= bmp
.GetMask();
1066 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1070 // don't give assert here because this would break existing
1071 // programs - just silently ignore useMask parameter
1078 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1080 // On some systems, MaskBlt succeeds yet is much much slower
1081 // than the wxWindows fall-back implementation. So we need
1082 // to be able to switch this on and off at runtime.
1084 #if wxUSE_SYSTEM_OPTIONS
1085 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1089 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1090 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1092 wxPalette
*pal
= bmp
.GetPalette();
1093 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1095 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1096 ::RealizePalette(hdcMem
);
1098 #endif // wxUSE_PALETTE
1100 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1103 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1107 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1108 #endif // wxUSE_PALETTE
1110 ::SelectObject(hdcMem
, hOldBitmap
);
1117 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1120 memDC
.SelectObject(bmp
);
1122 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1124 memDC
.SelectObject(wxNullBitmap
);
1127 else // no mask, just use BitBlt()
1130 HDC memdc
= ::CreateCompatibleDC( cdc
);
1131 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1133 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1135 COLORREF old_textground
= ::GetTextColor(GetHdc());
1136 COLORREF old_background
= ::GetBkColor(GetHdc());
1137 if (m_textForegroundColour
.Ok())
1139 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1141 if (m_textBackgroundColour
.Ok())
1143 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1147 wxPalette
*pal
= bmp
.GetPalette();
1148 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1150 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1151 ::RealizePalette(memdc
);
1153 #endif // wxUSE_PALETTE
1155 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1156 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1160 ::SelectPalette(memdc
, oldPal
, FALSE
);
1161 #endif // wxUSE_PALETTE
1163 ::SelectObject( memdc
, hOldBitmap
);
1164 ::DeleteDC( memdc
);
1166 ::SetTextColor(GetHdc(), old_textground
);
1167 ::SetBkColor(GetHdc(), old_background
);
1171 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1173 #ifdef __WXMICROWIN__
1174 if (!GetHDC()) return;
1177 DrawAnyText(text
, x
, y
);
1179 // update the bounding box
1180 CalcBoundingBox(x
, y
);
1183 GetTextExtent(text
, &w
, &h
);
1184 CalcBoundingBox(x
+ w
, y
+ h
);
1187 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1189 #ifdef __WXMICROWIN__
1190 if (!GetHDC()) return;
1193 // prepare for drawing the text
1194 if ( m_textForegroundColour
.Ok() )
1195 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1197 DWORD old_background
= 0;
1198 if ( m_textBackgroundColour
.Ok() )
1200 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1203 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1207 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1208 text
.c_str(), text
.length(), NULL
) == 0 )
1210 wxLogLastError(wxT("TextOut"));
1213 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1214 text
.c_str(), text
.length()) == 0 )
1216 wxLogLastError(wxT("TextOut"));
1220 // restore the old parameters (text foreground colour may be left because
1221 // it never is set to anything else, but background should remain
1222 // transparent even if we just drew an opaque string)
1223 if ( m_textBackgroundColour
.Ok() )
1224 (void)SetBkColor(GetHdc(), old_background
);
1226 SetBkMode(GetHdc(), TRANSPARENT
);
1229 void wxDC::DoDrawRotatedText(const wxString
& text
,
1230 wxCoord x
, wxCoord y
,
1233 #ifdef __WXMICROWIN__
1234 if (!GetHDC()) return;
1237 // we test that we have some font because otherwise we should still use the
1238 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1239 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1240 // font for drawing rotated fonts unfortunately)
1241 if ( (angle
== 0.0) && m_font
.Ok() )
1243 DoDrawText(text
, x
, y
);
1245 #ifndef __WXMICROWIN__
1248 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1249 // because it's not TrueType and so can't have non zero
1250 // orientation/escapement under Win9x
1251 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1252 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1254 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1256 wxLogLastError(wxT("GetObject(hfont)"));
1259 // GDI wants the angle in tenth of degree
1260 long angle10
= (long)(angle
* 10);
1261 lf
.lfEscapement
= angle10
;
1262 lf
. lfOrientation
= angle10
;
1264 hfont
= ::CreateFontIndirect(&lf
);
1267 wxLogLastError(wxT("CreateFont"));
1271 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1273 DrawAnyText(text
, x
, y
);
1275 (void)::SelectObject(GetHdc(), hfontOld
);
1276 (void)::DeleteObject(hfont
);
1279 // call the bounding box by adding all four vertices of the rectangle
1280 // containing the text to it (simpler and probably not slower than
1281 // determining which of them is really topmost/leftmost/...)
1283 GetTextExtent(text
, &w
, &h
);
1285 double rad
= DegToRad(angle
);
1287 // "upper left" and "upper right"
1288 CalcBoundingBox(x
, y
);
1289 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1291 // "bottom left" and "bottom right"
1292 x
+= (wxCoord
)(h
*sin(rad
));
1293 y
+= (wxCoord
)(h
*cos(rad
));
1294 CalcBoundingBox(x
, y
);
1295 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1300 // ---------------------------------------------------------------------------
1302 // ---------------------------------------------------------------------------
1306 void wxDC::DoSelectPalette(bool realize
)
1308 #ifdef __WXMICROWIN__
1309 if (!GetHDC()) return;
1312 // Set the old object temporarily, in case the assignment deletes an object
1313 // that's not yet selected out.
1316 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1320 if ( m_palette
.Ok() )
1322 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1323 GetHpaletteOf(m_palette
),
1326 m_oldPalette
= (WXHPALETTE
) oldPal
;
1329 ::RealizePalette(GetHdc());
1333 void wxDC::SetPalette(const wxPalette
& palette
)
1337 m_palette
= palette
;
1338 DoSelectPalette(TRUE
);
1342 void wxDC::InitializePalette()
1344 if ( wxDisplayDepth() <= 8 )
1346 // look for any window or parent that has a custom palette. If any has
1347 // one then we need to use it in drawing operations
1348 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1350 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1351 if ( m_hasCustomPalette
)
1353 m_palette
= win
->GetPalette();
1355 // turn on MSW translation for this palette
1361 #endif // wxUSE_PALETTE
1363 void wxDC::SetFont(const wxFont
& the_font
)
1365 #ifdef __WXMICROWIN__
1366 if (!GetHDC()) return;
1369 // Set the old object temporarily, in case the assignment deletes an object
1370 // that's not yet selected out.
1373 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1382 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
1386 if (m_font
.Ok() && m_font
.GetResourceHandle())
1388 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
1389 if (f
== (HFONT
) NULL
)
1391 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1394 m_oldFont
= (WXHFONT
) f
;
1398 void wxDC::SetPen(const wxPen
& pen
)
1400 #ifdef __WXMICROWIN__
1401 if (!GetHDC()) return;
1404 // Set the old object temporarily, in case the assignment deletes an object
1405 // that's not yet selected out.
1408 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1417 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
1423 if (m_pen
.GetResourceHandle())
1425 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
1427 m_oldPen
= (WXHPEN
) p
;
1432 void wxDC::SetBrush(const wxBrush
& brush
)
1434 #ifdef __WXMICROWIN__
1435 if (!GetHDC()) return;
1438 // Set the old object temporarily, in case the assignment deletes an object
1439 // that's not yet selected out.
1442 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1451 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1457 // to make sure the brush is alligned with the logical coordinates
1458 wxBitmap
*stipple
= m_brush
.GetStipple();
1459 if ( stipple
&& stipple
->Ok() )
1462 ::SetBrushOrgEx(GetHdc(),
1463 m_deviceOriginX
% stipple
->GetWidth(),
1464 m_deviceOriginY
% stipple
->GetHeight(),
1465 NULL
); // don't need previous brush origin
1467 ::SetBrushOrg(GetHdc(),
1468 m_deviceOriginX
% stipple
->GetWidth(),
1469 m_deviceOriginY
% stipple
->GetHeight());
1473 if ( m_brush
.GetResourceHandle() )
1475 HBRUSH b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1477 m_oldBrush
= (WXHBRUSH
) b
;
1482 void wxDC::SetBackground(const wxBrush
& brush
)
1484 #ifdef __WXMICROWIN__
1485 if (!GetHDC()) return;
1488 m_backgroundBrush
= brush
;
1490 if ( m_backgroundBrush
.Ok() )
1492 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1496 void wxDC::SetBackgroundMode(int mode
)
1498 #ifdef __WXMICROWIN__
1499 if (!GetHDC()) return;
1502 m_backgroundMode
= mode
;
1504 // SetBackgroundColour now only refers to text background
1505 // and m_backgroundMode is used there
1508 void wxDC::SetLogicalFunction(int function
)
1510 #ifdef __WXMICROWIN__
1511 if (!GetHDC()) return;
1514 m_logicalFunction
= function
;
1519 void wxDC::SetRop(WXHDC dc
)
1521 if ( !dc
|| m_logicalFunction
< 0 )
1526 switch (m_logicalFunction
)
1528 case wxCLEAR
: rop
= R2_BLACK
; break;
1529 case wxXOR
: rop
= R2_XORPEN
; break;
1530 case wxINVERT
: rop
= R2_NOT
; break;
1531 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1532 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1533 case wxCOPY
: rop
= R2_COPYPEN
; break;
1534 case wxAND
: rop
= R2_MASKPEN
; break;
1535 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1536 case wxNO_OP
: rop
= R2_NOP
; break;
1537 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1538 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1539 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1540 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1541 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1542 case wxOR
: rop
= R2_MERGEPEN
; break;
1543 case wxSET
: rop
= R2_WHITE
; break;
1546 wxFAIL_MSG( wxT("unsupported logical function") );
1550 SetROP2(GetHdc(), rop
);
1553 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1555 // We might be previewing, so return TRUE to let it continue.
1563 void wxDC::StartPage()
1567 void wxDC::EndPage()
1571 // ---------------------------------------------------------------------------
1573 // ---------------------------------------------------------------------------
1575 wxCoord
wxDC::GetCharHeight() const
1577 #ifdef __WXMICROWIN__
1578 if (!GetHDC()) return 0;
1581 TEXTMETRIC lpTextMetric
;
1583 GetTextMetrics(GetHdc(), &lpTextMetric
);
1585 return lpTextMetric
.tmHeight
;
1588 wxCoord
wxDC::GetCharWidth() const
1590 #ifdef __WXMICROWIN__
1591 if (!GetHDC()) return 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
);
1649 void wxDC::SetMapMode(int mode
)
1651 #ifdef __WXMICROWIN__
1652 if (!GetHDC()) return;
1655 m_mappingMode
= mode
;
1657 if ( mode
== wxMM_TEXT
)
1660 m_logicalScaleY
= 1.0;
1662 else // need to do some calculations
1664 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1665 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1666 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1667 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1669 if ( (mm_width
== 0) || (mm_height
== 0) )
1671 // we can't calculate mm2pixels[XY] then!
1675 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1676 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1681 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1682 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1686 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1687 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1691 m_logicalScaleX
= mm2pixelsX
;
1692 m_logicalScaleY
= mm2pixelsY
;
1696 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1697 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1701 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1705 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1706 // cases we could do with MM_TEXT and in the remaining 0.9% with
1707 // MM_ISOTROPIC (TODO!)
1709 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1711 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1712 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1714 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1715 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1717 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1718 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1722 void wxDC::SetUserScale(double x
, double y
)
1724 #ifdef __WXMICROWIN__
1725 if (!GetHDC()) return;
1729 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1735 SetMapMode(m_mappingMode
);
1739 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1741 #ifdef __WXMICROWIN__
1742 if (!GetHDC()) return;
1746 int signX
= xLeftRight
? 1 : -1,
1747 signY
= yBottomUp
? -1 : 1;
1749 if ( signX
!= m_signX
|| signY
!= m_signY
)
1754 SetMapMode(m_mappingMode
);
1759 void wxDC::SetSystemScale(double x
, double y
)
1761 #ifdef __WXMICROWIN__
1762 if (!GetHDC()) return;
1766 if ( x
== m_scaleX
&& y
== m_scaleY
)
1772 SetMapMode(m_mappingMode
);
1776 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1778 #ifdef __WXMICROWIN__
1779 if (!GetHDC()) return;
1783 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1786 m_logicalOriginX
= x
;
1787 m_logicalOriginY
= y
;
1789 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1793 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1795 #ifdef __WXMICROWIN__
1796 if (!GetHDC()) return;
1800 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1803 m_deviceOriginX
= x
;
1804 m_deviceOriginY
= y
;
1806 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1810 // ---------------------------------------------------------------------------
1811 // coordinates transformations
1812 // ---------------------------------------------------------------------------
1814 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1816 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1819 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1821 // axis orientation is not taken into account for conversion of a distance
1822 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1825 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1827 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1830 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1832 // axis orientation is not taken into account for conversion of a distance
1833 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1836 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1838 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1841 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1843 // axis orientation is not taken into account for conversion of a distance
1844 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1847 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1849 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1852 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1854 // axis orientation is not taken into account for conversion of a distance
1855 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1858 // ---------------------------------------------------------------------------
1860 // ---------------------------------------------------------------------------
1862 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1863 wxCoord width
, wxCoord height
,
1864 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1865 int rop
, bool useMask
,
1866 wxCoord xsrcMask
, wxCoord ysrcMask
)
1868 wxCHECK_MSG( source
, FALSE
, _T("wxDC::Blit(): NULL wxDC pointer") );
1870 #ifdef __WXMICROWIN__
1871 if (!GetHDC()) return FALSE
;
1874 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1875 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1877 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1878 GetHdcOf(*source
), bmpSrc
) )
1882 wxMask
*mask
= NULL
;
1885 mask
= bmpSrc
.GetMask();
1887 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1889 // don't give assert here because this would break existing
1890 // programs - just silently ignore useMask parameter
1895 if (xsrcMask
== -1 && ysrcMask
== -1)
1897 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1900 COLORREF old_textground
= ::GetTextColor(GetHdc());
1901 COLORREF old_background
= ::GetBkColor(GetHdc());
1902 if (m_textForegroundColour
.Ok())
1904 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1906 if (m_textBackgroundColour
.Ok())
1908 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1914 case wxXOR
: dwRop
= SRCINVERT
; break;
1915 case wxINVERT
: dwRop
= DSTINVERT
; break;
1916 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1917 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1918 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1919 case wxSET
: dwRop
= WHITENESS
; break;
1920 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1921 case wxAND
: dwRop
= SRCAND
; break;
1922 case wxOR
: dwRop
= SRCPAINT
; break;
1923 case wxEQUIV
: dwRop
= 0x00990066; break;
1924 case wxNAND
: dwRop
= 0x007700E6; break;
1925 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1926 case wxCOPY
: dwRop
= SRCCOPY
; break;
1927 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1928 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1929 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1931 wxFAIL_MSG( wxT("unsupported logical function") );
1935 bool success
= FALSE
;
1940 // we want the part of the image corresponding to the mask to be
1941 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1942 // meaning of fg and bg is inverted which corresponds to wxWin notion
1943 // of the mask which is also contrary to the Windows one)
1945 // On some systems, MaskBlt succeeds yet is much much slower
1946 // than the wxWindows fall-back implementation. So we need
1947 // to be able to switch this on and off at runtime.
1948 #if wxUSE_SYSTEM_OPTIONS
1949 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1955 xdest
, ydest
, width
, height
,
1958 (HBITMAP
)mask
->GetMaskBitmap(),
1960 MAKEROP4(dwRop
, DSTCOPY
)
1967 // Blit bitmap with mask
1970 HBITMAP buffer_bmap
;
1972 #if wxUSE_DC_CACHEING
1973 // create a temp buffer bitmap and DCs to access it and the mask
1974 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1975 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1977 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1978 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1980 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1983 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1984 #else // !wxUSE_DC_CACHEING
1985 // create a temp buffer bitmap and DCs to access it and the mask
1986 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1987 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1988 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1989 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1990 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1991 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1993 // copy dest to buffer
1994 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1995 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1997 wxLogLastError(wxT("BitBlt"));
2000 // copy src to buffer using selected raster op
2001 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2002 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2004 wxLogLastError(wxT("BitBlt"));
2007 // set masked area in buffer to BLACK (pixel value 0)
2008 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2009 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2010 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2011 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2013 wxLogLastError(wxT("BitBlt"));
2016 // set unmasked area in dest to BLACK
2017 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2018 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2019 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2020 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2022 wxLogLastError(wxT("BitBlt"));
2024 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2025 ::SetTextColor(GetHdc(), prevCol
);
2027 // OR buffer to dest
2028 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2029 (int)width
, (int)height
,
2030 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2033 wxLogLastError(wxT("BitBlt"));
2036 // tidy up temporary DCs and bitmap
2037 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2038 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2040 #if !wxUSE_DC_CACHEING
2042 ::DeleteDC(dc_mask
);
2043 ::DeleteDC(dc_buffer
);
2044 ::DeleteObject(buffer_bmap
);
2049 else // no mask, just BitBlt() it
2051 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2052 // use StretchBlt() if available and finally fall back to BitBlt()
2054 // FIXME: use appropriate WinCE functions
2056 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2057 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2062 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2064 &ds
) == sizeof(ds
) )
2066 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2068 // Figure out what co-ordinate system we're supposed to specify
2070 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2074 ysrc
= hDIB
- (ysrc
+ height
);
2077 if ( ::StretchDIBits(GetHdc(),
2083 (LPBITMAPINFO
)&ds
.dsBmih
,
2086 ) == (int)GDI_ERROR
)
2088 wxLogLastError(wxT("StretchDIBits"));
2097 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2102 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2108 xdest
, ydest
, width
, height
,
2110 xsrc
, ysrc
, width
, height
,
2114 wxLogLastError(_T("StretchBlt"));
2128 (int)width
, (int)height
,
2134 wxLogLastError(_T("BitBlt"));
2143 ::SetTextColor(GetHdc(), old_textground
);
2144 ::SetBkColor(GetHdc(), old_background
);
2149 void wxDC::DoGetSize(int *w
, int *h
) const
2151 #ifdef __WXMICROWIN__
2152 if (!GetHDC()) return;
2155 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2156 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2159 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2161 #ifdef __WXMICROWIN__
2162 if (!GetHDC()) return;
2165 // if we implement it in terms of DoGetSize() instead of directly using the
2166 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2167 // will also work for wxWindowDC and wxClientDC even though their size is
2168 // not the same as the total size of the screen
2169 int wPixels
, hPixels
;
2170 DoGetSize(&wPixels
, &hPixels
);
2174 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2176 wxCHECK_RET( wTotal
, _T("0 width device?") );
2178 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2183 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2185 wxCHECK_RET( hTotal
, _T("0 height device?") );
2187 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2191 wxSize
wxDC::GetPPI() const
2193 #ifdef __WXMICROWIN__
2194 if (!GetHDC()) return wxSize();
2197 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2198 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2200 return wxSize(x
, y
);
2203 // For use by wxWindows only, unless custom units are required.
2204 void wxDC::SetLogicalScale(double x
, double y
)
2206 #ifdef __WXMICROWIN__
2207 if (!GetHDC()) return;
2210 m_logicalScaleX
= x
;
2211 m_logicalScaleY
= y
;
2214 // ----------------------------------------------------------------------------
2216 // ----------------------------------------------------------------------------
2218 #if wxUSE_DC_CACHEING
2221 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2222 * improve it in due course, either using arrays, or simply storing pointers to one
2223 * entry for the bitmap, and two for the DCs. -- JACS
2226 wxList
wxDC::sm_bitmapCache
;
2227 wxList
wxDC::sm_dcCache
;
2229 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2238 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2247 wxDCCacheEntry::~wxDCCacheEntry()
2250 ::DeleteObject((HBITMAP
) m_bitmap
);
2252 ::DeleteDC((HDC
) m_dc
);
2255 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2257 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2258 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2261 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2263 if (entry
->m_depth
== depth
)
2265 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2267 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2268 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2269 if ( !entry
->m_bitmap
)
2271 wxLogLastError(wxT("CreateCompatibleBitmap"));
2273 entry
->m_width
= w
; entry
->m_height
= h
;
2279 node
= node
->GetNext();
2281 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2284 wxLogLastError(wxT("CreateCompatibleBitmap"));
2286 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2287 AddToBitmapCache(entry
);
2291 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2293 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2294 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2297 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2299 // Don't return the same one as we already have
2300 if (!notThis
|| (notThis
!= entry
))
2302 if (entry
->m_depth
== depth
)
2308 node
= node
->GetNext();
2310 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2313 wxLogLastError(wxT("CreateCompatibleDC"));
2315 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2316 AddToDCCache(entry
);
2320 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2322 sm_bitmapCache
.Append(entry
);
2325 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2327 sm_dcCache
.Append(entry
);
2330 void wxDC::ClearCache()
2332 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2333 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2336 // Clean up cache at app exit
2337 class wxDCModule
: public wxModule
2340 virtual bool OnInit() { return TRUE
; }
2341 virtual void OnExit() { wxDC::ClearCache(); }
2344 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2347 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2349 #endif // wxUSE_DC_CACHEING
2351 // ----------------------------------------------------------------------------
2352 // alpha channel support
2353 // ----------------------------------------------------------------------------
2355 static bool AlphaBlt(HDC hdcDst
,
2356 int x
, int y
, int width
, int height
,
2358 const wxBitmap
& bmp
)
2360 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2361 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2363 // do we have AlphaBlend() and company in the headers?
2364 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2365 // yes, now try to see if we have it during run-time
2366 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2367 HDC
,int,int,int,int,
2370 // bitmaps can be drawn only from GUI thread so there is no need to
2371 // protect this static variable from multiple threads
2372 static bool s_triedToLoad
= FALSE
;
2373 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2374 if ( !s_triedToLoad
)
2376 s_triedToLoad
= TRUE
;
2378 // don't give errors about the DLL being unavailable, we're
2379 // prepared to handle this
2382 wxDynamicLibrary
dll(_T("msimg32.dll"));
2383 if ( dll
.IsLoaded() )
2385 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2386 if ( pfnAlphaBlend
)
2388 // we must keep the DLL loaded if we want to be able to
2389 // call AlphaBlend() so just never unload it at all, not a
2396 if ( pfnAlphaBlend
)
2399 bf
.BlendOp
= AC_SRC_OVER
;
2401 bf
.SourceConstantAlpha
= 0xff;
2402 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2404 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2405 hdcSrc
, 0, 0, width
, height
,
2408 // skip wxAlphaBlend() call below
2412 wxLogLastError(_T("AlphaBlend"));
2414 #endif // defined(AC_SRC_OVER)
2416 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2418 #ifdef wxHAVE_RAW_BITMAP
2419 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2422 #else // !wxHAVE_RAW_BITMAP
2423 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2424 // alpha but at least something will be shown like this)
2426 #endif // wxHAVE_RAW_BITMAP
2430 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2431 #ifdef wxHAVE_RAW_BITMAP
2434 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2436 // get the destination DC pixels
2437 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2439 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2441 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2443 wxLogLastError(_T("BitBlt"));
2446 // combine them with the source bitmap using alpha
2447 wxAlphaPixelData
dataDst(bmpDst
),
2448 dataSrc((wxBitmap
&)bmpSrc
);
2450 wxCHECK_RET( dataDst
&& dataSrc
,
2451 _T("failed to get raw data in wxAlphaBlend") );
2453 wxAlphaPixelData::Iterator
pDst(dataDst
),
2456 for ( int y
= 0; y
< h
; y
++ )
2458 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2459 pSrcRowStart
= pSrc
;
2461 for ( int x
= 0; x
< w
; x
++ )
2463 // note that source bitmap uses premultiplied alpha (as required by
2464 // the real AlphaBlend)
2465 const unsigned beta
= 255 - pSrc
.Alpha();
2467 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2468 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2469 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2475 pDst
= pDstRowStart
;
2476 pSrc
= pSrcRowStart
;
2477 pDst
.OffsetY(dataDst
, 1);
2478 pSrc
.OffsetY(dataSrc
, 1);
2481 // and finally blit them back to the destination DC
2482 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2484 wxLogLastError(_T("BitBlt"));
2488 #endif // #ifdef wxHAVE_RAW_BITMAP