1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/window.h"
35 #include "wx/dialog.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
43 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
44 #include "wx/msw/missing.h" // needs to be before #include <commdlg.h>
46 #include "wx/sysopt.h"
47 #include "wx/dcprint.h"
48 #include "wx/module.h"
49 #include "wx/dynload.h"
51 #ifdef wxHAVE_RAW_BITMAP
52 #include "wx/rawbmp.h"
58 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
67 #define AC_SRC_ALPHA 1
70 /* Quaternary raster codes */
72 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
75 // apparently with MicroWindows it is possible that HDC is 0 so we have to
76 // check for this ourselves
78 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
79 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
81 #define WXMICROWIN_CHECK_HDC
82 #define WXMICROWIN_CHECK_HDC_RET(x)
85 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
87 // ---------------------------------------------------------------------------
89 // ---------------------------------------------------------------------------
91 static const int VIEWPORT_EXTENT
= 1000;
93 static const int MM_POINTS
= 9;
94 static const int MM_METRIC
= 10;
96 // usually this is defined in math.h
98 static const double M_PI
= 3.14159265358979323846;
101 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
102 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
103 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
105 // ----------------------------------------------------------------------------
106 // macros for logical <-> device coords conversion
107 // ----------------------------------------------------------------------------
110 We currently let Windows do all the translations itself so these macros are
111 not really needed (any more) but keep them to enhance readability of the
112 code by allowing to see where are the logical and where are the device
117 #define XLOG2DEV(x) (x)
118 #define YLOG2DEV(y) (y)
121 #define XDEV2LOG(x) (x)
122 #define YDEV2LOG(y) (y)
124 // ---------------------------------------------------------------------------
126 // ---------------------------------------------------------------------------
128 // convert degrees to radians
129 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
131 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
133 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
134 // to pass it to this function but as we already have it at the point
135 // of call anyhow we do
137 // return true if we could draw the bitmap in one way or the other, false
139 static bool AlphaBlt(HDC hdcDst
,
140 int x
, int y
, int w
, int h
,
142 const wxBitmap
& bmpSrc
);
144 #ifdef wxHAVE_RAW_BITMAP
145 // our (limited) AlphaBlend() replacement
147 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
150 // ----------------------------------------------------------------------------
152 // ----------------------------------------------------------------------------
154 // instead of duplicating the same code which sets and then restores text
155 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
156 // encapsulate this in a small helper class
158 // wxColourChanger: changes the text colours in the ctor if required and
159 // restores them in the dtor
160 class wxColourChanger
163 wxColourChanger(wxDC
& dc
);
169 COLORREF m_colFgOld
, m_colBgOld
;
173 DECLARE_NO_COPY_CLASS(wxColourChanger
)
176 // this class saves the old stretch blit mode during its life time
177 class StretchBltModeChanger
180 StretchBltModeChanger(HDC hdc
, int mode
)
184 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
186 wxLogLastError(_T("SetStretchBltMode"));
190 ~StretchBltModeChanger()
193 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
194 wxLogLastError(_T("SetStretchBltMode"));
203 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
206 // ===========================================================================
208 // ===========================================================================
210 // ----------------------------------------------------------------------------
212 // ----------------------------------------------------------------------------
214 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
216 const wxBrush
& brush
= dc
.GetBrush();
217 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
219 HDC hdc
= GetHdcOf(dc
);
220 m_colFgOld
= ::GetTextColor(hdc
);
221 m_colBgOld
= ::GetBkColor(hdc
);
223 // note that Windows convention is opposite to wxWindows one, this is
224 // why text colour becomes the background one and vice versa
225 const wxColour
& colFg
= dc
.GetTextForeground();
228 ::SetBkColor(hdc
, colFg
.GetPixel());
231 const wxColour
& colBg
= dc
.GetTextBackground();
234 ::SetTextColor(hdc
, colBg
.GetPixel());
238 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
241 // flag which telsl us to undo changes in the dtor
246 // nothing done, nothing to undo
251 wxColourChanger::~wxColourChanger()
255 // restore the colours we changed
256 HDC hdc
= GetHdcOf(m_dc
);
258 ::SetBkMode(hdc
, TRANSPARENT
);
259 ::SetTextColor(hdc
, m_colFgOld
);
260 ::SetBkColor(hdc
, m_colBgOld
);
264 // ---------------------------------------------------------------------------
266 // ---------------------------------------------------------------------------
268 // Default constructor
279 #endif // wxUSE_PALETTE
289 SelectOldObjects(m_hDC
);
291 // if we own the HDC, we delete it, otherwise we just release it
295 ::DeleteDC(GetHdc());
297 else // we don't own our HDC
301 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
305 // Must have been a wxScreenDC
306 ::ReleaseDC((HWND
) NULL
, GetHdc());
312 // This will select current objects out of the DC,
313 // which is what you have to do before deleting the
315 void wxDC::SelectOldObjects(WXHDC dc
)
321 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
323 if (m_selectedBitmap
.Ok())
325 m_selectedBitmap
.SetSelectedInto(NULL
);
332 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
337 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
342 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
349 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
352 #endif // wxUSE_PALETTE
355 m_brush
= wxNullBrush
;
358 m_palette
= wxNullPalette
;
359 #endif // wxUSE_PALETTE
361 m_backgroundBrush
= wxNullBrush
;
362 m_selectedBitmap
= wxNullBitmap
;
365 // ---------------------------------------------------------------------------
367 // ---------------------------------------------------------------------------
369 void wxDC::UpdateClipBox()
374 ::GetClipBox(GetHdc(), &rect
);
376 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
377 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
378 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
379 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
382 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
383 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
385 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
389 // note that we combine the new clipping region with the existing one: this
390 // is compatible with what the other ports do and is the documented
391 // behaviour now (starting with 2.3.3)
392 #if defined(__WXWINCE__)
394 if ( !::GetClipBox(GetHdc(), &rectClip
) )
397 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
398 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
399 rectClip
.right
, rectClip
.bottom
);
401 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
403 ::SelectClipRgn(GetHdc(), hrgnDest
);
406 ::DeleteObject(hrgnClipOld
);
407 ::DeleteObject(hrgnDest
);
409 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
411 wxLogLastError(_T("ExtSelectClipRgn"));
415 #endif // WinCE/!WinCE
422 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
424 // the region coords are always the device ones, so do the translation
427 // FIXME: possible +/-1 error here, to check!
428 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
430 LogicalToDeviceX(x
+ w
),
431 LogicalToDeviceY(y
+ h
));
434 wxLogLastError(_T("CreateRectRgn"));
438 SetClippingHrgn((WXHRGN
)hrgn
);
440 ::DeleteObject(hrgn
);
444 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
446 SetClippingHrgn(region
.GetHRGN());
449 void wxDC::DestroyClippingRegion()
453 if (m_clipping
&& m_hDC
)
455 // TODO: this should restore the previous clipping region,
456 // so that OnPaint processing works correctly, and the update
457 // clipping region doesn't get destroyed after the first
458 // DestroyClippingRegion.
459 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
460 ::SelectClipRgn(GetHdc(), rgn
);
467 // ---------------------------------------------------------------------------
468 // query capabilities
469 // ---------------------------------------------------------------------------
471 bool wxDC::CanDrawBitmap() const
476 bool wxDC::CanGetTextExtent() const
478 #ifdef __WXMICROWIN__
479 // TODO Extend MicroWindows' GetDeviceCaps function
482 // What sort of display is it?
483 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
485 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
489 int wxDC::GetDepth() const
491 WXMICROWIN_CHECK_HDC_RET(16)
493 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
496 // ---------------------------------------------------------------------------
498 // ---------------------------------------------------------------------------
507 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
511 // No, I think we should simply ignore this if printing on e.g.
513 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
514 if (!m_selectedBitmap
.Ok())
517 rect
.left
= 0; rect
.top
= 0;
518 rect
.right
= m_selectedBitmap
.GetWidth();
519 rect
.bottom
= m_selectedBitmap
.GetHeight();
523 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
526 DWORD colour
= ::GetBkColor(GetHdc());
527 HBRUSH brush
= ::CreateSolidBrush(colour
);
528 ::FillRect(GetHdc(), &rect
, brush
);
529 ::DeleteObject(brush
);
531 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
532 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
535 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
537 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
538 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
539 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
540 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
544 bool wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
550 WXMICROWIN_CHECK_HDC_RET(false)
552 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
554 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
555 : FLOODFILLBORDER
) ) ;
558 // quoting from the MSDN docs:
560 // Following are some of the reasons this function might fail:
562 // * The filling could not be completed.
563 // * The specified point has the boundary color specified by the
564 // crColor parameter (if FLOODFILLBORDER was requested).
565 // * The specified point does not have the color specified by
566 // crColor (if FLOODFILLSURFACE was requested)
567 // * The point is outside the clipping region that is, it is not
568 // visible on the device.
570 wxLogLastError(wxT("ExtFloodFill"));
573 CalcBoundingBox(x
, y
);
579 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
581 WXMICROWIN_CHECK_HDC_RET(false)
583 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
585 // get the color of the pixel
586 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
588 wxRGBToColour(*col
, pixelcolor
);
593 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
597 wxCoord x1
= x
-VIEWPORT_EXTENT
;
598 wxCoord y1
= y
-VIEWPORT_EXTENT
;
599 wxCoord x2
= x
+VIEWPORT_EXTENT
;
600 wxCoord y2
= y
+VIEWPORT_EXTENT
;
602 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
603 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
605 CalcBoundingBox(x1
, y1
);
606 CalcBoundingBox(x2
, y2
);
609 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
613 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
615 CalcBoundingBox(x1
, y1
);
616 CalcBoundingBox(x2
, y2
);
619 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
620 // and ending at (x2, y2)
621 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
622 wxCoord x2
, wxCoord y2
,
623 wxCoord xc
, wxCoord yc
)
626 // Slower emulation since WinCE doesn't support Pie and Arc
627 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
628 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
629 if( y1
>yc
) sa
= -sa
; // below center
630 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
631 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
636 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
640 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
641 wxCoord r
= (wxCoord
)radius
;
643 // treat the special case of full circle separately
644 if ( x1
== x2
&& y1
== y2
)
646 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
650 wxCoord xx1
= XLOG2DEV(x1
);
651 wxCoord yy1
= YLOG2DEV(y1
);
652 wxCoord xx2
= XLOG2DEV(x2
);
653 wxCoord yy2
= YLOG2DEV(y2
);
654 wxCoord xxc
= XLOG2DEV(xc
);
655 wxCoord yyc
= YLOG2DEV(yc
);
656 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
658 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
659 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
660 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
661 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
663 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
665 // Have to add 1 to bottom-right corner of rectangle
666 // to make semi-circles look right (crooked line otherwise).
667 // Unfortunately this is not a reliable method, depends
668 // on the size of shape.
669 // TODO: figure out why this happens!
670 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
674 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
677 CalcBoundingBox(xc
- r
, yc
- r
);
678 CalcBoundingBox(xc
+ r
, yc
+ r
);
682 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
683 wxCoord width
, wxCoord height
)
687 wxCoord x2
= x1
+ width
,
690 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
698 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
700 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
702 #else // Symantec-MicroWin
704 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
705 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
706 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
707 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
708 ::SetROP2(GetHdc(), R2_COPYPEN
);
709 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
710 MoveToEx(GetHdc(), x1
, y1
, NULL
);
711 LineTo(GetHdc(), x2
, y2
);
712 MoveToEx(GetHdc(), x2
, y1
, NULL
);
713 LineTo(GetHdc(), x1
, y2
);
714 ::SelectObject(GetHdc(), hPenOld
);
715 ::SelectObject(GetHdc(), hBrushOld
);
716 ::DeleteObject(blackPen
);
717 #endif // Win32/Symantec-MicroWin
719 CalcBoundingBox(x1
, y1
);
720 CalcBoundingBox(x2
, y2
);
723 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
727 COLORREF color
= 0x00ffffff;
730 color
= m_pen
.GetColour().GetPixel();
733 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
735 CalcBoundingBox(x
, y
);
738 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
742 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
744 // Do things less efficiently if we have offsets
745 if (xoffset
!= 0 || yoffset
!= 0)
747 POINT
*cpoints
= new POINT
[n
];
749 for (i
= 0; i
< n
; i
++)
751 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
752 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
754 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
757 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
759 (void)Polygon(GetHdc(), cpoints
, n
);
761 SetPolyFillMode(GetHdc(),prev
);
768 for (i
= 0; i
< n
; i
++)
769 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
772 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
774 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
776 SetPolyFillMode(GetHdc(),prev
);
782 wxDC::DoDrawPolyPolygon(int n
,
790 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
794 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
796 for (i
= cnt
= 0; i
< n
; i
++)
799 // Do things less efficiently if we have offsets
800 if (xoffset
!= 0 || yoffset
!= 0)
802 POINT
*cpoints
= new POINT
[cnt
];
803 for (i
= 0; i
< cnt
; i
++)
805 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
806 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
808 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
811 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
813 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
815 SetPolyFillMode(GetHdc(),prev
);
821 for (i
= 0; i
< cnt
; i
++)
822 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
825 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
827 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
829 SetPolyFillMode(GetHdc(),prev
);
836 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
840 // Do things less efficiently if we have offsets
841 if (xoffset
!= 0 || yoffset
!= 0)
843 POINT
*cpoints
= new POINT
[n
];
845 for (i
= 0; i
< n
; i
++)
847 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
848 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
850 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
852 (void)Polyline(GetHdc(), cpoints
, n
);
858 for (i
= 0; i
< n
; i
++)
859 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
861 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
865 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
869 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
871 wxCoord x2
= x
+ width
;
872 wxCoord y2
= y
+ height
;
874 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
877 rect
.left
= XLOG2DEV(x
);
878 rect
.top
= YLOG2DEV(y
);
879 rect
.right
= XLOG2DEV(x2
);
880 rect
.bottom
= YLOG2DEV(y2
);
881 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
885 // Windows draws the filled rectangles without outline (i.e. drawn with a
886 // transparent pen) one pixel smaller in both directions and we want them
887 // to have the same size regardless of which pen is used - adjust
889 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
890 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
896 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
900 CalcBoundingBox(x
, y
);
901 CalcBoundingBox(x2
, y2
);
904 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
908 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
910 // Now, a negative radius value is interpreted to mean
911 // 'the proportion of the smallest X or Y dimension'
915 double smallest
= (width
< height
) ? width
: height
;
916 radius
= (- radius
* smallest
);
919 wxCoord x2
= (x
+width
);
920 wxCoord y2
= (y
+height
);
922 // Windows draws the filled rectangles without outline (i.e. drawn with a
923 // transparent pen) one pixel smaller in both directions and we want them
924 // to have the same size regardless of which pen is used - adjust
925 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
931 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
932 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
934 CalcBoundingBox(x
, y
);
935 CalcBoundingBox(x2
, y2
);
938 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
942 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
944 wxCoord x2
= (x
+width
);
945 wxCoord y2
= (y
+height
);
947 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
949 CalcBoundingBox(x
, y
);
950 CalcBoundingBox(x2
, y2
);
953 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
954 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
957 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
962 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
967 int rx1
= XLOG2DEV(x
+w
/2);
968 int ry1
= YLOG2DEV(y
+h
/2);
975 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
976 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
977 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
978 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
980 // draw pie with NULL_PEN first and then outline otherwise a line is
981 // drawn from the start and end points to the centre
982 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
985 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
990 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
991 rx1
, ry1
-1, rx2
, ry2
-1);
994 ::SelectObject(GetHdc(), hpenOld
);
996 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
999 CalcBoundingBox(x
, y
);
1000 CalcBoundingBox(x2
, y2
);
1004 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1006 WXMICROWIN_CHECK_HDC
1008 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1011 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1013 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1016 CalcBoundingBox(x
, y
);
1017 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1020 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1022 WXMICROWIN_CHECK_HDC
1024 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1026 int width
= bmp
.GetWidth(),
1027 height
= bmp
.GetHeight();
1029 HBITMAP hbmpMask
= 0;
1032 HPALETTE oldPal
= 0;
1033 #endif // wxUSE_PALETTE
1035 if ( bmp
.HasAlpha() )
1038 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1040 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1046 wxMask
*mask
= bmp
.GetMask();
1048 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1052 // don't give assert here because this would break existing
1053 // programs - just silently ignore useMask parameter
1060 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1062 // On some systems, MaskBlt succeeds yet is much much slower
1063 // than the wxWindows fall-back implementation. So we need
1064 // to be able to switch this on and off at runtime.
1066 #if wxUSE_SYSTEM_OPTIONS
1067 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1071 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1072 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1074 wxPalette
*pal
= bmp
.GetPalette();
1075 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1077 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1078 ::RealizePalette(hdcMem
);
1080 #endif // wxUSE_PALETTE
1082 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1085 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1089 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1090 #endif // wxUSE_PALETTE
1092 ::SelectObject(hdcMem
, hOldBitmap
);
1099 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1102 memDC
.SelectObject(bmp
);
1104 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1106 memDC
.SelectObject(wxNullBitmap
);
1109 else // no mask, just use BitBlt()
1112 HDC memdc
= ::CreateCompatibleDC( cdc
);
1113 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1115 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1117 COLORREF old_textground
= ::GetTextColor(GetHdc());
1118 COLORREF old_background
= ::GetBkColor(GetHdc());
1119 if (m_textForegroundColour
.Ok())
1121 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1123 if (m_textBackgroundColour
.Ok())
1125 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1129 wxPalette
*pal
= bmp
.GetPalette();
1130 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1132 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1133 ::RealizePalette(memdc
);
1135 #endif // wxUSE_PALETTE
1137 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1138 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1142 ::SelectPalette(memdc
, oldPal
, FALSE
);
1143 #endif // wxUSE_PALETTE
1145 ::SelectObject( memdc
, hOldBitmap
);
1146 ::DeleteDC( memdc
);
1148 ::SetTextColor(GetHdc(), old_textground
);
1149 ::SetBkColor(GetHdc(), old_background
);
1153 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1155 WXMICROWIN_CHECK_HDC
1157 DrawAnyText(text
, x
, y
);
1159 // update the bounding box
1160 CalcBoundingBox(x
, y
);
1163 GetTextExtent(text
, &w
, &h
);
1164 CalcBoundingBox(x
+ w
, y
+ h
);
1167 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1169 WXMICROWIN_CHECK_HDC
1171 // prepare for drawing the text
1172 if ( m_textForegroundColour
.Ok() )
1173 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1175 DWORD old_background
= 0;
1176 if ( m_textBackgroundColour
.Ok() )
1178 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1181 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1185 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1186 text
.c_str(), text
.length(), NULL
) == 0 )
1188 wxLogLastError(wxT("TextOut"));
1191 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1192 text
.c_str(), text
.length()) == 0 )
1194 wxLogLastError(wxT("TextOut"));
1198 // restore the old parameters (text foreground colour may be left because
1199 // it never is set to anything else, but background should remain
1200 // transparent even if we just drew an opaque string)
1201 if ( m_textBackgroundColour
.Ok() )
1202 (void)SetBkColor(GetHdc(), old_background
);
1204 SetBkMode(GetHdc(), TRANSPARENT
);
1207 void wxDC::DoDrawRotatedText(const wxString
& text
,
1208 wxCoord x
, wxCoord y
,
1211 WXMICROWIN_CHECK_HDC
1213 // we test that we have some font because otherwise we should still use the
1214 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1215 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1216 // font for drawing rotated fonts unfortunately)
1217 if ( (angle
== 0.0) && m_font
.Ok() )
1219 DoDrawText(text
, x
, y
);
1221 #ifndef __WXMICROWIN__
1224 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1225 // because it's not TrueType and so can't have non zero
1226 // orientation/escapement under Win9x
1227 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1228 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1230 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1232 wxLogLastError(wxT("GetObject(hfont)"));
1235 // GDI wants the angle in tenth of degree
1236 long angle10
= (long)(angle
* 10);
1237 lf
.lfEscapement
= angle10
;
1238 lf
. lfOrientation
= angle10
;
1240 hfont
= ::CreateFontIndirect(&lf
);
1243 wxLogLastError(wxT("CreateFont"));
1247 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1249 DrawAnyText(text
, x
, y
);
1251 (void)::SelectObject(GetHdc(), hfontOld
);
1252 (void)::DeleteObject(hfont
);
1255 // call the bounding box by adding all four vertices of the rectangle
1256 // containing the text to it (simpler and probably not slower than
1257 // determining which of them is really topmost/leftmost/...)
1259 GetTextExtent(text
, &w
, &h
);
1261 double rad
= DegToRad(angle
);
1263 // "upper left" and "upper right"
1264 CalcBoundingBox(x
, y
);
1265 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1267 // "bottom left" and "bottom right"
1268 x
+= (wxCoord
)(h
*sin(rad
));
1269 y
+= (wxCoord
)(h
*cos(rad
));
1270 CalcBoundingBox(x
, y
);
1271 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1276 // ---------------------------------------------------------------------------
1278 // ---------------------------------------------------------------------------
1282 void wxDC::DoSelectPalette(bool realize
)
1284 WXMICROWIN_CHECK_HDC
1286 // Set the old object temporarily, in case the assignment deletes an object
1287 // that's not yet selected out.
1290 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1294 if ( m_palette
.Ok() )
1296 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1297 GetHpaletteOf(m_palette
),
1300 m_oldPalette
= (WXHPALETTE
) oldPal
;
1303 ::RealizePalette(GetHdc());
1307 void wxDC::SetPalette(const wxPalette
& palette
)
1311 m_palette
= palette
;
1312 DoSelectPalette(true);
1316 void wxDC::InitializePalette()
1318 if ( wxDisplayDepth() <= 8 )
1320 // look for any window or parent that has a custom palette. If any has
1321 // one then we need to use it in drawing operations
1322 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1324 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1325 if ( m_hasCustomPalette
)
1327 m_palette
= win
->GetPalette();
1329 // turn on MSW translation for this palette
1335 #endif // wxUSE_PALETTE
1337 // SetFont/Pen/Brush() really ask to be implemented as a single template
1338 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1340 void wxDC::SetFont(const wxFont
& font
)
1342 WXMICROWIN_CHECK_HDC
1344 if ( font
== m_font
)
1349 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1350 if ( hfont
== HGDI_ERROR
)
1352 wxLogLastError(_T("SelectObject(font)"));
1357 m_oldFont
= (WXHPEN
)hfont
;
1362 else // invalid font, reset the current font
1366 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1368 wxLogLastError(_T("SelectObject(old font)"));
1374 m_font
= wxNullFont
;
1378 void wxDC::SetPen(const wxPen
& pen
)
1380 WXMICROWIN_CHECK_HDC
1387 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1388 if ( hpen
== HGDI_ERROR
)
1390 wxLogLastError(_T("SelectObject(pen)"));
1395 m_oldPen
= (WXHPEN
)hpen
;
1400 else // invalid pen, reset the current pen
1404 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1406 wxLogLastError(_T("SelectObject(old pen)"));
1416 void wxDC::SetBrush(const wxBrush
& brush
)
1418 WXMICROWIN_CHECK_HDC
1420 if ( brush
== m_brush
)
1425 // we must make sure the brush is aligned with the logical coordinates
1426 // before selecting it
1427 wxBitmap
*stipple
= brush
.GetStipple();
1428 if ( stipple
&& stipple
->Ok() )
1430 if ( !::SetBrushOrgEx
1433 m_deviceOriginX
% stipple
->GetWidth(),
1434 m_deviceOriginY
% stipple
->GetHeight(),
1435 NULL
// [out] previous brush origin
1438 wxLogLastError(_T("SetBrushOrgEx()"));
1442 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1443 if ( hbrush
== HGDI_ERROR
)
1445 wxLogLastError(_T("SelectObject(brush)"));
1450 m_oldBrush
= (WXHPEN
)hbrush
;
1455 else // invalid brush, reset the current brush
1459 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1461 wxLogLastError(_T("SelectObject(old brush)"));
1467 m_brush
= wxNullBrush
;
1471 void wxDC::SetBackground(const wxBrush
& brush
)
1473 WXMICROWIN_CHECK_HDC
1475 m_backgroundBrush
= brush
;
1477 if ( m_backgroundBrush
.Ok() )
1479 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1483 void wxDC::SetBackgroundMode(int mode
)
1485 WXMICROWIN_CHECK_HDC
1487 m_backgroundMode
= mode
;
1489 // SetBackgroundColour now only refers to text background
1490 // and m_backgroundMode is used there
1493 void wxDC::SetLogicalFunction(int function
)
1495 WXMICROWIN_CHECK_HDC
1497 m_logicalFunction
= function
;
1502 void wxDC::SetRop(WXHDC dc
)
1504 if ( !dc
|| m_logicalFunction
< 0 )
1509 switch (m_logicalFunction
)
1511 case wxCLEAR
: rop
= R2_BLACK
; break;
1512 case wxXOR
: rop
= R2_XORPEN
; break;
1513 case wxINVERT
: rop
= R2_NOT
; break;
1514 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1515 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1516 case wxCOPY
: rop
= R2_COPYPEN
; break;
1517 case wxAND
: rop
= R2_MASKPEN
; break;
1518 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1519 case wxNO_OP
: rop
= R2_NOP
; break;
1520 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1521 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1522 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1523 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1524 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1525 case wxOR
: rop
= R2_MERGEPEN
; break;
1526 case wxSET
: rop
= R2_WHITE
; break;
1529 wxFAIL_MSG( wxT("unsupported logical function") );
1533 SetROP2(GetHdc(), rop
);
1536 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1538 // We might be previewing, so return true to let it continue.
1546 void wxDC::StartPage()
1550 void wxDC::EndPage()
1554 // ---------------------------------------------------------------------------
1556 // ---------------------------------------------------------------------------
1558 wxCoord
wxDC::GetCharHeight() const
1560 WXMICROWIN_CHECK_HDC_RET(0)
1562 TEXTMETRIC lpTextMetric
;
1564 GetTextMetrics(GetHdc(), &lpTextMetric
);
1566 return lpTextMetric
.tmHeight
;
1569 wxCoord
wxDC::GetCharWidth() const
1571 WXMICROWIN_CHECK_HDC_RET(0)
1573 TEXTMETRIC lpTextMetric
;
1575 GetTextMetrics(GetHdc(), &lpTextMetric
);
1577 return lpTextMetric
.tmAveCharWidth
;
1580 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1581 wxCoord
*descent
, wxCoord
*externalLeading
,
1584 #ifdef __WXMICROWIN__
1589 if (descent
) *descent
= 0;
1590 if (externalLeading
) *externalLeading
= 0;
1593 #endif // __WXMICROWIN__
1598 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1600 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1602 else // don't change the font
1610 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1611 GetTextMetrics(GetHdc(), &tm
);
1618 *descent
= tm
.tmDescent
;
1619 if (externalLeading
)
1620 *externalLeading
= tm
.tmExternalLeading
;
1624 ::SelectObject(GetHdc(), hfontOld
);
1629 // Each element of the array will be the width of the string up to and
1630 // including the coresoponding character in text.
1632 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1634 static int maxLenText
= -1;
1635 static int maxWidth
= -1;
1638 int stlen
= text
.Length();
1640 if (maxLenText
== -1)
1642 // Win9x and WinNT+ have different limits
1643 int version
= wxGetOsVersion();
1644 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1645 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1649 widths
.Add(0, stlen
); // fill the array with zeros
1651 if (!::GetTextExtentExPoint(GetHdc(),
1652 text
.c_str(), // string to check
1653 wxMin(stlen
, maxLenText
),
1655 &fit
, // [out] count of chars
1657 &widths
[0], // array to fill
1661 wxLogLastError(wxT("GetTextExtentExPoint"));
1671 void wxDC::SetMapMode(int mode
)
1673 WXMICROWIN_CHECK_HDC
1675 m_mappingMode
= mode
;
1677 if ( mode
== wxMM_TEXT
)
1680 m_logicalScaleY
= 1.0;
1682 else // need to do some calculations
1684 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1685 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1686 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1687 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1689 if ( (mm_width
== 0) || (mm_height
== 0) )
1691 // we can't calculate mm2pixels[XY] then!
1695 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1696 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1701 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1702 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1706 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1707 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1711 m_logicalScaleX
= mm2pixelsX
;
1712 m_logicalScaleY
= mm2pixelsY
;
1716 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1717 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1721 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1725 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1726 // cases we could do with MM_TEXT and in the remaining 0.9% with
1727 // MM_ISOTROPIC (TODO!)
1729 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1731 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1732 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1734 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1735 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1737 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1738 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1742 void wxDC::SetUserScale(double x
, double y
)
1744 WXMICROWIN_CHECK_HDC
1747 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1753 SetMapMode(m_mappingMode
);
1757 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1759 WXMICROWIN_CHECK_HDC
1762 int signX
= xLeftRight
? 1 : -1,
1763 signY
= yBottomUp
? -1 : 1;
1765 if ( signX
!= m_signX
|| signY
!= m_signY
)
1770 SetMapMode(m_mappingMode
);
1775 void wxDC::SetSystemScale(double x
, double y
)
1777 WXMICROWIN_CHECK_HDC
1780 if ( x
== m_scaleX
&& y
== m_scaleY
)
1786 SetMapMode(m_mappingMode
);
1790 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1792 WXMICROWIN_CHECK_HDC
1795 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1798 m_logicalOriginX
= x
;
1799 m_logicalOriginY
= y
;
1801 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1805 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1807 WXMICROWIN_CHECK_HDC
1810 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1813 m_deviceOriginX
= x
;
1814 m_deviceOriginY
= y
;
1816 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1820 // ---------------------------------------------------------------------------
1821 // coordinates transformations
1822 // ---------------------------------------------------------------------------
1824 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1826 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1829 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1831 // axis orientation is not taken into account for conversion of a distance
1832 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1835 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1837 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1840 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1842 // axis orientation is not taken into account for conversion of a distance
1843 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1846 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1848 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1851 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1853 // axis orientation is not taken into account for conversion of a distance
1854 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1857 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1859 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1862 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1864 // axis orientation is not taken into account for conversion of a distance
1865 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1868 // ---------------------------------------------------------------------------
1870 // ---------------------------------------------------------------------------
1872 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1873 wxCoord width
, wxCoord height
,
1874 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1875 int rop
, bool useMask
,
1876 wxCoord xsrcMask
, wxCoord ysrcMask
)
1878 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1880 WXMICROWIN_CHECK_HDC_RET(false)
1882 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1883 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1885 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1886 GetHdcOf(*source
), bmpSrc
) )
1890 wxMask
*mask
= NULL
;
1893 mask
= bmpSrc
.GetMask();
1895 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1897 // don't give assert here because this would break existing
1898 // programs - just silently ignore useMask parameter
1903 if (xsrcMask
== -1 && ysrcMask
== -1)
1905 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1908 COLORREF old_textground
= ::GetTextColor(GetHdc());
1909 COLORREF old_background
= ::GetBkColor(GetHdc());
1910 if (m_textForegroundColour
.Ok())
1912 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1914 if (m_textBackgroundColour
.Ok())
1916 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1922 case wxXOR
: dwRop
= SRCINVERT
; break;
1923 case wxINVERT
: dwRop
= DSTINVERT
; break;
1924 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1925 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1926 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1927 case wxSET
: dwRop
= WHITENESS
; break;
1928 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1929 case wxAND
: dwRop
= SRCAND
; break;
1930 case wxOR
: dwRop
= SRCPAINT
; break;
1931 case wxEQUIV
: dwRop
= 0x00990066; break;
1932 case wxNAND
: dwRop
= 0x007700E6; break;
1933 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1934 case wxCOPY
: dwRop
= SRCCOPY
; break;
1935 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1936 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1937 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1939 wxFAIL_MSG( wxT("unsupported logical function") );
1943 bool success
= false;
1948 // we want the part of the image corresponding to the mask to be
1949 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1950 // meaning of fg and bg is inverted which corresponds to wxWin notion
1951 // of the mask which is also contrary to the Windows one)
1953 // On some systems, MaskBlt succeeds yet is much much slower
1954 // than the wxWindows fall-back implementation. So we need
1955 // to be able to switch this on and off at runtime.
1956 #if wxUSE_SYSTEM_OPTIONS
1957 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1963 xdest
, ydest
, width
, height
,
1966 (HBITMAP
)mask
->GetMaskBitmap(),
1968 MAKEROP4(dwRop
, DSTCOPY
)
1975 // Blit bitmap with mask
1978 HBITMAP buffer_bmap
;
1980 #if wxUSE_DC_CACHEING
1981 // create a temp buffer bitmap and DCs to access it and the mask
1982 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1983 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1985 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1986 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1988 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1991 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1992 #else // !wxUSE_DC_CACHEING
1993 // create a temp buffer bitmap and DCs to access it and the mask
1994 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1995 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1996 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1997 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1998 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1999 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2001 // copy dest to buffer
2002 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2003 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2005 wxLogLastError(wxT("BitBlt"));
2008 // copy src to buffer using selected raster op
2009 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2010 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2012 wxLogLastError(wxT("BitBlt"));
2015 // set masked area in buffer to BLACK (pixel value 0)
2016 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2017 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2018 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2019 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2021 wxLogLastError(wxT("BitBlt"));
2024 // set unmasked area in dest to BLACK
2025 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2026 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2027 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2028 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2030 wxLogLastError(wxT("BitBlt"));
2032 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2033 ::SetTextColor(GetHdc(), prevCol
);
2035 // OR buffer to dest
2036 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2037 (int)width
, (int)height
,
2038 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2041 wxLogLastError(wxT("BitBlt"));
2044 // tidy up temporary DCs and bitmap
2045 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2046 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2048 #if !wxUSE_DC_CACHEING
2050 ::DeleteDC(dc_mask
);
2051 ::DeleteDC(dc_buffer
);
2052 ::DeleteObject(buffer_bmap
);
2057 else // no mask, just BitBlt() it
2059 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2060 // use StretchBlt() if available and finally fall back to BitBlt()
2062 // FIXME: use appropriate WinCE functions
2064 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2065 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2070 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2072 &ds
) == sizeof(ds
) )
2074 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2076 // Figure out what co-ordinate system we're supposed to specify
2078 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2082 ysrc
= hDIB
- (ysrc
+ height
);
2085 if ( ::StretchDIBits(GetHdc(),
2091 (LPBITMAPINFO
)&ds
.dsBmih
,
2094 ) == (int)GDI_ERROR
)
2096 // On Win9x this API fails most (all?) of the time, so
2097 // logging it becomes quite distracting. Since it falls
2098 // back to the code below this is not really serious, so
2100 //wxLogLastError(wxT("StretchDIBits"));
2109 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2114 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2120 xdest
, ydest
, width
, height
,
2122 xsrc
, ysrc
, width
, height
,
2126 wxLogLastError(_T("StretchBlt"));
2140 (int)width
, (int)height
,
2146 wxLogLastError(_T("BitBlt"));
2155 ::SetTextColor(GetHdc(), old_textground
);
2156 ::SetBkColor(GetHdc(), old_background
);
2161 void wxDC::DoGetSize(int *w
, int *h
) const
2163 WXMICROWIN_CHECK_HDC
2165 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2166 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2169 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2171 WXMICROWIN_CHECK_HDC
2173 // if we implement it in terms of DoGetSize() instead of directly using the
2174 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2175 // will also work for wxWindowDC and wxClientDC even though their size is
2176 // not the same as the total size of the screen
2177 int wPixels
, hPixels
;
2178 DoGetSize(&wPixels
, &hPixels
);
2182 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2184 wxCHECK_RET( wTotal
, _T("0 width device?") );
2186 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2191 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2193 wxCHECK_RET( hTotal
, _T("0 height device?") );
2195 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2199 wxSize
wxDC::GetPPI() const
2201 WXMICROWIN_CHECK_HDC_RET(wxSize())
2203 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2204 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2206 return wxSize(x
, y
);
2209 // For use by wxWindows only, unless custom units are required.
2210 void wxDC::SetLogicalScale(double x
, double y
)
2212 WXMICROWIN_CHECK_HDC
2214 m_logicalScaleX
= x
;
2215 m_logicalScaleY
= y
;
2218 // ----------------------------------------------------------------------------
2220 // ----------------------------------------------------------------------------
2222 #if wxUSE_DC_CACHEING
2225 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2226 * improve it in due course, either using arrays, or simply storing pointers to one
2227 * entry for the bitmap, and two for the DCs. -- JACS
2230 wxList
wxDC::sm_bitmapCache
;
2231 wxList
wxDC::sm_dcCache
;
2233 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2242 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2251 wxDCCacheEntry::~wxDCCacheEntry()
2254 ::DeleteObject((HBITMAP
) m_bitmap
);
2256 ::DeleteDC((HDC
) m_dc
);
2259 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2261 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2262 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2265 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2267 if (entry
->m_depth
== depth
)
2269 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2271 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2272 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2273 if ( !entry
->m_bitmap
)
2275 wxLogLastError(wxT("CreateCompatibleBitmap"));
2277 entry
->m_width
= w
; entry
->m_height
= h
;
2283 node
= node
->GetNext();
2285 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2288 wxLogLastError(wxT("CreateCompatibleBitmap"));
2290 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2291 AddToBitmapCache(entry
);
2295 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2297 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2298 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2301 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2303 // Don't return the same one as we already have
2304 if (!notThis
|| (notThis
!= entry
))
2306 if (entry
->m_depth
== depth
)
2312 node
= node
->GetNext();
2314 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2317 wxLogLastError(wxT("CreateCompatibleDC"));
2319 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2320 AddToDCCache(entry
);
2324 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2326 sm_bitmapCache
.Append(entry
);
2329 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2331 sm_dcCache
.Append(entry
);
2334 void wxDC::ClearCache()
2336 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2337 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2340 // Clean up cache at app exit
2341 class wxDCModule
: public wxModule
2344 virtual bool OnInit() { return true; }
2345 virtual void OnExit() { wxDC::ClearCache(); }
2348 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2351 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2353 #endif // wxUSE_DC_CACHEING
2355 // ----------------------------------------------------------------------------
2356 // alpha channel support
2357 // ----------------------------------------------------------------------------
2359 static bool AlphaBlt(HDC hdcDst
,
2360 int x
, int y
, int width
, int height
,
2362 const wxBitmap
& bmp
)
2364 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2365 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2367 // do we have AlphaBlend() and company in the headers?
2368 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2369 // yes, now try to see if we have it during run-time
2370 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2371 HDC
,int,int,int,int,
2374 // bitmaps can be drawn only from GUI thread so there is no need to
2375 // protect this static variable from multiple threads
2376 static bool s_triedToLoad
= false;
2377 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2378 if ( !s_triedToLoad
)
2380 s_triedToLoad
= true;
2382 // don't give errors about the DLL being unavailable, we're
2383 // prepared to handle this
2386 wxDynamicLibrary
dll(_T("msimg32.dll"));
2387 if ( dll
.IsLoaded() )
2389 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2390 if ( pfnAlphaBlend
)
2392 // we must keep the DLL loaded if we want to be able to
2393 // call AlphaBlend() so just never unload it at all, not a
2400 if ( pfnAlphaBlend
)
2403 bf
.BlendOp
= AC_SRC_OVER
;
2405 bf
.SourceConstantAlpha
= 0xff;
2406 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2408 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2409 hdcSrc
, 0, 0, width
, height
,
2412 // skip wxAlphaBlend() call below
2416 wxLogLastError(_T("AlphaBlend"));
2418 #endif // defined(AC_SRC_OVER)
2420 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2422 #ifdef wxHAVE_RAW_BITMAP
2423 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2426 #else // !wxHAVE_RAW_BITMAP
2427 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2428 // alpha but at least something will be shown like this)
2430 #endif // wxHAVE_RAW_BITMAP
2434 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2435 #ifdef wxHAVE_RAW_BITMAP
2438 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2440 // get the destination DC pixels
2441 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2443 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2445 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2447 wxLogLastError(_T("BitBlt"));
2450 // combine them with the source bitmap using alpha
2451 wxAlphaPixelData
dataDst(bmpDst
),
2452 dataSrc((wxBitmap
&)bmpSrc
);
2454 wxCHECK_RET( dataDst
&& dataSrc
,
2455 _T("failed to get raw data in wxAlphaBlend") );
2457 wxAlphaPixelData::Iterator
pDst(dataDst
),
2460 for ( int y
= 0; y
< h
; y
++ )
2462 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2463 pSrcRowStart
= pSrc
;
2465 for ( int x
= 0; x
< w
; x
++ )
2467 // note that source bitmap uses premultiplied alpha (as required by
2468 // the real AlphaBlend)
2469 const unsigned beta
= 255 - pSrc
.Alpha();
2471 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2472 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2473 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2479 pDst
= pDstRowStart
;
2480 pSrc
= pSrcRowStart
;
2481 pDst
.OffsetY(dataDst
, 1);
2482 pSrc
.OffsetY(dataSrc
, 1);
2485 // and finally blit them back to the destination DC
2486 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2488 wxLogLastError(_T("BitBlt"));
2492 #endif // #ifdef wxHAVE_RAW_BITMAP