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 // apparently with MicroWindows it is possible that HDC is 0 so we have to
75 // check for this ourselves
77 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
78 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
80 #define WXMICROWIN_CHECK_HDC
81 #define WXMICROWIN_CHECK_HDC_RET(x)
84 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
86 // ---------------------------------------------------------------------------
88 // ---------------------------------------------------------------------------
90 static const int VIEWPORT_EXTENT
= 1000;
92 static const int MM_POINTS
= 9;
93 static const int MM_METRIC
= 10;
95 // usually this is defined in math.h
97 static const double M_PI
= 3.14159265358979323846;
100 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
101 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
102 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
104 // ----------------------------------------------------------------------------
105 // macros for logical <-> device coords conversion
106 // ----------------------------------------------------------------------------
109 We currently let Windows do all the translations itself so these macros are
110 not really needed (any more) but keep them to enhance readability of the
111 code by allowing to see where are the logical and where are the device
116 #define XLOG2DEV(x) (x)
117 #define YLOG2DEV(y) (y)
120 #define XDEV2LOG(x) (x)
121 #define YDEV2LOG(y) (y)
123 // ---------------------------------------------------------------------------
125 // ---------------------------------------------------------------------------
127 // convert degrees to radians
128 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
130 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
132 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
133 // to pass it to this function but as we already have it at the point
134 // of call anyhow we do
136 // return true if we could draw the bitmap in one way or the other, false
138 static bool AlphaBlt(HDC hdcDst
,
139 int x
, int y
, int w
, int h
,
141 const wxBitmap
& bmpSrc
);
143 #ifdef wxHAVE_RAW_BITMAP
144 // our (limited) AlphaBlend() replacement
146 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, const wxBitmap
& bmp
);
149 // ----------------------------------------------------------------------------
151 // ----------------------------------------------------------------------------
153 // instead of duplicating the same code which sets and then restores text
154 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
155 // encapsulate this in a small helper class
157 // wxColourChanger: changes the text colours in the ctor if required and
158 // restores them in the dtor
159 class wxColourChanger
162 wxColourChanger(wxDC
& dc
);
168 COLORREF m_colFgOld
, m_colBgOld
;
172 DECLARE_NO_COPY_CLASS(wxColourChanger
)
175 // this class saves the old stretch blit mode during its life time
176 class StretchBltModeChanger
179 StretchBltModeChanger(HDC hdc
, int mode
)
183 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
185 wxLogLastError(_T("SetStretchBltMode"));
189 ~StretchBltModeChanger()
192 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
193 wxLogLastError(_T("SetStretchBltMode"));
202 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
205 // ===========================================================================
207 // ===========================================================================
209 // ----------------------------------------------------------------------------
211 // ----------------------------------------------------------------------------
213 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
215 const wxBrush
& brush
= dc
.GetBrush();
216 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
218 HDC hdc
= GetHdcOf(dc
);
219 m_colFgOld
= ::GetTextColor(hdc
);
220 m_colBgOld
= ::GetBkColor(hdc
);
222 // note that Windows convention is opposite to wxWindows one, this is
223 // why text colour becomes the background one and vice versa
224 const wxColour
& colFg
= dc
.GetTextForeground();
227 ::SetBkColor(hdc
, colFg
.GetPixel());
230 const wxColour
& colBg
= dc
.GetTextBackground();
233 ::SetTextColor(hdc
, colBg
.GetPixel());
237 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
240 // flag which telsl us to undo changes in the dtor
245 // nothing done, nothing to undo
250 wxColourChanger::~wxColourChanger()
254 // restore the colours we changed
255 HDC hdc
= GetHdcOf(m_dc
);
257 ::SetBkMode(hdc
, TRANSPARENT
);
258 ::SetTextColor(hdc
, m_colFgOld
);
259 ::SetBkColor(hdc
, m_colBgOld
);
263 // ---------------------------------------------------------------------------
265 // ---------------------------------------------------------------------------
267 // Default constructor
278 #endif // wxUSE_PALETTE
288 SelectOldObjects(m_hDC
);
290 // if we own the HDC, we delete it, otherwise we just release it
294 ::DeleteDC(GetHdc());
296 else // we don't own our HDC
300 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
304 // Must have been a wxScreenDC
305 ::ReleaseDC((HWND
) NULL
, GetHdc());
311 // This will select current objects out of the DC,
312 // which is what you have to do before deleting the
314 void wxDC::SelectOldObjects(WXHDC dc
)
320 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
322 if (m_selectedBitmap
.Ok())
324 m_selectedBitmap
.SetSelectedInto(NULL
);
331 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
336 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
341 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
348 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
351 #endif // wxUSE_PALETTE
354 m_brush
= wxNullBrush
;
357 m_palette
= wxNullPalette
;
358 #endif // wxUSE_PALETTE
360 m_backgroundBrush
= wxNullBrush
;
361 m_selectedBitmap
= wxNullBitmap
;
364 // ---------------------------------------------------------------------------
366 // ---------------------------------------------------------------------------
368 void wxDC::UpdateClipBox()
373 ::GetClipBox(GetHdc(), &rect
);
375 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
376 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
377 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
378 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
381 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
382 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
384 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
388 // note that we combine the new clipping region with the existing one: this
389 // is compatible with what the other ports do and is the documented
390 // behaviour now (starting with 2.3.3)
391 #if defined(__WIN16__) || defined(__WXWINCE__)
393 if ( !::GetClipBox(GetHdc(), &rectClip
) )
396 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
397 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
398 rectClip
.right
, rectClip
.bottom
);
400 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
402 ::SelectClipRgn(GetHdc(), hrgnDest
);
405 ::DeleteObject(hrgnClipOld
);
406 ::DeleteObject(hrgnDest
);
408 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
410 wxLogLastError(_T("ExtSelectClipRgn"));
421 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
423 // the region coords are always the device ones, so do the translation
426 // FIXME: possible +/-1 error here, to check!
427 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
429 LogicalToDeviceX(x
+ w
),
430 LogicalToDeviceY(y
+ h
));
433 wxLogLastError(_T("CreateRectRgn"));
437 SetClippingHrgn((WXHRGN
)hrgn
);
439 ::DeleteObject(hrgn
);
443 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
445 SetClippingHrgn(region
.GetHRGN());
448 void wxDC::DestroyClippingRegion()
452 if (m_clipping
&& m_hDC
)
454 // TODO: this should restore the previous clipping region,
455 // so that OnPaint processing works correctly, and the update
456 // clipping region doesn't get destroyed after the first
457 // DestroyClippingRegion.
458 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
459 ::SelectClipRgn(GetHdc(), rgn
);
466 // ---------------------------------------------------------------------------
467 // query capabilities
468 // ---------------------------------------------------------------------------
470 bool wxDC::CanDrawBitmap() const
475 bool wxDC::CanGetTextExtent() const
477 #ifdef __WXMICROWIN__
478 // TODO Extend MicroWindows' GetDeviceCaps function
481 // What sort of display is it?
482 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
484 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
488 int wxDC::GetDepth() const
490 WXMICROWIN_CHECK_HDC_RET(16)
492 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
495 // ---------------------------------------------------------------------------
497 // ---------------------------------------------------------------------------
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 WXMICROWIN_CHECK_HDC_RET(false)
551 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
553 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
554 : FLOODFILLBORDER
) ) ;
557 // quoting from the MSDN docs:
559 // Following are some of the reasons this function might fail:
561 // * The filling could not be completed.
562 // * The specified point has the boundary color specified by the
563 // crColor parameter (if FLOODFILLBORDER was requested).
564 // * The specified point does not have the color specified by
565 // crColor (if FLOODFILLSURFACE was requested)
566 // * The point is outside the clipping region that is, it is not
567 // visible on the device.
569 wxLogLastError(wxT("ExtFloodFill"));
572 CalcBoundingBox(x
, y
);
578 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
580 WXMICROWIN_CHECK_HDC_RET(false)
582 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
584 // get the color of the pixel
585 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
587 wxRGBToColour(*col
, pixelcolor
);
592 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
596 wxCoord x1
= x
-VIEWPORT_EXTENT
;
597 wxCoord y1
= y
-VIEWPORT_EXTENT
;
598 wxCoord x2
= x
+VIEWPORT_EXTENT
;
599 wxCoord y2
= y
+VIEWPORT_EXTENT
;
601 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
602 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
604 CalcBoundingBox(x1
, y1
);
605 CalcBoundingBox(x2
, y2
);
608 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
612 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
614 CalcBoundingBox(x1
, y1
);
615 CalcBoundingBox(x2
, y2
);
618 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
619 // and ending at (x2, y2)
620 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
621 wxCoord x2
, wxCoord y2
,
622 wxCoord xc
, wxCoord yc
)
625 // Slower emulation since WinCE doesn't support Pie and Arc
626 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
627 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
628 if( y1
>yc
) sa
= -sa
; // below center
629 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
630 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
635 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
639 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
640 wxCoord r
= (wxCoord
)radius
;
642 // treat the special case of full circle separately
643 if ( x1
== x2
&& y1
== y2
)
645 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
649 wxCoord xx1
= XLOG2DEV(x1
);
650 wxCoord yy1
= YLOG2DEV(y1
);
651 wxCoord xx2
= XLOG2DEV(x2
);
652 wxCoord yy2
= YLOG2DEV(y2
);
653 wxCoord xxc
= XLOG2DEV(xc
);
654 wxCoord yyc
= YLOG2DEV(yc
);
655 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
657 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
658 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
659 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
660 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
662 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
664 // Have to add 1 to bottom-right corner of rectangle
665 // to make semi-circles look right (crooked line otherwise).
666 // Unfortunately this is not a reliable method, depends
667 // on the size of shape.
668 // TODO: figure out why this happens!
669 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
673 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
676 CalcBoundingBox(xc
- r
, yc
- r
);
677 CalcBoundingBox(xc
+ r
, yc
+ r
);
681 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
682 wxCoord width
, wxCoord height
)
686 wxCoord x2
= x1
+ width
,
689 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
697 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
699 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
702 // In WIN16, draw a cross
703 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
704 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
705 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
706 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
707 ::SetROP2(GetHdc(), R2_COPYPEN
);
708 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
709 MoveToEx(GetHdc(), x1
, y1
, NULL
);
710 LineTo(GetHdc(), x2
, y2
);
711 MoveToEx(GetHdc(), x2
, y1
, NULL
);
712 LineTo(GetHdc(), x1
, y2
);
713 ::SelectObject(GetHdc(), hPenOld
);
714 ::SelectObject(GetHdc(), hBrushOld
);
715 ::DeleteObject(blackPen
);
718 CalcBoundingBox(x1
, y1
);
719 CalcBoundingBox(x2
, y2
);
722 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
726 COLORREF color
= 0x00ffffff;
729 color
= m_pen
.GetColour().GetPixel();
732 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
734 CalcBoundingBox(x
, y
);
737 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
741 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
743 // Do things less efficiently if we have offsets
744 if (xoffset
!= 0 || yoffset
!= 0)
746 POINT
*cpoints
= new POINT
[n
];
748 for (i
= 0; i
< n
; i
++)
750 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
751 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
753 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
756 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
758 (void)Polygon(GetHdc(), cpoints
, n
);
760 SetPolyFillMode(GetHdc(),prev
);
767 for (i
= 0; i
< n
; i
++)
768 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
771 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
773 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
775 SetPolyFillMode(GetHdc(),prev
);
781 wxDC::DoDrawPolyPolygon(int n
,
790 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
792 for (i
= cnt
= 0; i
< n
; i
++)
795 // Do things less efficiently if we have offsets
796 if (xoffset
!= 0 || yoffset
!= 0)
798 POINT
*cpoints
= new POINT
[cnt
];
799 for (i
= 0; i
< cnt
; i
++)
801 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
802 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
804 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
806 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
807 (void)PolyPolygon(GetHdc(), cpoints
, start
, n
);
808 SetPolyFillMode(GetHdc(),prev
);
813 for (i
= 0; i
< cnt
; i
++)
814 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
816 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
817 (void)PolyPolygon(GetHdc(), (POINT
*) points
, start
, n
);
818 SetPolyFillMode(GetHdc(),prev
);
822 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
826 // Do things less efficiently if we have offsets
827 if (xoffset
!= 0 || yoffset
!= 0)
829 POINT
*cpoints
= new POINT
[n
];
831 for (i
= 0; i
< n
; i
++)
833 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
834 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
836 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
838 (void)Polyline(GetHdc(), cpoints
, n
);
844 for (i
= 0; i
< n
; i
++)
845 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
847 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
851 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
855 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
857 wxCoord x2
= x
+ width
;
858 wxCoord y2
= y
+ height
;
860 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
863 rect
.left
= XLOG2DEV(x
);
864 rect
.top
= YLOG2DEV(y
);
865 rect
.right
= XLOG2DEV(x2
);
866 rect
.bottom
= YLOG2DEV(y2
);
867 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
871 // Windows draws the filled rectangles without outline (i.e. drawn with a
872 // transparent pen) one pixel smaller in both directions and we want them
873 // to have the same size regardless of which pen is used - adjust
875 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
876 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
882 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
886 CalcBoundingBox(x
, y
);
887 CalcBoundingBox(x2
, y2
);
890 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
894 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
896 // Now, a negative radius value is interpreted to mean
897 // 'the proportion of the smallest X or Y dimension'
901 double smallest
= (width
< height
) ? width
: height
;
902 radius
= (- radius
* smallest
);
905 wxCoord x2
= (x
+width
);
906 wxCoord y2
= (y
+height
);
908 // Windows draws the filled rectangles without outline (i.e. drawn with a
909 // transparent pen) one pixel smaller in both directions and we want them
910 // to have the same size regardless of which pen is used - adjust
911 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
917 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
918 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
920 CalcBoundingBox(x
, y
);
921 CalcBoundingBox(x2
, y2
);
924 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
928 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
930 wxCoord x2
= (x
+width
);
931 wxCoord y2
= (y
+height
);
933 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
935 CalcBoundingBox(x
, y
);
936 CalcBoundingBox(x2
, y2
);
939 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
940 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
943 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
948 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
953 int rx1
= XLOG2DEV(x
+w
/2);
954 int ry1
= YLOG2DEV(y
+h
/2);
961 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
962 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
963 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
964 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
966 // draw pie with NULL_PEN first and then outline otherwise a line is
967 // drawn from the start and end points to the centre
968 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
971 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
976 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
977 rx1
, ry1
-1, rx2
, ry2
-1);
980 ::SelectObject(GetHdc(), hpenOld
);
982 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
985 CalcBoundingBox(x
, y
);
986 CalcBoundingBox(x2
, y2
);
990 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
994 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
997 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
999 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1002 CalcBoundingBox(x
, y
);
1003 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1006 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1008 WXMICROWIN_CHECK_HDC
1010 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1012 int width
= bmp
.GetWidth(),
1013 height
= bmp
.GetHeight();
1015 HBITMAP hbmpMask
= 0;
1018 HPALETTE oldPal
= 0;
1019 #endif // wxUSE_PALETTE
1021 if ( bmp
.HasAlpha() )
1024 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1026 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, hdcMem
, bmp
) )
1032 wxMask
*mask
= bmp
.GetMask();
1034 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1038 // don't give assert here because this would break existing
1039 // programs - just silently ignore useMask parameter
1046 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1048 // On some systems, MaskBlt succeeds yet is much much slower
1049 // than the wxWindows fall-back implementation. So we need
1050 // to be able to switch this on and off at runtime.
1052 #if wxUSE_SYSTEM_OPTIONS
1053 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1057 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1058 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1060 wxPalette
*pal
= bmp
.GetPalette();
1061 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1063 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1064 ::RealizePalette(hdcMem
);
1066 #endif // wxUSE_PALETTE
1068 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1071 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1075 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1076 #endif // wxUSE_PALETTE
1078 ::SelectObject(hdcMem
, hOldBitmap
);
1085 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1088 memDC
.SelectObject(bmp
);
1090 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1092 memDC
.SelectObject(wxNullBitmap
);
1095 else // no mask, just use BitBlt()
1098 HDC memdc
= ::CreateCompatibleDC( cdc
);
1099 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1101 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1103 COLORREF old_textground
= ::GetTextColor(GetHdc());
1104 COLORREF old_background
= ::GetBkColor(GetHdc());
1105 if (m_textForegroundColour
.Ok())
1107 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1109 if (m_textBackgroundColour
.Ok())
1111 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1115 wxPalette
*pal
= bmp
.GetPalette();
1116 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1118 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1119 ::RealizePalette(memdc
);
1121 #endif // wxUSE_PALETTE
1123 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1124 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1128 ::SelectPalette(memdc
, oldPal
, FALSE
);
1129 #endif // wxUSE_PALETTE
1131 ::SelectObject( memdc
, hOldBitmap
);
1132 ::DeleteDC( memdc
);
1134 ::SetTextColor(GetHdc(), old_textground
);
1135 ::SetBkColor(GetHdc(), old_background
);
1139 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1141 WXMICROWIN_CHECK_HDC
1143 DrawAnyText(text
, x
, y
);
1145 // update the bounding box
1146 CalcBoundingBox(x
, y
);
1149 GetTextExtent(text
, &w
, &h
);
1150 CalcBoundingBox(x
+ w
, y
+ h
);
1153 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1155 WXMICROWIN_CHECK_HDC
1157 // prepare for drawing the text
1158 if ( m_textForegroundColour
.Ok() )
1159 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1161 DWORD old_background
= 0;
1162 if ( m_textBackgroundColour
.Ok() )
1164 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1167 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1171 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1172 text
.c_str(), text
.length(), NULL
) == 0 )
1174 wxLogLastError(wxT("TextOut"));
1177 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1178 text
.c_str(), text
.length()) == 0 )
1180 wxLogLastError(wxT("TextOut"));
1184 // restore the old parameters (text foreground colour may be left because
1185 // it never is set to anything else, but background should remain
1186 // transparent even if we just drew an opaque string)
1187 if ( m_textBackgroundColour
.Ok() )
1188 (void)SetBkColor(GetHdc(), old_background
);
1190 SetBkMode(GetHdc(), TRANSPARENT
);
1193 void wxDC::DoDrawRotatedText(const wxString
& text
,
1194 wxCoord x
, wxCoord y
,
1197 WXMICROWIN_CHECK_HDC
1199 // we test that we have some font because otherwise we should still use the
1200 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1201 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1202 // font for drawing rotated fonts unfortunately)
1203 if ( (angle
== 0.0) && m_font
.Ok() )
1205 DoDrawText(text
, x
, y
);
1207 #ifndef __WXMICROWIN__
1210 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1211 // because it's not TrueType and so can't have non zero
1212 // orientation/escapement under Win9x
1213 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1214 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1216 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1218 wxLogLastError(wxT("GetObject(hfont)"));
1221 // GDI wants the angle in tenth of degree
1222 long angle10
= (long)(angle
* 10);
1223 lf
.lfEscapement
= angle10
;
1224 lf
. lfOrientation
= angle10
;
1226 hfont
= ::CreateFontIndirect(&lf
);
1229 wxLogLastError(wxT("CreateFont"));
1233 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1235 DrawAnyText(text
, x
, y
);
1237 (void)::SelectObject(GetHdc(), hfontOld
);
1238 (void)::DeleteObject(hfont
);
1241 // call the bounding box by adding all four vertices of the rectangle
1242 // containing the text to it (simpler and probably not slower than
1243 // determining which of them is really topmost/leftmost/...)
1245 GetTextExtent(text
, &w
, &h
);
1247 double rad
= DegToRad(angle
);
1249 // "upper left" and "upper right"
1250 CalcBoundingBox(x
, y
);
1251 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(h
*sin(rad
)));
1253 // "bottom left" and "bottom right"
1254 x
+= (wxCoord
)(h
*sin(rad
));
1255 y
+= (wxCoord
)(h
*cos(rad
));
1256 CalcBoundingBox(x
, y
);
1257 CalcBoundingBox(x
+ wxCoord(h
*sin(rad
)), y
+ wxCoord(h
*cos(rad
)));
1262 // ---------------------------------------------------------------------------
1264 // ---------------------------------------------------------------------------
1268 void wxDC::DoSelectPalette(bool realize
)
1270 WXMICROWIN_CHECK_HDC
1272 // Set the old object temporarily, in case the assignment deletes an object
1273 // that's not yet selected out.
1276 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1280 if ( m_palette
.Ok() )
1282 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1283 GetHpaletteOf(m_palette
),
1286 m_oldPalette
= (WXHPALETTE
) oldPal
;
1289 ::RealizePalette(GetHdc());
1293 void wxDC::SetPalette(const wxPalette
& palette
)
1297 m_palette
= palette
;
1298 DoSelectPalette(true);
1302 void wxDC::InitializePalette()
1304 if ( wxDisplayDepth() <= 8 )
1306 // look for any window or parent that has a custom palette. If any has
1307 // one then we need to use it in drawing operations
1308 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1310 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1311 if ( m_hasCustomPalette
)
1313 m_palette
= win
->GetPalette();
1315 // turn on MSW translation for this palette
1321 #endif // wxUSE_PALETTE
1323 // SetFont/Pen/Brush() really ask to be implemented as a single template
1324 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1326 void wxDC::SetFont(const wxFont
& font
)
1328 WXMICROWIN_CHECK_HDC
1330 if ( font
== m_font
)
1335 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1336 if ( hfont
== HGDI_ERROR
)
1338 wxLogLastError(_T("SelectObject(font)"));
1343 m_oldFont
= (WXHPEN
)hfont
;
1348 else // invalid font, reset the current font
1352 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1354 wxLogLastError(_T("SelectObject(old font)"));
1360 m_font
= wxNullFont
;
1364 void wxDC::SetPen(const wxPen
& pen
)
1366 WXMICROWIN_CHECK_HDC
1373 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1374 if ( hpen
== HGDI_ERROR
)
1376 wxLogLastError(_T("SelectObject(pen)"));
1381 m_oldPen
= (WXHPEN
)hpen
;
1386 else // invalid pen, reset the current pen
1390 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1392 wxLogLastError(_T("SelectObject(old pen)"));
1402 void wxDC::SetBrush(const wxBrush
& brush
)
1404 WXMICROWIN_CHECK_HDC
1406 if ( brush
== m_brush
)
1411 // we must make sure the brush is aligned with the logical coordinates
1412 // before selecting it
1413 wxBitmap
*stipple
= brush
.GetStipple();
1414 if ( stipple
&& stipple
->Ok() )
1416 if ( !::SetBrushOrgEx
1419 m_deviceOriginX
% stipple
->GetWidth(),
1420 m_deviceOriginY
% stipple
->GetHeight(),
1421 NULL
// [out] previous brush origin
1424 wxLogLastError(_T("SetBrushOrgEx()"));
1428 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1429 if ( hbrush
== HGDI_ERROR
)
1431 wxLogLastError(_T("SelectObject(brush)"));
1436 m_oldBrush
= (WXHPEN
)hbrush
;
1441 else // invalid brush, reset the current brush
1445 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1447 wxLogLastError(_T("SelectObject(old brush)"));
1453 m_brush
= wxNullBrush
;
1457 void wxDC::SetBackground(const wxBrush
& brush
)
1459 WXMICROWIN_CHECK_HDC
1461 m_backgroundBrush
= brush
;
1463 if ( m_backgroundBrush
.Ok() )
1465 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1469 void wxDC::SetBackgroundMode(int mode
)
1471 WXMICROWIN_CHECK_HDC
1473 m_backgroundMode
= mode
;
1475 // SetBackgroundColour now only refers to text background
1476 // and m_backgroundMode is used there
1479 void wxDC::SetLogicalFunction(int function
)
1481 WXMICROWIN_CHECK_HDC
1483 m_logicalFunction
= function
;
1488 void wxDC::SetRop(WXHDC dc
)
1490 if ( !dc
|| m_logicalFunction
< 0 )
1495 switch (m_logicalFunction
)
1497 case wxCLEAR
: rop
= R2_BLACK
; break;
1498 case wxXOR
: rop
= R2_XORPEN
; break;
1499 case wxINVERT
: rop
= R2_NOT
; break;
1500 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1501 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1502 case wxCOPY
: rop
= R2_COPYPEN
; break;
1503 case wxAND
: rop
= R2_MASKPEN
; break;
1504 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1505 case wxNO_OP
: rop
= R2_NOP
; break;
1506 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1507 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1508 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1509 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1510 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1511 case wxOR
: rop
= R2_MERGEPEN
; break;
1512 case wxSET
: rop
= R2_WHITE
; break;
1515 wxFAIL_MSG( wxT("unsupported logical function") );
1519 SetROP2(GetHdc(), rop
);
1522 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1524 // We might be previewing, so return true to let it continue.
1532 void wxDC::StartPage()
1536 void wxDC::EndPage()
1540 // ---------------------------------------------------------------------------
1542 // ---------------------------------------------------------------------------
1544 wxCoord
wxDC::GetCharHeight() const
1546 WXMICROWIN_CHECK_HDC_RET(0)
1548 TEXTMETRIC lpTextMetric
;
1550 GetTextMetrics(GetHdc(), &lpTextMetric
);
1552 return lpTextMetric
.tmHeight
;
1555 wxCoord
wxDC::GetCharWidth() const
1557 WXMICROWIN_CHECK_HDC_RET(0)
1559 TEXTMETRIC lpTextMetric
;
1561 GetTextMetrics(GetHdc(), &lpTextMetric
);
1563 return lpTextMetric
.tmAveCharWidth
;
1566 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1567 wxCoord
*descent
, wxCoord
*externalLeading
,
1570 #ifdef __WXMICROWIN__
1575 if (descent
) *descent
= 0;
1576 if (externalLeading
) *externalLeading
= 0;
1579 #endif // __WXMICROWIN__
1584 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1586 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1588 else // don't change the font
1596 GetTextExtentPoint(GetHdc(), string
, string
.length(), &sizeRect
);
1597 GetTextMetrics(GetHdc(), &tm
);
1604 *descent
= tm
.tmDescent
;
1605 if (externalLeading
)
1606 *externalLeading
= tm
.tmExternalLeading
;
1610 ::SelectObject(GetHdc(), hfontOld
);
1615 // Each element of the array will be the width of the string up to and
1616 // including the coresoponding character in text.
1618 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1620 static int maxLenText
= -1;
1621 static int maxWidth
= -1;
1624 int stlen
= text
.Length();
1626 if (maxLenText
== -1)
1628 // Win9x and WinNT+ have different limits
1629 int version
= wxGetOsVersion();
1630 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1631 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1635 widths
.Add(0, stlen
); // fill the array with zeros
1637 if (!::GetTextExtentExPoint(GetHdc(),
1638 text
.c_str(), // string to check
1639 wxMin(stlen
, maxLenText
),
1641 &fit
, // [out] count of chars
1643 &widths
[0], // array to fill
1647 wxLogLastError(wxT("GetTextExtentExPoint"));
1657 void wxDC::SetMapMode(int mode
)
1659 WXMICROWIN_CHECK_HDC
1661 m_mappingMode
= mode
;
1663 if ( mode
== wxMM_TEXT
)
1666 m_logicalScaleY
= 1.0;
1668 else // need to do some calculations
1670 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1671 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1672 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1673 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1675 if ( (mm_width
== 0) || (mm_height
== 0) )
1677 // we can't calculate mm2pixels[XY] then!
1681 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1682 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1687 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1688 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1692 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1693 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1697 m_logicalScaleX
= mm2pixelsX
;
1698 m_logicalScaleY
= mm2pixelsY
;
1702 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1703 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1707 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1711 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1712 // cases we could do with MM_TEXT and in the remaining 0.9% with
1713 // MM_ISOTROPIC (TODO!)
1715 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1717 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1718 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1720 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1721 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1723 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1724 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1728 void wxDC::SetUserScale(double x
, double y
)
1730 WXMICROWIN_CHECK_HDC
1733 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1739 SetMapMode(m_mappingMode
);
1743 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1745 WXMICROWIN_CHECK_HDC
1748 int signX
= xLeftRight
? 1 : -1,
1749 signY
= yBottomUp
? -1 : 1;
1751 if ( signX
!= m_signX
|| signY
!= m_signY
)
1756 SetMapMode(m_mappingMode
);
1761 void wxDC::SetSystemScale(double x
, double y
)
1763 WXMICROWIN_CHECK_HDC
1766 if ( x
== m_scaleX
&& y
== m_scaleY
)
1772 SetMapMode(m_mappingMode
);
1776 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1778 WXMICROWIN_CHECK_HDC
1781 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1784 m_logicalOriginX
= x
;
1785 m_logicalOriginY
= y
;
1787 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1791 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1793 WXMICROWIN_CHECK_HDC
1796 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1799 m_deviceOriginX
= x
;
1800 m_deviceOriginY
= y
;
1802 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1806 // ---------------------------------------------------------------------------
1807 // coordinates transformations
1808 // ---------------------------------------------------------------------------
1810 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1812 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1815 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1817 // axis orientation is not taken into account for conversion of a distance
1818 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1821 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1823 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1826 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1828 // axis orientation is not taken into account for conversion of a distance
1829 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1832 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1834 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1837 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1839 // axis orientation is not taken into account for conversion of a distance
1840 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1843 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1845 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1848 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1850 // axis orientation is not taken into account for conversion of a distance
1851 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1854 // ---------------------------------------------------------------------------
1856 // ---------------------------------------------------------------------------
1858 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1859 wxCoord width
, wxCoord height
,
1860 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1861 int rop
, bool useMask
,
1862 wxCoord xsrcMask
, wxCoord ysrcMask
)
1864 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1866 WXMICROWIN_CHECK_HDC_RET(false)
1868 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1869 if ( bmpSrc
.Ok() && bmpSrc
.HasAlpha() )
1871 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1872 GetHdcOf(*source
), bmpSrc
) )
1876 wxMask
*mask
= NULL
;
1879 mask
= bmpSrc
.GetMask();
1881 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1883 // don't give assert here because this would break existing
1884 // programs - just silently ignore useMask parameter
1889 if (xsrcMask
== -1 && ysrcMask
== -1)
1891 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1894 COLORREF old_textground
= ::GetTextColor(GetHdc());
1895 COLORREF old_background
= ::GetBkColor(GetHdc());
1896 if (m_textForegroundColour
.Ok())
1898 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1900 if (m_textBackgroundColour
.Ok())
1902 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1908 case wxXOR
: dwRop
= SRCINVERT
; break;
1909 case wxINVERT
: dwRop
= DSTINVERT
; break;
1910 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1911 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1912 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1913 case wxSET
: dwRop
= WHITENESS
; break;
1914 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1915 case wxAND
: dwRop
= SRCAND
; break;
1916 case wxOR
: dwRop
= SRCPAINT
; break;
1917 case wxEQUIV
: dwRop
= 0x00990066; break;
1918 case wxNAND
: dwRop
= 0x007700E6; break;
1919 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1920 case wxCOPY
: dwRop
= SRCCOPY
; break;
1921 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1922 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1923 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1925 wxFAIL_MSG( wxT("unsupported logical function") );
1929 bool success
= false;
1934 // we want the part of the image corresponding to the mask to be
1935 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1936 // meaning of fg and bg is inverted which corresponds to wxWin notion
1937 // of the mask which is also contrary to the Windows one)
1939 // On some systems, MaskBlt succeeds yet is much much slower
1940 // than the wxWindows fall-back implementation. So we need
1941 // to be able to switch this on and off at runtime.
1942 #if wxUSE_SYSTEM_OPTIONS
1943 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1949 xdest
, ydest
, width
, height
,
1952 (HBITMAP
)mask
->GetMaskBitmap(),
1954 MAKEROP4(dwRop
, DSTCOPY
)
1961 // Blit bitmap with mask
1964 HBITMAP buffer_bmap
;
1966 #if wxUSE_DC_CACHEING
1967 // create a temp buffer bitmap and DCs to access it and the mask
1968 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
1969 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
1971 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
1972 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
1974 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
1977 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
1978 #else // !wxUSE_DC_CACHEING
1979 // create a temp buffer bitmap and DCs to access it and the mask
1980 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1981 dc_buffer
= ::CreateCompatibleDC(GetHdc());
1982 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1983 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
1984 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1985 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
1987 // copy dest to buffer
1988 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1989 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1991 wxLogLastError(wxT("BitBlt"));
1994 // copy src to buffer using selected raster op
1995 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1996 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1998 wxLogLastError(wxT("BitBlt"));
2001 // set masked area in buffer to BLACK (pixel value 0)
2002 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2003 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2004 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2005 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2007 wxLogLastError(wxT("BitBlt"));
2010 // set unmasked area in dest to BLACK
2011 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2012 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2013 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2014 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2016 wxLogLastError(wxT("BitBlt"));
2018 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2019 ::SetTextColor(GetHdc(), prevCol
);
2021 // OR buffer to dest
2022 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2023 (int)width
, (int)height
,
2024 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2027 wxLogLastError(wxT("BitBlt"));
2030 // tidy up temporary DCs and bitmap
2031 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2032 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2034 #if !wxUSE_DC_CACHEING
2036 ::DeleteDC(dc_mask
);
2037 ::DeleteDC(dc_buffer
);
2038 ::DeleteObject(buffer_bmap
);
2043 else // no mask, just BitBlt() it
2045 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2046 // use StretchBlt() if available and finally fall back to BitBlt()
2048 // FIXME: use appropriate WinCE functions
2050 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2051 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2056 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2058 &ds
) == sizeof(ds
) )
2060 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2062 // Figure out what co-ordinate system we're supposed to specify
2064 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2068 ysrc
= hDIB
- (ysrc
+ height
);
2071 if ( ::StretchDIBits(GetHdc(),
2077 (LPBITMAPINFO
)&ds
.dsBmih
,
2080 ) == (int)GDI_ERROR
)
2082 wxLogLastError(wxT("StretchDIBits"));
2091 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2096 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2102 xdest
, ydest
, width
, height
,
2104 xsrc
, ysrc
, width
, height
,
2108 wxLogLastError(_T("StretchBlt"));
2122 (int)width
, (int)height
,
2128 wxLogLastError(_T("BitBlt"));
2137 ::SetTextColor(GetHdc(), old_textground
);
2138 ::SetBkColor(GetHdc(), old_background
);
2143 void wxDC::DoGetSize(int *w
, int *h
) const
2145 WXMICROWIN_CHECK_HDC
2147 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2148 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2151 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2153 WXMICROWIN_CHECK_HDC
2155 // if we implement it in terms of DoGetSize() instead of directly using the
2156 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2157 // will also work for wxWindowDC and wxClientDC even though their size is
2158 // not the same as the total size of the screen
2159 int wPixels
, hPixels
;
2160 DoGetSize(&wPixels
, &hPixels
);
2164 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2166 wxCHECK_RET( wTotal
, _T("0 width device?") );
2168 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2173 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2175 wxCHECK_RET( hTotal
, _T("0 height device?") );
2177 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2181 wxSize
wxDC::GetPPI() const
2183 WXMICROWIN_CHECK_HDC_RET(wxSize())
2185 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2186 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2188 return wxSize(x
, y
);
2191 // For use by wxWindows only, unless custom units are required.
2192 void wxDC::SetLogicalScale(double x
, double y
)
2194 WXMICROWIN_CHECK_HDC
2196 m_logicalScaleX
= x
;
2197 m_logicalScaleY
= y
;
2200 // ----------------------------------------------------------------------------
2202 // ----------------------------------------------------------------------------
2204 #if wxUSE_DC_CACHEING
2207 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2208 * improve it in due course, either using arrays, or simply storing pointers to one
2209 * entry for the bitmap, and two for the DCs. -- JACS
2212 wxList
wxDC::sm_bitmapCache
;
2213 wxList
wxDC::sm_dcCache
;
2215 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2224 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2233 wxDCCacheEntry::~wxDCCacheEntry()
2236 ::DeleteObject((HBITMAP
) m_bitmap
);
2238 ::DeleteDC((HDC
) m_dc
);
2241 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2243 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2244 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2247 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2249 if (entry
->m_depth
== depth
)
2251 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2253 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2254 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2255 if ( !entry
->m_bitmap
)
2257 wxLogLastError(wxT("CreateCompatibleBitmap"));
2259 entry
->m_width
= w
; entry
->m_height
= h
;
2265 node
= node
->GetNext();
2267 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2270 wxLogLastError(wxT("CreateCompatibleBitmap"));
2272 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2273 AddToBitmapCache(entry
);
2277 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2279 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2280 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2283 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2285 // Don't return the same one as we already have
2286 if (!notThis
|| (notThis
!= entry
))
2288 if (entry
->m_depth
== depth
)
2294 node
= node
->GetNext();
2296 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2299 wxLogLastError(wxT("CreateCompatibleDC"));
2301 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2302 AddToDCCache(entry
);
2306 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2308 sm_bitmapCache
.Append(entry
);
2311 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2313 sm_dcCache
.Append(entry
);
2316 void wxDC::ClearCache()
2318 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2319 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2322 // Clean up cache at app exit
2323 class wxDCModule
: public wxModule
2326 virtual bool OnInit() { return true; }
2327 virtual void OnExit() { wxDC::ClearCache(); }
2330 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2333 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2335 #endif // wxUSE_DC_CACHEING
2337 // ----------------------------------------------------------------------------
2338 // alpha channel support
2339 // ----------------------------------------------------------------------------
2341 static bool AlphaBlt(HDC hdcDst
,
2342 int x
, int y
, int width
, int height
,
2344 const wxBitmap
& bmp
)
2346 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2347 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2349 // do we have AlphaBlend() and company in the headers?
2350 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2351 // yes, now try to see if we have it during run-time
2352 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2353 HDC
,int,int,int,int,
2356 // bitmaps can be drawn only from GUI thread so there is no need to
2357 // protect this static variable from multiple threads
2358 static bool s_triedToLoad
= false;
2359 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2360 if ( !s_triedToLoad
)
2362 s_triedToLoad
= true;
2364 // don't give errors about the DLL being unavailable, we're
2365 // prepared to handle this
2368 wxDynamicLibrary
dll(_T("msimg32.dll"));
2369 if ( dll
.IsLoaded() )
2371 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2372 if ( pfnAlphaBlend
)
2374 // we must keep the DLL loaded if we want to be able to
2375 // call AlphaBlend() so just never unload it at all, not a
2382 if ( pfnAlphaBlend
)
2385 bf
.BlendOp
= AC_SRC_OVER
;
2387 bf
.SourceConstantAlpha
= 0xff;
2388 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2390 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2391 hdcSrc
, 0, 0, width
, height
,
2394 // skip wxAlphaBlend() call below
2398 wxLogLastError(_T("AlphaBlend"));
2400 #endif // defined(AC_SRC_OVER)
2402 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2404 #ifdef wxHAVE_RAW_BITMAP
2405 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, bmp
);
2408 #else // !wxHAVE_RAW_BITMAP
2409 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2410 // alpha but at least something will be shown like this)
2412 #endif // wxHAVE_RAW_BITMAP
2416 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2417 #ifdef wxHAVE_RAW_BITMAP
2420 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, const wxBitmap
& bmpSrc
)
2422 // get the destination DC pixels
2423 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2425 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2427 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2429 wxLogLastError(_T("BitBlt"));
2432 // combine them with the source bitmap using alpha
2433 wxAlphaPixelData
dataDst(bmpDst
),
2434 dataSrc((wxBitmap
&)bmpSrc
);
2436 wxCHECK_RET( dataDst
&& dataSrc
,
2437 _T("failed to get raw data in wxAlphaBlend") );
2439 wxAlphaPixelData::Iterator
pDst(dataDst
),
2442 for ( int y
= 0; y
< h
; y
++ )
2444 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2445 pSrcRowStart
= pSrc
;
2447 for ( int x
= 0; x
< w
; x
++ )
2449 // note that source bitmap uses premultiplied alpha (as required by
2450 // the real AlphaBlend)
2451 const unsigned beta
= 255 - pSrc
.Alpha();
2453 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2454 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2455 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2461 pDst
= pDstRowStart
;
2462 pSrc
= pSrcRowStart
;
2463 pDst
.OffsetY(dataDst
, 1);
2464 pSrc
.OffsetY(dataSrc
, 1);
2467 // and finally blit them back to the destination DC
2468 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2470 wxLogLastError(_T("BitBlt"));
2474 #endif // #ifdef wxHAVE_RAW_BITMAP