1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/sysopt.h"
45 #include "wx/dcprint.h"
46 #include "wx/module.h"
47 #include "wx/dynload.h"
49 #ifdef wxHAVE_RAW_BITMAP
50 #include "wx/rawbmp.h"
55 #include "wx/msw/wrapcdlg.h"
61 #define AC_SRC_ALPHA 1
64 /* Quaternary raster codes */
66 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
69 // apparently with MicroWindows it is possible that HDC is 0 so we have to
70 // check for this ourselves
72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
75 #define WXMICROWIN_CHECK_HDC
76 #define WXMICROWIN_CHECK_HDC_RET(x)
79 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 static const int MM_POINTS
= 9;
88 static const int MM_METRIC
= 10;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
107 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
108 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
109 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
111 #define XLOG2DEV(x) (x)
112 #define YLOG2DEV(y) (y)
113 #define XDEV2LOG(x) (x)
114 #define YDEV2LOG(y) (y)
117 // ---------------------------------------------------------------------------
119 // ---------------------------------------------------------------------------
121 // convert degrees to radians
122 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
124 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
126 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
127 // to pass it to this function but as we already have it at the point
128 // of call anyhow we do
130 // return true if we could draw the bitmap in one way or the other, false
132 static bool AlphaBlt(HDC hdcDst
,
133 int x
, int y
, int w
, int h
,
134 int srcX
, int srcY
, HDC hdcSrc
,
135 const wxBitmap
& bmpSrc
);
137 #ifdef wxHAVE_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement
140 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmp
);
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
147 // instead of duplicating the same code which sets and then restores text
148 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
149 // encapsulate this in a small helper class
151 // wxColourChanger: changes the text colours in the ctor if required and
152 // restores them in the dtor
153 class wxColourChanger
156 wxColourChanger(wxDC
& dc
);
162 COLORREF m_colFgOld
, m_colBgOld
;
166 DECLARE_NO_COPY_CLASS(wxColourChanger
)
169 // this class saves the old stretch blit mode during its life time
170 class StretchBltModeChanger
173 StretchBltModeChanger(HDC hdc
,
174 int WXUNUSED_IN_WINCE(mode
))
178 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
180 wxLogLastError(_T("SetStretchBltMode"));
184 ~StretchBltModeChanger()
187 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
188 wxLogLastError(_T("SetStretchBltMode"));
197 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
200 // ===========================================================================
202 // ===========================================================================
204 // ----------------------------------------------------------------------------
206 // ----------------------------------------------------------------------------
208 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
210 const wxBrush
& brush
= dc
.GetBrush();
211 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
213 HDC hdc
= GetHdcOf(dc
);
214 m_colFgOld
= ::GetTextColor(hdc
);
215 m_colBgOld
= ::GetBkColor(hdc
);
217 // note that Windows convention is opposite to wxWidgets one, this is
218 // why text colour becomes the background one and vice versa
219 const wxColour
& colFg
= dc
.GetTextForeground();
222 ::SetBkColor(hdc
, colFg
.GetPixel());
225 const wxColour
& colBg
= dc
.GetTextBackground();
228 ::SetTextColor(hdc
, colBg
.GetPixel());
232 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
235 // flag which telsl us to undo changes in the dtor
240 // nothing done, nothing to undo
245 wxColourChanger::~wxColourChanger()
249 // restore the colours we changed
250 HDC hdc
= GetHdcOf(m_dc
);
252 ::SetBkMode(hdc
, TRANSPARENT
);
253 ::SetTextColor(hdc
, m_colFgOld
);
254 ::SetBkColor(hdc
, m_colBgOld
);
258 // ---------------------------------------------------------------------------
260 // ---------------------------------------------------------------------------
262 // Default constructor
273 #endif // wxUSE_PALETTE
283 SelectOldObjects(m_hDC
);
285 // if we own the HDC, we delete it, otherwise we just release it
289 ::DeleteDC(GetHdc());
291 else // we don't own our HDC
295 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
299 // Must have been a wxScreenDC
300 ::ReleaseDC((HWND
) NULL
, GetHdc());
306 // This will select current objects out of the DC,
307 // which is what you have to do before deleting the
309 void wxDC::SelectOldObjects(WXHDC dc
)
315 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
317 if (m_selectedBitmap
.Ok())
319 m_selectedBitmap
.SetSelectedInto(NULL
);
326 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
331 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
336 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
343 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
346 #endif // wxUSE_PALETTE
349 m_brush
= wxNullBrush
;
352 m_palette
= wxNullPalette
;
353 #endif // wxUSE_PALETTE
355 m_backgroundBrush
= wxNullBrush
;
356 m_selectedBitmap
= wxNullBitmap
;
359 // ---------------------------------------------------------------------------
361 // ---------------------------------------------------------------------------
363 void wxDC::UpdateClipBox()
368 ::GetClipBox(GetHdc(), &rect
);
370 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
371 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
372 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
373 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
377 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
379 // check if we should try to retrieve the clipping region possibly not set
380 // by our SetClippingRegion() but preset by Windows:this can only happen
381 // when we're associated with an existing HDC usign SetHDC(), see there
382 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
384 wxDC
*self
= wxConstCast(this, wxDC
);
385 self
->UpdateClipBox();
387 if ( !m_clipX1
&& !m_clipX2
)
388 self
->m_clipping
= false;
391 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
394 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
395 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
397 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
401 // note that we combine the new clipping region with the existing one: this
402 // is compatible with what the other ports do and is the documented
403 // behaviour now (starting with 2.3.3)
404 #if defined(__WXWINCE__)
406 if ( !::GetClipBox(GetHdc(), &rectClip
) )
409 // GetClipBox returns logical coordinates, so transform to device
410 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
411 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
412 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
413 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
415 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
416 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
417 rectClip
.right
, rectClip
.bottom
);
419 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
421 ::SelectClipRgn(GetHdc(), hrgnDest
);
424 ::DeleteObject(hrgnClipOld
);
425 ::DeleteObject(hrgnDest
);
427 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
429 wxLogLastError(_T("ExtSelectClipRgn"));
433 #endif // WinCE/!WinCE
440 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
442 // the region coords are always the device ones, so do the translation
445 // FIXME: possible +/-1 error here, to check!
446 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
448 LogicalToDeviceX(x
+ w
),
449 LogicalToDeviceY(y
+ h
));
452 wxLogLastError(_T("CreateRectRgn"));
456 SetClippingHrgn((WXHRGN
)hrgn
);
458 ::DeleteObject(hrgn
);
462 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
464 SetClippingHrgn(region
.GetHRGN());
467 void wxDC::DestroyClippingRegion()
471 if (m_clipping
&& m_hDC
)
473 // TODO: this should restore the previous clipping region,
474 // so that OnPaint processing works correctly, and the update
475 // clipping region doesn't get destroyed after the first
476 // DestroyClippingRegion.
477 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
478 ::SelectClipRgn(GetHdc(), rgn
);
482 wxDCBase::DestroyClippingRegion();
485 // ---------------------------------------------------------------------------
486 // query capabilities
487 // ---------------------------------------------------------------------------
489 bool wxDC::CanDrawBitmap() const
494 bool wxDC::CanGetTextExtent() const
496 #ifdef __WXMICROWIN__
497 // TODO Extend MicroWindows' GetDeviceCaps function
500 // What sort of display is it?
501 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
503 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
507 int wxDC::GetDepth() const
509 WXMICROWIN_CHECK_HDC_RET(16)
511 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
514 // ---------------------------------------------------------------------------
516 // ---------------------------------------------------------------------------
525 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
529 // No, I think we should simply ignore this if printing on e.g.
531 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
532 if (!m_selectedBitmap
.Ok())
535 rect
.left
= 0; rect
.top
= 0;
536 rect
.right
= m_selectedBitmap
.GetWidth();
537 rect
.bottom
= m_selectedBitmap
.GetHeight();
541 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
544 DWORD colour
= ::GetBkColor(GetHdc());
545 HBRUSH brush
= ::CreateSolidBrush(colour
);
546 ::FillRect(GetHdc(), &rect
, brush
);
547 ::DeleteObject(brush
);
550 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
551 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
553 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
555 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
556 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
557 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
558 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
562 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
563 wxCoord
WXUNUSED_IN_WINCE(y
),
564 const wxColour
& WXUNUSED_IN_WINCE(col
),
565 int WXUNUSED_IN_WINCE(style
))
570 WXMICROWIN_CHECK_HDC_RET(false)
572 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
574 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
575 : FLOODFILLBORDER
) ) ;
578 // quoting from the MSDN docs:
580 // Following are some of the reasons this function might fail:
582 // * The filling could not be completed.
583 // * The specified point has the boundary color specified by the
584 // crColor parameter (if FLOODFILLBORDER was requested).
585 // * The specified point does not have the color specified by
586 // crColor (if FLOODFILLSURFACE was requested)
587 // * The point is outside the clipping region that is, it is not
588 // visible on the device.
590 wxLogLastError(wxT("ExtFloodFill"));
593 CalcBoundingBox(x
, y
);
599 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
601 WXMICROWIN_CHECK_HDC_RET(false)
603 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
605 // get the color of the pixel
606 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
608 wxRGBToColour(*col
, pixelcolor
);
613 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
617 wxCoord x1
= x
-VIEWPORT_EXTENT
;
618 wxCoord y1
= y
-VIEWPORT_EXTENT
;
619 wxCoord x2
= x
+VIEWPORT_EXTENT
;
620 wxCoord y2
= y
+VIEWPORT_EXTENT
;
622 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
623 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
625 CalcBoundingBox(x1
, y1
);
626 CalcBoundingBox(x2
, y2
);
629 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
633 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
635 CalcBoundingBox(x1
, y1
);
636 CalcBoundingBox(x2
, y2
);
639 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
640 // and ending at (x2, y2)
641 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
642 wxCoord x2
, wxCoord y2
,
643 wxCoord xc
, wxCoord yc
)
646 // Slower emulation since WinCE doesn't support Pie and Arc
647 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
648 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
649 if( y1
>yc
) sa
= -sa
; // below center
650 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
651 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
656 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
660 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
661 wxCoord r
= (wxCoord
)radius
;
663 // treat the special case of full circle separately
664 if ( x1
== x2
&& y1
== y2
)
666 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
670 wxCoord xx1
= XLOG2DEV(x1
);
671 wxCoord yy1
= YLOG2DEV(y1
);
672 wxCoord xx2
= XLOG2DEV(x2
);
673 wxCoord yy2
= YLOG2DEV(y2
);
674 wxCoord xxc
= XLOG2DEV(xc
);
675 wxCoord yyc
= YLOG2DEV(yc
);
676 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
678 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
679 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
680 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
681 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
683 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
685 // Have to add 1 to bottom-right corner of rectangle
686 // to make semi-circles look right (crooked line otherwise).
687 // Unfortunately this is not a reliable method, depends
688 // on the size of shape.
689 // TODO: figure out why this happens!
690 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
694 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
697 CalcBoundingBox(xc
- r
, yc
- r
);
698 CalcBoundingBox(xc
+ r
, yc
+ r
);
702 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
703 wxCoord width
, wxCoord height
)
707 wxCoord x2
= x1
+ width
,
710 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
718 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
720 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
722 #else // Symantec-MicroWin
724 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
725 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
726 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
727 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
728 ::SetROP2(GetHdc(), R2_COPYPEN
);
729 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
730 MoveToEx(GetHdc(), x1
, y1
, NULL
);
731 LineTo(GetHdc(), x2
, y2
);
732 MoveToEx(GetHdc(), x2
, y1
, NULL
);
733 LineTo(GetHdc(), x1
, y2
);
734 ::SelectObject(GetHdc(), hPenOld
);
735 ::SelectObject(GetHdc(), hBrushOld
);
736 ::DeleteObject(blackPen
);
737 #endif // Win32/Symantec-MicroWin
739 CalcBoundingBox(x1
, y1
);
740 CalcBoundingBox(x2
, y2
);
743 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
747 COLORREF color
= 0x00ffffff;
750 color
= m_pen
.GetColour().GetPixel();
753 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
755 CalcBoundingBox(x
, y
);
758 void wxDC::DoDrawPolygon(int n
,
762 int WXUNUSED_IN_WINCE(fillStyle
))
766 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
768 // Do things less efficiently if we have offsets
769 if (xoffset
!= 0 || yoffset
!= 0)
771 POINT
*cpoints
= new POINT
[n
];
773 for (i
= 0; i
< n
; i
++)
775 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
776 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
778 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
781 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
783 (void)Polygon(GetHdc(), cpoints
, n
);
785 SetPolyFillMode(GetHdc(),prev
);
792 for (i
= 0; i
< n
; i
++)
793 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
796 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
798 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
800 SetPolyFillMode(GetHdc(),prev
);
806 wxDC::DoDrawPolyPolygon(int n
,
814 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
818 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
820 for (i
= cnt
= 0; i
< n
; i
++)
823 // Do things less efficiently if we have offsets
824 if (xoffset
!= 0 || yoffset
!= 0)
826 POINT
*cpoints
= new POINT
[cnt
];
827 for (i
= 0; i
< cnt
; i
++)
829 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
830 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
832 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
835 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
837 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
839 SetPolyFillMode(GetHdc(),prev
);
845 for (i
= 0; i
< cnt
; i
++)
846 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
849 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
851 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
853 SetPolyFillMode(GetHdc(),prev
);
860 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
864 // Do things less efficiently if we have offsets
865 if (xoffset
!= 0 || yoffset
!= 0)
867 POINT
*cpoints
= new POINT
[n
];
869 for (i
= 0; i
< n
; i
++)
871 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
872 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
874 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
876 (void)Polyline(GetHdc(), cpoints
, n
);
882 for (i
= 0; i
< n
; i
++)
883 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
885 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
889 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
893 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
895 wxCoord x2
= x
+ width
;
896 wxCoord y2
= y
+ height
;
898 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
901 rect
.left
= XLOG2DEV(x
);
902 rect
.top
= YLOG2DEV(y
);
903 rect
.right
= XLOG2DEV(x2
);
904 rect
.bottom
= YLOG2DEV(y2
);
905 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
909 // Windows draws the filled rectangles without outline (i.e. drawn with a
910 // transparent pen) one pixel smaller in both directions and we want them
911 // to have the same size regardless of which pen is used - adjust
913 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
914 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
916 // Apparently not needed for WinCE (see e.g. Life! demo)
923 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
927 CalcBoundingBox(x
, y
);
928 CalcBoundingBox(x2
, y2
);
931 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
935 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
937 // Now, a negative radius value is interpreted to mean
938 // 'the proportion of the smallest X or Y dimension'
942 double smallest
= (width
< height
) ? width
: height
;
943 radius
= (- radius
* smallest
);
946 wxCoord x2
= (x
+width
);
947 wxCoord y2
= (y
+height
);
949 // Windows draws the filled rectangles without outline (i.e. drawn with a
950 // transparent pen) one pixel smaller in both directions and we want them
951 // to have the same size regardless of which pen is used - adjust
952 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
958 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
959 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
961 CalcBoundingBox(x
, y
);
962 CalcBoundingBox(x2
, y2
);
965 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
969 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
971 wxCoord x2
= (x
+width
);
972 wxCoord y2
= (y
+height
);
974 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
976 CalcBoundingBox(x
, y
);
977 CalcBoundingBox(x2
, y2
);
980 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
981 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
984 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
989 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
994 int rx1
= XLOG2DEV(x
+w
/2);
995 int ry1
= YLOG2DEV(y
+h
/2);
1002 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1003 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1004 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1005 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1007 // draw pie with NULL_PEN first and then outline otherwise a line is
1008 // drawn from the start and end points to the centre
1009 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1012 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1013 rx1
, ry1
, rx2
, ry2
);
1017 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1018 rx1
, ry1
-1, rx2
, ry2
-1);
1021 ::SelectObject(GetHdc(), hpenOld
);
1023 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1024 rx1
, ry1
, rx2
, ry2
);
1026 CalcBoundingBox(x
, y
);
1027 CalcBoundingBox(x2
, y2
);
1031 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1033 WXMICROWIN_CHECK_HDC
1035 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1038 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1040 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1043 CalcBoundingBox(x
, y
);
1044 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1047 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1049 WXMICROWIN_CHECK_HDC
1051 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1053 int width
= bmp
.GetWidth(),
1054 height
= bmp
.GetHeight();
1056 HBITMAP hbmpMask
= 0;
1059 HPALETTE oldPal
= 0;
1060 #endif // wxUSE_PALETTE
1062 if ( bmp
.HasAlpha() )
1065 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1067 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1073 wxMask
*mask
= bmp
.GetMask();
1075 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1079 // don't give assert here because this would break existing
1080 // programs - just silently ignore useMask parameter
1087 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1089 // On some systems, MaskBlt succeeds yet is much much slower
1090 // than the wxWidgets fall-back implementation. So we need
1091 // to be able to switch this on and off at runtime.
1093 #if wxUSE_SYSTEM_OPTIONS
1094 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1098 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1099 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1101 wxPalette
*pal
= bmp
.GetPalette();
1102 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1104 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1105 ::RealizePalette(hdcMem
);
1107 #endif // wxUSE_PALETTE
1109 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1112 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1116 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1117 #endif // wxUSE_PALETTE
1119 ::SelectObject(hdcMem
, hOldBitmap
);
1126 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1129 memDC
.SelectObject(bmp
);
1131 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1133 memDC
.SelectObject(wxNullBitmap
);
1136 else // no mask, just use BitBlt()
1139 HDC memdc
= ::CreateCompatibleDC( cdc
);
1140 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1142 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1144 COLORREF old_textground
= ::GetTextColor(GetHdc());
1145 COLORREF old_background
= ::GetBkColor(GetHdc());
1146 if (m_textForegroundColour
.Ok())
1148 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1150 if (m_textBackgroundColour
.Ok())
1152 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1156 wxPalette
*pal
= bmp
.GetPalette();
1157 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1159 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1160 ::RealizePalette(memdc
);
1162 #endif // wxUSE_PALETTE
1164 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1165 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1169 ::SelectPalette(memdc
, oldPal
, FALSE
);
1170 #endif // wxUSE_PALETTE
1172 ::SelectObject( memdc
, hOldBitmap
);
1173 ::DeleteDC( memdc
);
1175 ::SetTextColor(GetHdc(), old_textground
);
1176 ::SetBkColor(GetHdc(), old_background
);
1180 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1182 WXMICROWIN_CHECK_HDC
1184 DrawAnyText(text
, x
, y
);
1186 // update the bounding box
1187 CalcBoundingBox(x
, y
);
1190 GetTextExtent(text
, &w
, &h
);
1191 CalcBoundingBox(x
+ w
, y
+ h
);
1194 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1196 WXMICROWIN_CHECK_HDC
1198 // prepare for drawing the text
1199 if ( m_textForegroundColour
.Ok() )
1200 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1202 DWORD old_background
= 0;
1203 if ( m_textBackgroundColour
.Ok() )
1205 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1208 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1212 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1213 text
.c_str(), text
.length(), NULL
) == 0 )
1215 wxLogLastError(wxT("TextOut"));
1218 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1219 text
.c_str(), text
.length()) == 0 )
1221 wxLogLastError(wxT("TextOut"));
1225 // restore the old parameters (text foreground colour may be left because
1226 // it never is set to anything else, but background should remain
1227 // transparent even if we just drew an opaque string)
1228 if ( m_textBackgroundColour
.Ok() )
1229 (void)SetBkColor(GetHdc(), old_background
);
1231 SetBkMode(GetHdc(), TRANSPARENT
);
1234 void wxDC::DoDrawRotatedText(const wxString
& text
,
1235 wxCoord x
, wxCoord y
,
1238 WXMICROWIN_CHECK_HDC
1240 // we test that we have some font because otherwise we should still use the
1241 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1242 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1243 // font for drawing rotated fonts unfortunately)
1244 if ( (angle
== 0.0) && m_font
.Ok() )
1246 DoDrawText(text
, x
, y
);
1248 #ifndef __WXMICROWIN__
1251 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1252 // because it's not TrueType and so can't have non zero
1253 // orientation/escapement under Win9x
1254 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1255 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1257 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1259 wxLogLastError(wxT("GetObject(hfont)"));
1262 // GDI wants the angle in tenth of degree
1263 long angle10
= (long)(angle
* 10);
1264 lf
.lfEscapement
= angle10
;
1265 lf
. lfOrientation
= angle10
;
1267 hfont
= ::CreateFontIndirect(&lf
);
1270 wxLogLastError(wxT("CreateFont"));
1274 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1276 DrawAnyText(text
, x
, y
);
1278 (void)::SelectObject(GetHdc(), hfontOld
);
1279 (void)::DeleteObject(hfont
);
1282 // call the bounding box by adding all four vertices of the rectangle
1283 // containing the text to it (simpler and probably not slower than
1284 // determining which of them is really topmost/leftmost/...)
1286 GetTextExtent(text
, &w
, &h
);
1288 double rad
= DegToRad(angle
);
1290 // "upper left" and "upper right"
1291 CalcBoundingBox(x
, y
);
1292 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1294 // "bottom left" and "bottom right"
1295 x
+= (wxCoord
)(h
*sin(rad
));
1296 y
+= (wxCoord
)(h
*cos(rad
));
1297 CalcBoundingBox(x
, y
);
1298 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1303 // ---------------------------------------------------------------------------
1305 // ---------------------------------------------------------------------------
1309 void wxDC::DoSelectPalette(bool realize
)
1311 WXMICROWIN_CHECK_HDC
1313 // Set the old object temporarily, in case the assignment deletes an object
1314 // that's not yet selected out.
1317 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1321 if ( m_palette
.Ok() )
1323 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1324 GetHpaletteOf(m_palette
),
1327 m_oldPalette
= (WXHPALETTE
) oldPal
;
1330 ::RealizePalette(GetHdc());
1334 void wxDC::SetPalette(const wxPalette
& palette
)
1338 m_palette
= palette
;
1339 DoSelectPalette(true);
1343 void wxDC::InitializePalette()
1345 if ( wxDisplayDepth() <= 8 )
1347 // look for any window or parent that has a custom palette. If any has
1348 // one then we need to use it in drawing operations
1349 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1351 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1352 if ( m_hasCustomPalette
)
1354 m_palette
= win
->GetPalette();
1356 // turn on MSW translation for this palette
1362 #endif // wxUSE_PALETTE
1364 // SetFont/Pen/Brush() really ask to be implemented as a single template
1365 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1367 void wxDC::SetFont(const wxFont
& font
)
1369 WXMICROWIN_CHECK_HDC
1371 if ( font
== m_font
)
1376 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1377 if ( hfont
== HGDI_ERROR
)
1379 wxLogLastError(_T("SelectObject(font)"));
1384 m_oldFont
= (WXHPEN
)hfont
;
1389 else // invalid font, reset the current font
1393 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1395 wxLogLastError(_T("SelectObject(old font)"));
1401 m_font
= wxNullFont
;
1405 void wxDC::SetPen(const wxPen
& pen
)
1407 WXMICROWIN_CHECK_HDC
1414 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1415 if ( hpen
== HGDI_ERROR
)
1417 wxLogLastError(_T("SelectObject(pen)"));
1422 m_oldPen
= (WXHPEN
)hpen
;
1427 else // invalid pen, reset the current pen
1431 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1433 wxLogLastError(_T("SelectObject(old pen)"));
1443 void wxDC::SetBrush(const wxBrush
& brush
)
1445 WXMICROWIN_CHECK_HDC
1447 if ( brush
== m_brush
)
1452 // we must make sure the brush is aligned with the logical coordinates
1453 // before selecting it
1454 wxBitmap
*stipple
= brush
.GetStipple();
1455 if ( stipple
&& stipple
->Ok() )
1457 if ( !::SetBrushOrgEx
1460 m_deviceOriginX
% stipple
->GetWidth(),
1461 m_deviceOriginY
% stipple
->GetHeight(),
1462 NULL
// [out] previous brush origin
1465 wxLogLastError(_T("SetBrushOrgEx()"));
1469 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1470 if ( hbrush
== HGDI_ERROR
)
1472 wxLogLastError(_T("SelectObject(brush)"));
1477 m_oldBrush
= (WXHPEN
)hbrush
;
1482 else // invalid brush, reset the current brush
1486 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1488 wxLogLastError(_T("SelectObject(old brush)"));
1494 m_brush
= wxNullBrush
;
1498 void wxDC::SetBackground(const wxBrush
& brush
)
1500 WXMICROWIN_CHECK_HDC
1502 m_backgroundBrush
= brush
;
1504 if ( m_backgroundBrush
.Ok() )
1506 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1510 void wxDC::SetBackgroundMode(int mode
)
1512 WXMICROWIN_CHECK_HDC
1514 m_backgroundMode
= mode
;
1516 // SetBackgroundColour now only refers to text background
1517 // and m_backgroundMode is used there
1520 void wxDC::SetLogicalFunction(int function
)
1522 WXMICROWIN_CHECK_HDC
1524 m_logicalFunction
= function
;
1529 void wxDC::SetRop(WXHDC dc
)
1531 if ( !dc
|| m_logicalFunction
< 0 )
1536 switch (m_logicalFunction
)
1538 case wxCLEAR
: rop
= R2_BLACK
; break;
1539 case wxXOR
: rop
= R2_XORPEN
; break;
1540 case wxINVERT
: rop
= R2_NOT
; break;
1541 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1542 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1543 case wxCOPY
: rop
= R2_COPYPEN
; break;
1544 case wxAND
: rop
= R2_MASKPEN
; break;
1545 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1546 case wxNO_OP
: rop
= R2_NOP
; break;
1547 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1548 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1549 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1550 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1551 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1552 case wxOR
: rop
= R2_MERGEPEN
; break;
1553 case wxSET
: rop
= R2_WHITE
; break;
1556 wxFAIL_MSG( wxT("unsupported logical function") );
1560 SetROP2(GetHdc(), rop
);
1563 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1565 // We might be previewing, so return true to let it continue.
1573 void wxDC::StartPage()
1577 void wxDC::EndPage()
1581 // ---------------------------------------------------------------------------
1583 // ---------------------------------------------------------------------------
1585 wxCoord
wxDC::GetCharHeight() const
1587 WXMICROWIN_CHECK_HDC_RET(0)
1589 TEXTMETRIC lpTextMetric
;
1591 GetTextMetrics(GetHdc(), &lpTextMetric
);
1593 return lpTextMetric
.tmHeight
;
1596 wxCoord
wxDC::GetCharWidth() const
1598 WXMICROWIN_CHECK_HDC_RET(0)
1600 TEXTMETRIC lpTextMetric
;
1602 GetTextMetrics(GetHdc(), &lpTextMetric
);
1604 return lpTextMetric
.tmAveCharWidth
;
1607 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1608 wxCoord
*descent
, wxCoord
*externalLeading
,
1611 #ifdef __WXMICROWIN__
1616 if (descent
) *descent
= 0;
1617 if (externalLeading
) *externalLeading
= 0;
1620 #endif // __WXMICROWIN__
1625 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1627 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1629 else // don't change the font
1637 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1638 GetTextMetrics(GetHdc(), &tm
);
1645 *descent
= tm
.tmDescent
;
1646 if (externalLeading
)
1647 *externalLeading
= tm
.tmExternalLeading
;
1651 ::SelectObject(GetHdc(), hfontOld
);
1656 // Each element of the array will be the width of the string up to and
1657 // including the coresoponding character in text.
1659 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1661 static int maxLenText
= -1;
1662 static int maxWidth
= -1;
1665 int stlen
= text
.Length();
1667 if (maxLenText
== -1)
1669 // Win9x and WinNT+ have different limits
1670 int version
= wxGetOsVersion();
1671 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1672 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1676 widths
.Add(0, stlen
); // fill the array with zeros
1680 if (!::GetTextExtentExPoint(GetHdc(),
1681 text
.c_str(), // string to check
1682 wxMin(stlen
, maxLenText
),
1684 &fit
, // [out] count of chars
1686 &widths
[0], // array to fill
1690 wxLogLastError(wxT("GetTextExtentExPoint"));
1700 void wxDC::SetMapMode(int mode
)
1702 WXMICROWIN_CHECK_HDC
1704 m_mappingMode
= mode
;
1706 if ( mode
== wxMM_TEXT
)
1709 m_logicalScaleY
= 1.0;
1711 else // need to do some calculations
1713 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1714 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1715 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1716 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1718 if ( (mm_width
== 0) || (mm_height
== 0) )
1720 // we can't calculate mm2pixels[XY] then!
1724 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1725 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1730 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1731 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1735 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1736 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1740 m_logicalScaleX
= mm2pixelsX
;
1741 m_logicalScaleY
= mm2pixelsY
;
1745 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1746 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1750 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1754 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1755 // cases we could do with MM_TEXT and in the remaining 0.9% with
1756 // MM_ISOTROPIC (TODO!)
1758 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1760 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1761 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1763 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1764 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1766 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1767 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1771 void wxDC::SetUserScale(double x
, double y
)
1773 WXMICROWIN_CHECK_HDC
1775 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1781 this->SetMapMode(m_mappingMode
);
1784 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1785 bool WXUNUSED_IN_WINCE(yBottomUp
))
1787 WXMICROWIN_CHECK_HDC
1790 int signX
= xLeftRight
? 1 : -1,
1791 signY
= yBottomUp
? -1 : 1;
1793 if ( signX
!= m_signX
|| signY
!= m_signY
)
1798 SetMapMode(m_mappingMode
);
1803 void wxDC::SetSystemScale(double x
, double y
)
1805 WXMICROWIN_CHECK_HDC
1807 if ( x
== m_scaleX
&& y
== m_scaleY
)
1814 SetMapMode(m_mappingMode
);
1818 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1820 WXMICROWIN_CHECK_HDC
1822 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1825 m_logicalOriginX
= x
;
1826 m_logicalOriginY
= y
;
1829 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1833 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1835 WXMICROWIN_CHECK_HDC
1837 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1840 m_deviceOriginX
= x
;
1841 m_deviceOriginY
= y
;
1843 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1846 // ---------------------------------------------------------------------------
1847 // coordinates transformations
1848 // ---------------------------------------------------------------------------
1850 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1852 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1855 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1857 // axis orientation is not taken into account for conversion of a distance
1858 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1861 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1863 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1866 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1868 // axis orientation is not taken into account for conversion of a distance
1869 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1872 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1874 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1877 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1879 // axis orientation is not taken into account for conversion of a distance
1880 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1883 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1885 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1888 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1890 // axis orientation is not taken into account for conversion of a distance
1891 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1894 // ---------------------------------------------------------------------------
1896 // ---------------------------------------------------------------------------
1898 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1899 wxCoord width
, wxCoord height
,
1900 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1901 int rop
, bool useMask
,
1902 wxCoord xsrcMask
, wxCoord ysrcMask
)
1904 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1906 WXMICROWIN_CHECK_HDC_RET(false)
1908 // if either the source or destination has alpha channel, we must use
1909 // AlphaBlt() as other function don't handle it correctly
1910 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1911 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1912 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1914 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1915 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
1919 wxMask
*mask
= NULL
;
1922 mask
= bmpSrc
.GetMask();
1924 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1926 // don't give assert here because this would break existing
1927 // programs - just silently ignore useMask parameter
1932 if (xsrcMask
== -1 && ysrcMask
== -1)
1934 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
1937 COLORREF old_textground
= ::GetTextColor(GetHdc());
1938 COLORREF old_background
= ::GetBkColor(GetHdc());
1939 if (m_textForegroundColour
.Ok())
1941 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1943 if (m_textBackgroundColour
.Ok())
1945 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1951 case wxXOR
: dwRop
= SRCINVERT
; break;
1952 case wxINVERT
: dwRop
= DSTINVERT
; break;
1953 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1954 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1955 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1956 case wxSET
: dwRop
= WHITENESS
; break;
1957 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1958 case wxAND
: dwRop
= SRCAND
; break;
1959 case wxOR
: dwRop
= SRCPAINT
; break;
1960 case wxEQUIV
: dwRop
= 0x00990066; break;
1961 case wxNAND
: dwRop
= 0x007700E6; break;
1962 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1963 case wxCOPY
: dwRop
= SRCCOPY
; break;
1964 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1965 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1966 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1968 wxFAIL_MSG( wxT("unsupported logical function") );
1972 bool success
= false;
1977 // we want the part of the image corresponding to the mask to be
1978 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1979 // meaning of fg and bg is inverted which corresponds to wxWin notion
1980 // of the mask which is also contrary to the Windows one)
1982 // On some systems, MaskBlt succeeds yet is much much slower
1983 // than the wxWidgets fall-back implementation. So we need
1984 // to be able to switch this on and off at runtime.
1985 #if wxUSE_SYSTEM_OPTIONS
1986 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1992 xdest
, ydest
, width
, height
,
1995 (HBITMAP
)mask
->GetMaskBitmap(),
1997 MAKEROP4(dwRop
, DSTCOPY
)
2004 // Blit bitmap with mask
2007 HBITMAP buffer_bmap
;
2009 #if wxUSE_DC_CACHEING
2010 // create a temp buffer bitmap and DCs to access it and the mask
2011 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2012 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2014 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2015 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2017 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2020 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2021 #else // !wxUSE_DC_CACHEING
2022 // create a temp buffer bitmap and DCs to access it and the mask
2023 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2024 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2025 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2026 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2027 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2028 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2030 // copy dest to buffer
2031 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2032 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2034 wxLogLastError(wxT("BitBlt"));
2037 // copy src to buffer using selected raster op
2038 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2039 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2041 wxLogLastError(wxT("BitBlt"));
2044 // set masked area in buffer to BLACK (pixel value 0)
2045 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2046 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2047 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2048 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2050 wxLogLastError(wxT("BitBlt"));
2053 // set unmasked area in dest to BLACK
2054 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2055 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2056 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2057 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2059 wxLogLastError(wxT("BitBlt"));
2061 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2062 ::SetTextColor(GetHdc(), prevCol
);
2064 // OR buffer to dest
2065 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2066 (int)width
, (int)height
,
2067 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2070 wxLogLastError(wxT("BitBlt"));
2073 // tidy up temporary DCs and bitmap
2074 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2075 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2077 #if !wxUSE_DC_CACHEING
2079 ::DeleteDC(dc_mask
);
2080 ::DeleteDC(dc_buffer
);
2081 ::DeleteObject(buffer_bmap
);
2086 else // no mask, just BitBlt() it
2088 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2089 // use StretchBlt() if available and finally fall back to BitBlt()
2091 // FIXME: use appropriate WinCE functions
2093 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2094 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2099 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2101 &ds
) == sizeof(ds
) )
2103 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2105 // Figure out what co-ordinate system we're supposed to specify
2107 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2111 ysrc
= hDIB
- (ysrc
+ height
);
2114 if ( ::StretchDIBits(GetHdc(),
2120 (LPBITMAPINFO
)&ds
.dsBmih
,
2123 ) == (int)GDI_ERROR
)
2125 // On Win9x this API fails most (all?) of the time, so
2126 // logging it becomes quite distracting. Since it falls
2127 // back to the code below this is not really serious, so
2129 //wxLogLastError(wxT("StretchDIBits"));
2138 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2143 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2149 xdest
, ydest
, width
, height
,
2151 xsrc
, ysrc
, width
, height
,
2155 wxLogLastError(_T("StretchBlt"));
2169 (int)width
, (int)height
,
2175 wxLogLastError(_T("BitBlt"));
2184 ::SetTextColor(GetHdc(), old_textground
);
2185 ::SetBkColor(GetHdc(), old_background
);
2190 void wxDC::DoGetSize(int *w
, int *h
) const
2192 WXMICROWIN_CHECK_HDC
2194 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2195 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2198 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2200 WXMICROWIN_CHECK_HDC
2202 // if we implement it in terms of DoGetSize() instead of directly using the
2203 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2204 // will also work for wxWindowDC and wxClientDC even though their size is
2205 // not the same as the total size of the screen
2206 int wPixels
, hPixels
;
2207 DoGetSize(&wPixels
, &hPixels
);
2211 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2213 wxCHECK_RET( wTotal
, _T("0 width device?") );
2215 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2220 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2222 wxCHECK_RET( hTotal
, _T("0 height device?") );
2224 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2228 wxSize
wxDC::GetPPI() const
2230 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2232 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2233 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2235 return wxSize(x
, y
);
2238 // For use by wxWidgets only, unless custom units are required.
2239 void wxDC::SetLogicalScale(double x
, double y
)
2241 WXMICROWIN_CHECK_HDC
2243 m_logicalScaleX
= x
;
2244 m_logicalScaleY
= y
;
2247 // ----------------------------------------------------------------------------
2249 // ----------------------------------------------------------------------------
2251 #if wxUSE_DC_CACHEING
2254 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2255 * improve it in due course, either using arrays, or simply storing pointers to one
2256 * entry for the bitmap, and two for the DCs. -- JACS
2259 wxList
wxDC::sm_bitmapCache
;
2260 wxList
wxDC::sm_dcCache
;
2262 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2271 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2280 wxDCCacheEntry::~wxDCCacheEntry()
2283 ::DeleteObject((HBITMAP
) m_bitmap
);
2285 ::DeleteDC((HDC
) m_dc
);
2288 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2290 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2291 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2294 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2296 if (entry
->m_depth
== depth
)
2298 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2300 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2301 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2302 if ( !entry
->m_bitmap
)
2304 wxLogLastError(wxT("CreateCompatibleBitmap"));
2306 entry
->m_width
= w
; entry
->m_height
= h
;
2312 node
= node
->GetNext();
2314 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2317 wxLogLastError(wxT("CreateCompatibleBitmap"));
2319 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2320 AddToBitmapCache(entry
);
2324 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2326 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2327 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2330 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2332 // Don't return the same one as we already have
2333 if (!notThis
|| (notThis
!= entry
))
2335 if (entry
->m_depth
== depth
)
2341 node
= node
->GetNext();
2343 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2346 wxLogLastError(wxT("CreateCompatibleDC"));
2348 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2349 AddToDCCache(entry
);
2353 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2355 sm_bitmapCache
.Append(entry
);
2358 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2360 sm_dcCache
.Append(entry
);
2363 void wxDC::ClearCache()
2365 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2366 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2369 // Clean up cache at app exit
2370 class wxDCModule
: public wxModule
2373 virtual bool OnInit() { return true; }
2374 virtual void OnExit() { wxDC::ClearCache(); }
2377 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2380 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2382 #endif // wxUSE_DC_CACHEING
2384 // ----------------------------------------------------------------------------
2385 // alpha channel support
2386 // ----------------------------------------------------------------------------
2388 static bool AlphaBlt(HDC hdcDst
,
2389 int x
, int y
, int width
, int height
,
2390 int srcX
, int srcY
, HDC hdcSrc
,
2391 const wxBitmap
& bmp
)
2393 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2394 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2396 // do we have AlphaBlend() and company in the headers?
2397 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2398 // yes, now try to see if we have it during run-time
2399 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2400 HDC
,int,int,int,int,
2403 // bitmaps can be drawn only from GUI thread so there is no need to
2404 // protect this static variable from multiple threads
2405 static bool s_triedToLoad
= false;
2406 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2407 if ( !s_triedToLoad
)
2409 s_triedToLoad
= true;
2411 // don't give errors about the DLL being unavailable, we're
2412 // prepared to handle this
2415 wxDynamicLibrary
dll(_T("msimg32.dll"));
2416 if ( dll
.IsLoaded() )
2418 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2419 if ( pfnAlphaBlend
)
2421 // we must keep the DLL loaded if we want to be able to
2422 // call AlphaBlend() so just never unload it at all, not a
2429 if ( pfnAlphaBlend
)
2432 bf
.BlendOp
= AC_SRC_OVER
;
2434 bf
.SourceConstantAlpha
= 0xff;
2435 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2437 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2438 hdcSrc
, srcX
, srcY
, width
, height
,
2441 // skip wxAlphaBlend() call below
2445 wxLogLastError(_T("AlphaBlend"));
2447 #endif // defined(AC_SRC_OVER)
2449 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2451 #ifdef wxHAVE_RAW_BITMAP
2452 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2455 #else // !wxHAVE_RAW_BITMAP
2456 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2457 // alpha but at least something will be shown like this)
2460 #endif // wxHAVE_RAW_BITMAP
2464 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2465 #ifdef wxHAVE_RAW_BITMAP
2468 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2470 // get the destination DC pixels
2471 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2473 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2475 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2477 wxLogLastError(_T("BitBlt"));
2480 // combine them with the source bitmap using alpha
2481 wxAlphaPixelData
dataDst(bmpDst
),
2482 dataSrc((wxBitmap
&)bmpSrc
);
2484 wxCHECK_RET( dataDst
&& dataSrc
,
2485 _T("failed to get raw data in wxAlphaBlend") );
2487 wxAlphaPixelData::Iterator
pDst(dataDst
),
2490 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2492 for ( int y
= 0; y
< h
; y
++ )
2494 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2495 pSrcRowStart
= pSrc
;
2497 for ( int x
= 0; x
< w
; x
++ )
2499 // note that source bitmap uses premultiplied alpha (as required by
2500 // the real AlphaBlend)
2501 const unsigned beta
= 255 - pSrc
.Alpha();
2503 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2504 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2505 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2511 pDst
= pDstRowStart
;
2512 pSrc
= pSrcRowStart
;
2513 pDst
.OffsetY(dataDst
, 1);
2514 pSrc
.OffsetY(dataSrc
, 1);
2517 // and finally blit them back to the destination DC
2518 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2520 wxLogLastError(_T("BitBlt"));
2524 #endif // #ifdef wxHAVE_RAW_BITMAP