1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dc.cpp
3 // Purpose: wxDC class for MSW port
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/msw/wrapcdlg.h"
30 #include "wx/window.h"
32 #include "wx/dialog.h"
34 #include "wx/bitmap.h"
35 #include "wx/dcmemory.h"
38 #include "wx/dcprint.h"
39 #include "wx/module.h"
42 #include "wx/msw/dc.h"
43 #include "wx/sysopt.h"
44 #include "wx/dynlib.h"
46 #ifdef wxHAS_RAW_BITMAP
47 #include "wx/rawbmp.h"
52 #include "wx/msw/private/dc.h"
54 using namespace wxMSWImpl
;
57 #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(wxMSWDCImpl
, wxDCImpl
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
88 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
89 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
91 // ----------------------------------------------------------------------------
92 // macros for logical <-> device coords conversion
93 // ----------------------------------------------------------------------------
96 We currently let Windows do all the translations itself so these macros are
97 not really needed (any more) but keep them to enhance readability of the
98 code by allowing to see where are the logical and where are the device
103 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
104 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
105 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
106 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
108 #define XLOG2DEV(x) (x)
109 #define YLOG2DEV(y) (y)
110 #define XDEV2LOG(x) (x)
111 #define YDEV2LOG(y) (y)
114 // ---------------------------------------------------------------------------
116 // ---------------------------------------------------------------------------
118 // convert degrees to radians
119 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
121 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
123 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
124 // to pass it to this function but as we already have it at the point
125 // of call anyhow we do
127 // return true if we could draw the bitmap in one way or the other, false
129 static bool AlphaBlt(HDC hdcDst
,
130 int x
, int y
, int dstWidth
, int dstHeight
,
132 int srcWidth
, int srcHeight
,
134 const wxBitmap
& bmp
);
136 #ifdef wxHAS_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement for Windows versions not providing it
140 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
141 int dstWidth
, int dstHeight
,
143 int srcWidth
, int srcHeight
,
144 const wxBitmap
& bmpSrc
);
146 #endif // wxHAS_RAW_BITMAP
148 // ----------------------------------------------------------------------------
150 // ----------------------------------------------------------------------------
152 // instead of duplicating the same code which sets and then restores text
153 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
154 // encapsulate this in a small helper class
156 // wxBrushAttrsSetter: changes the text colours in the ctor if required and
157 // restores them in the dtor
158 class wxBrushAttrsSetter
: private wxBkModeChanger
,
159 private wxTextColoursChanger
162 wxBrushAttrsSetter(wxMSWDCImpl
& dc
);
165 wxDECLARE_NO_COPY_CLASS(wxBrushAttrsSetter
);
170 #define SET_STRETCH_BLT_MODE(hdc)
172 #else // !__WXWINCE__
174 // this class sets the stretch blit mode to COLORONCOLOR during its lifetime
176 // don't use it directly, use SET_STRETCH_BLT_MODE() macro instead as it
177 // expands to nothing under WinCE which doesn't have SetStretchBltMode()
178 class StretchBltModeChanger
181 StretchBltModeChanger(HDC hdc
)
184 m_modeOld
= ::SetStretchBltMode(m_hdc
, COLORONCOLOR
);
186 wxLogLastError(_T("SetStretchBltMode"));
189 ~StretchBltModeChanger()
191 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
192 wxLogLastError(_T("SetStretchBltMode"));
200 wxDECLARE_NO_COPY_CLASS(StretchBltModeChanger
);
203 #define SET_STRETCH_BLT_MODE(hdc) \
204 StretchBltModeChanger wxMAKE_UNIQUE_NAME(stretchModeChanger)(hdc)
206 #endif // __WXWINCE__/!__WXWINCE__
208 #if wxUSE_DYNLIB_CLASS
210 // helper class to cache dynamically loaded libraries and not attempt reloading
212 class wxOnceOnlyDLLLoader
215 // ctor argument must be a literal string as we don't make a copy of it!
216 wxOnceOnlyDLLLoader(const wxChar
*dllName
)
222 // return the symbol with the given name or NULL if the DLL not loaded
223 // or symbol not present
224 void *GetSymbol(const wxChar
*name
)
226 // we're prepared to handle errors here
231 m_dll
.Load(m_dllName
);
233 // reset the name whether we succeeded or failed so that we don't
234 // try again the next time
238 return m_dll
.IsLoaded() ? m_dll
.GetSymbol(name
) : NULL
;
243 if ( m_dll
.IsLoaded() )
250 wxDynamicLibrary m_dll
;
251 const wxChar
*m_dllName
;
254 static wxOnceOnlyDLLLoader
wxMSIMG32DLL(_T("msimg32"));
256 // we must ensure that DLLs are unloaded before the static objects cleanup time
257 // because we may hit the notorious DllMain() dead lock in this case if wx is
258 // used as a DLL (attempting to unload another DLL from inside DllMain() hangs
259 // under Windows because it tries to reacquire the same lock)
260 class wxGDIDLLsCleanupModule
: public wxModule
263 virtual bool OnInit() { return true; }
264 virtual void OnExit() { wxMSIMG32DLL
.Unload(); }
267 DECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule
)
270 IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule
, wxModule
)
272 #endif // wxUSE_DYNLIB_CLASS
274 // ===========================================================================
276 // ===========================================================================
278 // ----------------------------------------------------------------------------
279 // wxBrushAttrsSetter
280 // ----------------------------------------------------------------------------
282 wxBrushAttrsSetter::wxBrushAttrsSetter(wxMSWDCImpl
& dc
)
283 : wxBkModeChanger(GetHdcOf(dc
)),
284 wxTextColoursChanger(GetHdcOf(dc
))
286 const wxBrush
& brush
= dc
.GetBrush();
287 if ( brush
.IsOk() && brush
.GetStyle() == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE
)
289 // note that Windows convention is opposite to wxWidgets one, this is
290 // why text colour becomes the background one and vice versa
291 wxTextColoursChanger::Change(dc
.GetTextBackground(),
292 dc
.GetTextForeground());
294 wxBkModeChanger::Change(dc
.GetBackgroundMode());
298 // ----------------------------------------------------------------------------
299 // wxDC MSW-specific methods
300 // ----------------------------------------------------------------------------
302 WXHDC
wxDC::GetHDC() const
304 wxMSWDCImpl
* const impl
= wxDynamicCast(GetImpl(), wxMSWDCImpl
);
305 return impl
? impl
->GetHDC() : 0;
308 // ---------------------------------------------------------------------------
310 // ---------------------------------------------------------------------------
312 wxMSWDCImpl::wxMSWDCImpl( wxDC
*owner
, WXHDC hDC
) :
319 wxMSWDCImpl::~wxMSWDCImpl()
323 SelectOldObjects(m_hDC
);
325 // if we own the HDC, we delete it, otherwise we just release it
329 ::DeleteDC(GetHdc());
331 else // we don't own our HDC
335 ::ReleaseDC(GetHwndOf(m_window
), GetHdc());
339 // Must have been a wxScreenDC
340 ::ReleaseDC((HWND
) NULL
, GetHdc());
346 // This will select current objects out of the DC,
347 // which is what you have to do before deleting the
349 void wxMSWDCImpl::SelectOldObjects(WXHDC dc
)
355 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
356 if (m_selectedBitmap
.IsOk())
358 m_selectedBitmap
.SetSelectedInto(NULL
);
364 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
369 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
374 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
381 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
384 #endif // wxUSE_PALETTE
387 m_brush
= wxNullBrush
;
390 m_palette
= wxNullPalette
;
391 #endif // wxUSE_PALETTE
393 m_backgroundBrush
= wxNullBrush
;
394 m_selectedBitmap
= wxNullBitmap
;
397 // ---------------------------------------------------------------------------
399 // ---------------------------------------------------------------------------
401 void wxMSWDCImpl::UpdateClipBox()
406 ::GetClipBox(GetHdc(), &rect
);
408 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
409 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
410 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
411 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
415 wxMSWDCImpl::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
417 // check if we should try to retrieve the clipping region possibly not set
418 // by our SetClippingRegion() but preset by Windows:this can only happen
419 // when we're associated with an existing HDC usign SetHDC(), see there
420 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
422 wxMSWDCImpl
*self
= wxConstCast(this, wxMSWDCImpl
);
423 self
->UpdateClipBox();
425 if ( !m_clipX1
&& !m_clipX2
)
426 self
->m_clipping
= false;
429 wxDCImpl::DoGetClippingBox(x
, y
, w
, h
);
432 // common part of DoSetClippingRegion() and DoSetDeviceClippingRegion()
433 void wxMSWDCImpl::SetClippingHrgn(WXHRGN hrgn
)
435 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
439 // note that we combine the new clipping region with the existing one: this
440 // is compatible with what the other ports do and is the documented
441 // behaviour now (starting with 2.3.3)
442 #if defined(__WXWINCE__)
444 if ( !::GetClipBox(GetHdc(), &rectClip
) )
447 // GetClipBox returns logical coordinates, so transform to device
448 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
449 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
450 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
451 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
453 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
454 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
455 rectClip
.right
, rectClip
.bottom
);
457 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
459 ::SelectClipRgn(GetHdc(), hrgnDest
);
462 ::DeleteObject(hrgnClipOld
);
463 ::DeleteObject(hrgnDest
);
465 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
467 wxLogLastError(_T("ExtSelectClipRgn"));
471 #endif // WinCE/!WinCE
478 void wxMSWDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
480 // the region coords are always the device ones, so do the translation
483 // FIXME: possible +/-1 error here, to check!
484 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
486 LogicalToDeviceX(x
+ w
),
487 LogicalToDeviceY(y
+ h
));
490 wxLogLastError(_T("CreateRectRgn"));
494 SetClippingHrgn((WXHRGN
)hrgn
);
496 ::DeleteObject(hrgn
);
500 void wxMSWDCImpl::DoSetDeviceClippingRegion(const wxRegion
& region
)
502 SetClippingHrgn(region
.GetHRGN());
505 void wxMSWDCImpl::DestroyClippingRegion()
509 if (m_clipping
&& m_hDC
)
512 // On a PocketPC device (not necessarily emulator), resetting
513 // the clip region as per the old method causes bad display
514 // problems. In fact setting a null region is probably OK
515 // on desktop WIN32 also, since the WIN32 docs imply that the user
516 // clipping region is independent from the paint clipping region.
517 ::SelectClipRgn(GetHdc(), 0);
519 // TODO: this should restore the previous clipping region,
520 // so that OnPaint processing works correctly, and the update
521 // clipping region doesn't get destroyed after the first
522 // DestroyClippingRegion.
523 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
524 ::SelectClipRgn(GetHdc(), rgn
);
529 wxDCImpl::DestroyClippingRegion();
532 // ---------------------------------------------------------------------------
533 // query capabilities
534 // ---------------------------------------------------------------------------
536 bool wxMSWDCImpl::CanDrawBitmap() const
541 bool wxMSWDCImpl::CanGetTextExtent() const
543 #ifdef __WXMICROWIN__
544 // TODO Extend MicroWindows' GetDeviceCaps function
547 // What sort of display is it?
548 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
550 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
554 int wxMSWDCImpl::GetDepth() const
556 WXMICROWIN_CHECK_HDC_RET(16)
558 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
561 // ---------------------------------------------------------------------------
563 // ---------------------------------------------------------------------------
565 void wxMSWDCImpl::Clear()
572 GetClientRect((HWND
) m_window
->GetHWND(), &rect
);
576 // No, I think we should simply ignore this if printing on e.g.
578 // wxCHECK_RET( m_selectedBitmap.IsOk(), wxT("this DC can't be cleared") );
579 if (!m_selectedBitmap
.IsOk())
582 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
583 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
584 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
588 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
591 DWORD colour
= ::GetBkColor(GetHdc());
592 HBRUSH brush
= ::CreateSolidBrush(colour
);
593 ::FillRect(GetHdc(), &rect
, brush
);
594 ::DeleteObject(brush
);
596 RealizeScaleAndOrigin();
599 bool wxMSWDCImpl::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
600 wxCoord
WXUNUSED_IN_WINCE(y
),
601 const wxColour
& WXUNUSED_IN_WINCE(col
),
602 wxFloodFillStyle
WXUNUSED_IN_WINCE(style
))
607 WXMICROWIN_CHECK_HDC_RET(false)
609 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
611 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
612 : FLOODFILLBORDER
) ) ;
615 // quoting from the MSDN docs:
617 // Following are some of the reasons this function might fail:
619 // * The filling could not be completed.
620 // * The specified point has the boundary color specified by the
621 // crColor parameter (if FLOODFILLBORDER was requested).
622 // * The specified point does not have the color specified by
623 // crColor (if FLOODFILLSURFACE was requested)
624 // * The point is outside the clipping region that is, it is not
625 // visible on the device.
627 wxLogLastError(wxT("ExtFloodFill"));
630 CalcBoundingBox(x
, y
);
636 bool wxMSWDCImpl::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
638 WXMICROWIN_CHECK_HDC_RET(false)
640 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxMSWDCImpl::GetPixel") );
642 // get the color of the pixel
643 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
645 wxRGBToColour(*col
, pixelcolor
);
650 void wxMSWDCImpl::DoCrossHair(wxCoord x
, wxCoord y
)
654 wxCoord x1
= x
-VIEWPORT_EXTENT
;
655 wxCoord y1
= y
-VIEWPORT_EXTENT
;
656 wxCoord x2
= x
+VIEWPORT_EXTENT
;
657 wxCoord y2
= y
+VIEWPORT_EXTENT
;
659 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
660 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
662 CalcBoundingBox(x1
, y1
);
663 CalcBoundingBox(x2
, y2
);
666 void wxMSWDCImpl::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
670 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
672 CalcBoundingBox(x1
, y1
);
673 CalcBoundingBox(x2
, y2
);
676 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
677 // and ending at (x2, y2)
678 void wxMSWDCImpl::DoDrawArc(wxCoord x1
, wxCoord y1
,
679 wxCoord x2
, wxCoord y2
,
680 wxCoord xc
, wxCoord yc
)
684 wxCoord r
= (wxCoord
)sqrt(dx
*dx
+ dy
*dy
);
688 // Slower emulation since WinCE doesn't support Pie and Arc
689 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
691 sa
= -sa
; // below center
692 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
693 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
698 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
700 // treat the special case of full circle separately
701 if ( x1
== x2
&& y1
== y2
)
703 GetOwner()->DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
707 wxCoord xx1
= XLOG2DEV(x1
);
708 wxCoord yy1
= YLOG2DEV(y1
);
709 wxCoord xx2
= XLOG2DEV(x2
);
710 wxCoord yy2
= YLOG2DEV(y2
);
711 wxCoord xxc
= XLOG2DEV(xc
);
712 wxCoord yyc
= YLOG2DEV(yc
);
715 wxCoord ray
= (wxCoord
)sqrt(dx
*dx
+ dy
*dy
);
717 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
718 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
719 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
720 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
722 if ( m_brush
.IsOk() && m_brush
.GetStyle() != wxBRUSHSTYLE_TRANSPARENT
)
724 // Have to add 1 to bottom-right corner of rectangle
725 // to make semi-circles look right (crooked line otherwise).
726 // Unfortunately this is not a reliable method, depends
727 // on the size of shape.
728 // TODO: figure out why this happens!
729 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
733 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
736 CalcBoundingBox(xc
- r
, yc
- r
);
737 CalcBoundingBox(xc
+ r
, yc
+ r
);
741 void wxMSWDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
742 wxCoord width
, wxCoord height
)
744 // cases when we don't have DrawFrameControl()
745 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
746 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
748 wxCoord x2
= x1
+ width
,
758 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
| DFCS_CHECKED
);
760 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
763 CalcBoundingBox(x1
, y1
);
764 CalcBoundingBox(x2
, y2
);
765 #endif // Microwin/Normal
768 void wxMSWDCImpl::DoDrawPoint(wxCoord x
, wxCoord y
)
772 COLORREF color
= 0x00ffffff;
775 color
= m_pen
.GetColour().GetPixel();
778 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
780 CalcBoundingBox(x
, y
);
783 void wxMSWDCImpl::DoDrawPolygon(int n
,
787 wxPolygonFillMode
WXUNUSED_IN_WINCE(fillStyle
))
791 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
793 // Do things less efficiently if we have offsets
794 if (xoffset
!= 0 || yoffset
!= 0)
796 POINT
*cpoints
= new POINT
[n
];
798 for (i
= 0; i
< n
; i
++)
800 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
801 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
803 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
806 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
808 (void)Polygon(GetHdc(), cpoints
, n
);
810 SetPolyFillMode(GetHdc(),prev
);
817 for (i
= 0; i
< n
; i
++)
818 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
821 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
823 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
825 SetPolyFillMode(GetHdc(),prev
);
831 wxMSWDCImpl::DoDrawPolyPolygon(int n
,
836 wxPolygonFillMode fillStyle
)
839 wxDCImpl::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
843 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
845 for (i
= cnt
= 0; i
< n
; i
++)
848 // Do things less efficiently if we have offsets
849 if (xoffset
!= 0 || yoffset
!= 0)
851 POINT
*cpoints
= new POINT
[cnt
];
852 for (i
= 0; i
< cnt
; i
++)
854 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
855 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
857 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
860 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
862 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
864 SetPolyFillMode(GetHdc(),prev
);
870 for (i
= 0; i
< cnt
; i
++)
871 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
874 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
876 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
878 SetPolyFillMode(GetHdc(),prev
);
885 void wxMSWDCImpl::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
889 // Do things less efficiently if we have offsets
890 if (xoffset
!= 0 || yoffset
!= 0)
892 POINT
*cpoints
= new POINT
[n
];
894 for (i
= 0; i
< n
; i
++)
896 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
897 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
899 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
901 (void)Polyline(GetHdc(), cpoints
, n
);
907 for (i
= 0; i
< n
; i
++)
908 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
910 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
914 void wxMSWDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
918 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
920 wxCoord x2
= x
+ width
;
921 wxCoord y2
= y
+ height
;
923 wxCoord x2dev
= XLOG2DEV(x2
),
924 y2dev
= YLOG2DEV(y2
);
926 // Windows (but not Windows CE) draws the filled rectangles without outline
927 // (i.e. drawn with a transparent pen) one pixel smaller in both directions
928 // and we want them to have the same size regardless of which pen is used
930 if ( m_pen
.IsOk() && m_pen
.GetStyle() == wxPENSTYLE_TRANSPARENT
)
935 #endif // !__WXWINCE__
937 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), x2dev
, y2dev
);
939 CalcBoundingBox(x
, y
);
940 CalcBoundingBox(x2
, y2
);
943 void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
947 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
949 // Now, a negative radius value is interpreted to mean
950 // 'the proportion of the smallest X or Y dimension'
954 double smallest
= (width
< height
) ? width
: height
;
955 radius
= (- radius
* smallest
);
958 wxCoord x2
= (x
+width
);
959 wxCoord y2
= (y
+height
);
961 // Windows draws the filled rectangles without outline (i.e. drawn with a
962 // transparent pen) one pixel smaller in both directions and we want them
963 // to have the same size regardless of which pen is used - adjust
964 if ( m_pen
.GetStyle() == wxPENSTYLE_TRANSPARENT
)
970 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
971 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
973 CalcBoundingBox(x
, y
);
974 CalcBoundingBox(x2
, y2
);
977 void wxMSWDCImpl::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
981 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
983 // +1 below makes the ellipse more similar to other platforms.
984 // In particular, DoDrawEllipse(x,y,1,1) should draw one point.
985 wxCoord x2
= x
+ width
+ 1;
986 wxCoord y2
= y
+ height
+ 1;
988 // Problem: Windows GDI Ellipse() with x2-x == y2-y == 3 and transparent
989 // pen doesn't draw anything. Should we provide a workaround?
991 ::Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
993 CalcBoundingBox(x
, y
);
994 CalcBoundingBox(x2
, y2
);
997 #if wxUSE_SPLINES && !defined(__WXWINCE__)
998 void wxMSWDCImpl::DoDrawSpline(const wxPointList
*points
)
1000 // quadratic b-spline to cubic bezier spline conversion
1002 // quadratic spline with control points P0,P1,P2
1003 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1005 // bezier spline with control points B0,B1,B2,B3
1006 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1008 // control points of bezier spline calculated from b-spline
1010 // B1 = (2*P1 + P0)/3
1011 // B2 = (2*P1 + P2)/3
1014 WXMICROWIN_CHECK_HDC
1016 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1018 const size_t n_points
= points
->GetCount();
1019 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1021 const size_t n_bezier_points
= n_points
* 3 + 1;
1022 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1023 size_t bezier_pos
= 0;
1024 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1026 wxPointList::compatibility_iterator node
= points
->GetFirst();
1027 wxPoint
*p
= node
->GetData();
1028 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1029 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1031 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1034 node
= node
->GetNext();
1035 p
= node
->GetData();
1039 cx1
= ( x1
+ x2
) / 2;
1040 cy1
= ( y1
+ y2
) / 2;
1041 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1042 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1044 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1048 while ((node
= node
->GetNext()) != NULL
)
1050 while ((node
= node
->GetNext()))
1051 #endif // !wxUSE_STL
1053 p
= (wxPoint
*)node
->GetData();
1058 cx4
= (x1
+ x2
) / 2;
1059 cy4
= (y1
+ y2
) / 2;
1060 // B0 is B3 of previous segment
1062 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1063 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1066 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1067 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1070 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1071 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1077 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1079 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1080 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1082 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1085 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1089 #endif // wxUSE_SPLINES
1091 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1092 void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1095 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1098 WXMICROWIN_CHECK_HDC
1100 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1105 int rx1
= XLOG2DEV(x
+w
/2);
1106 int ry1
= YLOG2DEV(y
+h
/2);
1113 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1114 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1115 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1116 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1118 // Swap start and end positions if the end angle is less than the start angle.
1129 // draw pie with NULL_PEN first and then outline otherwise a line is
1130 // drawn from the start and end points to the centre
1131 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1134 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1135 rx1
, ry1
, rx2
, ry2
);
1139 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1140 rx1
, ry1
-1, rx2
, ry2
-1);
1143 ::SelectObject(GetHdc(), hpenOld
);
1145 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1146 rx1
, ry1
, rx2
, ry2
);
1148 CalcBoundingBox(x
, y
);
1149 CalcBoundingBox(x2
, y2
);
1153 void wxMSWDCImpl::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1155 WXMICROWIN_CHECK_HDC
1157 wxCHECK_RET( icon
.IsOk(), wxT("invalid icon in DrawIcon") );
1160 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1162 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1165 CalcBoundingBox(x
, y
);
1166 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1169 void wxMSWDCImpl::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1171 WXMICROWIN_CHECK_HDC
1173 wxCHECK_RET( bmp
.IsOk(), _T("invalid bitmap in wxMSWDCImpl::DrawBitmap") );
1175 int width
= bmp
.GetWidth(),
1176 height
= bmp
.GetHeight();
1178 HBITMAP hbmpMask
= 0;
1181 HPALETTE oldPal
= 0;
1182 #endif // wxUSE_PALETTE
1184 if ( bmp
.HasAlpha() )
1187 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1189 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1193 SET_STRETCH_BLT_MODE(GetHdc());
1197 wxMask
*mask
= bmp
.GetMask();
1199 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1203 // don't give assert here because this would break existing
1204 // programs - just silently ignore useMask parameter
1211 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1213 // On some systems, MaskBlt succeeds yet is much much slower
1214 // than the wxWidgets fall-back implementation. So we need
1215 // to be able to switch this on and off at runtime.
1217 #if wxUSE_SYSTEM_OPTIONS
1218 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1222 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1223 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1225 wxPalette
*pal
= bmp
.GetPalette();
1226 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1228 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1229 ::RealizePalette(hdcMem
);
1231 #endif // wxUSE_PALETTE
1233 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1236 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1240 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1241 #endif // wxUSE_PALETTE
1243 ::SelectObject(hdcMem
, hOldBitmap
);
1250 // Rather than reproduce wxMSWDCImpl::Blit, let's do it at the wxWin API
1254 memDC
.SelectObjectAsSource(bmp
);
1256 GetOwner()->Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1258 memDC
.SelectObject(wxNullBitmap
);
1261 else // no mask, just use BitBlt()
1264 HDC memdc
= ::CreateCompatibleDC( cdc
);
1265 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1267 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1269 wxTextColoursChanger
textCol(GetHdc(), *this);
1272 wxPalette
*pal
= bmp
.GetPalette();
1273 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1275 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1276 ::RealizePalette(memdc
);
1278 #endif // wxUSE_PALETTE
1280 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1281 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1285 ::SelectPalette(memdc
, oldPal
, FALSE
);
1286 #endif // wxUSE_PALETTE
1288 ::SelectObject( memdc
, hOldBitmap
);
1289 ::DeleteDC( memdc
);
1293 void wxMSWDCImpl::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1295 WXMICROWIN_CHECK_HDC
1297 DrawAnyText(text
, x
, y
);
1299 // update the bounding box
1300 CalcBoundingBox(x
, y
);
1303 GetOwner()->GetTextExtent(text
, &w
, &h
);
1304 CalcBoundingBox(x
+ w
, y
+ h
);
1307 void wxMSWDCImpl::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1309 WXMICROWIN_CHECK_HDC
1311 // prepare for drawing the text
1312 wxTextColoursChanger
textCol(GetHdc(), *this);
1314 wxBkModeChanger
bkMode(GetHdc(), m_backgroundMode
);
1316 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1317 text
.c_str(), text
.length(), NULL
) == 0 )
1319 wxLogLastError(wxT("TextOut"));
1323 void wxMSWDCImpl::DoDrawRotatedText(const wxString
& text
,
1324 wxCoord x
, wxCoord y
,
1327 WXMICROWIN_CHECK_HDC
1329 // we test that we have some font because otherwise we should still use the
1330 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1331 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1332 // font for drawing rotated fonts unfortunately)
1333 if ( (angle
== 0.0) && m_font
.IsOk() )
1335 DoDrawText(text
, x
, y
);
1337 #ifndef __WXMICROWIN__
1340 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1341 // because it's not TrueType and so can't have non zero
1342 // orientation/escapement under Win9x
1343 wxFont font
= m_font
.IsOk() ? m_font
: *wxSWISS_FONT
;
1344 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1346 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1348 wxLogLastError(wxT("GetObject(hfont)"));
1351 // GDI wants the angle in tenth of degree
1352 long angle10
= (long)(angle
* 10);
1353 lf
.lfEscapement
= angle10
;
1354 lf
. lfOrientation
= angle10
;
1356 hfont
= ::CreateFontIndirect(&lf
);
1359 wxLogLastError(wxT("CreateFont"));
1363 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1365 DrawAnyText(text
, x
, y
);
1367 (void)::SelectObject(GetHdc(), hfontOld
);
1368 (void)::DeleteObject(hfont
);
1371 // call the bounding box by adding all four vertices of the rectangle
1372 // containing the text to it (simpler and probably not slower than
1373 // determining which of them is really topmost/leftmost/...)
1375 GetOwner()->GetTextExtent(text
, &w
, &h
);
1377 double rad
= DegToRad(angle
);
1379 // "upper left" and "upper right"
1380 CalcBoundingBox(x
, y
);
1381 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1383 // "bottom left" and "bottom right"
1384 x
+= (wxCoord
)(h
*sin(rad
));
1385 y
+= (wxCoord
)(h
*cos(rad
));
1386 CalcBoundingBox(x
, y
);
1387 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1392 // ---------------------------------------------------------------------------
1394 // ---------------------------------------------------------------------------
1398 void wxMSWDCImpl::DoSelectPalette(bool realize
)
1400 WXMICROWIN_CHECK_HDC
1402 // Set the old object temporarily, in case the assignment deletes an object
1403 // that's not yet selected out.
1406 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1410 if ( m_palette
.IsOk() )
1412 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1413 GetHpaletteOf(m_palette
),
1416 m_oldPalette
= (WXHPALETTE
) oldPal
;
1419 ::RealizePalette(GetHdc());
1423 void wxMSWDCImpl::SetPalette(const wxPalette
& palette
)
1425 if ( palette
.IsOk() )
1427 m_palette
= palette
;
1428 DoSelectPalette(true);
1432 void wxMSWDCImpl::InitializePalette()
1434 if ( wxDisplayDepth() <= 8 )
1436 // look for any window or parent that has a custom palette. If any has
1437 // one then we need to use it in drawing operations
1438 wxWindow
*win
= m_window
->GetAncestorWithCustomPalette();
1440 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1441 if ( m_hasCustomPalette
)
1443 m_palette
= win
->GetPalette();
1445 // turn on MSW translation for this palette
1451 #endif // wxUSE_PALETTE
1453 // SetFont/Pen/Brush() really ask to be implemented as a single template
1454 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1456 void wxMSWDCImpl::SetFont(const wxFont
& font
)
1458 WXMICROWIN_CHECK_HDC
1460 if ( font
== m_font
)
1465 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1466 if ( hfont
== HGDI_ERROR
)
1468 wxLogLastError(_T("SelectObject(font)"));
1473 m_oldFont
= (WXHFONT
)hfont
;
1478 else // invalid font, reset the current font
1482 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1484 wxLogLastError(_T("SelectObject(old font)"));
1490 m_font
= wxNullFont
;
1494 void wxMSWDCImpl::SetPen(const wxPen
& pen
)
1496 WXMICROWIN_CHECK_HDC
1503 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1504 if ( hpen
== HGDI_ERROR
)
1506 wxLogLastError(_T("SelectObject(pen)"));
1511 m_oldPen
= (WXHPEN
)hpen
;
1516 else // invalid pen, reset the current pen
1520 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1522 wxLogLastError(_T("SelectObject(old pen)"));
1532 void wxMSWDCImpl::SetBrush(const wxBrush
& brush
)
1534 WXMICROWIN_CHECK_HDC
1536 if ( brush
== m_brush
)
1541 // we must make sure the brush is aligned with the logical coordinates
1542 // before selecting it
1543 wxBitmap
*stipple
= brush
.GetStipple();
1544 if ( stipple
&& stipple
->IsOk() )
1546 if ( !::SetBrushOrgEx
1549 m_deviceOriginX
% stipple
->GetWidth(),
1550 m_deviceOriginY
% stipple
->GetHeight(),
1551 NULL
// [out] previous brush origin
1554 wxLogLastError(_T("SetBrushOrgEx()"));
1558 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1559 if ( hbrush
== HGDI_ERROR
)
1561 wxLogLastError(_T("SelectObject(brush)"));
1566 m_oldBrush
= (WXHBRUSH
)hbrush
;
1571 else // invalid brush, reset the current brush
1575 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1577 wxLogLastError(_T("SelectObject(old brush)"));
1583 m_brush
= wxNullBrush
;
1587 void wxMSWDCImpl::SetBackground(const wxBrush
& brush
)
1589 WXMICROWIN_CHECK_HDC
1591 m_backgroundBrush
= brush
;
1593 if ( m_backgroundBrush
.IsOk() )
1595 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1599 void wxMSWDCImpl::SetBackgroundMode(int mode
)
1601 WXMICROWIN_CHECK_HDC
1603 m_backgroundMode
= mode
;
1605 // SetBackgroundColour now only refers to text background
1606 // and m_backgroundMode is used there
1609 void wxMSWDCImpl::SetLogicalFunction(wxRasterOperationMode function
)
1611 WXMICROWIN_CHECK_HDC
1613 m_logicalFunction
= function
;
1618 void wxMSWDCImpl::SetRop(WXHDC dc
)
1620 if ( !dc
|| m_logicalFunction
< 0 )
1625 switch (m_logicalFunction
)
1627 case wxCLEAR
: rop
= R2_BLACK
; break;
1628 case wxXOR
: rop
= R2_XORPEN
; break;
1629 case wxINVERT
: rop
= R2_NOT
; break;
1630 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1631 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1632 case wxCOPY
: rop
= R2_COPYPEN
; break;
1633 case wxAND
: rop
= R2_MASKPEN
; break;
1634 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1635 case wxNO_OP
: rop
= R2_NOP
; break;
1636 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1637 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1638 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1639 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1640 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1641 case wxOR
: rop
= R2_MERGEPEN
; break;
1642 case wxSET
: rop
= R2_WHITE
; break;
1644 wxFAIL_MSG( wxS("unknown logical function") );
1648 SetROP2(GetHdc(), rop
);
1651 bool wxMSWDCImpl::StartDoc(const wxString
& WXUNUSED(message
))
1653 // We might be previewing, so return true to let it continue.
1657 void wxMSWDCImpl::EndDoc()
1661 void wxMSWDCImpl::StartPage()
1665 void wxMSWDCImpl::EndPage()
1669 // ---------------------------------------------------------------------------
1671 // ---------------------------------------------------------------------------
1673 wxCoord
wxMSWDCImpl::GetCharHeight() const
1675 WXMICROWIN_CHECK_HDC_RET(0)
1677 TEXTMETRIC lpTextMetric
;
1679 GetTextMetrics(GetHdc(), &lpTextMetric
);
1681 return lpTextMetric
.tmHeight
;
1684 wxCoord
wxMSWDCImpl::GetCharWidth() const
1686 WXMICROWIN_CHECK_HDC_RET(0)
1688 TEXTMETRIC lpTextMetric
;
1690 GetTextMetrics(GetHdc(), &lpTextMetric
);
1692 return lpTextMetric
.tmAveCharWidth
;
1695 void wxMSWDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1696 wxCoord
*descent
, wxCoord
*externalLeading
,
1697 const wxFont
*font
) const
1699 #ifdef __WXMICROWIN__
1704 if (descent
) *descent
= 0;
1705 if (externalLeading
) *externalLeading
= 0;
1708 #endif // __WXMICROWIN__
1713 wxASSERT_MSG( font
->IsOk(), _T("invalid font in wxMSWDCImpl::GetTextExtent") );
1715 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1717 else // don't change the font
1723 const size_t len
= string
.length();
1724 if ( !::GetTextExtentPoint32(GetHdc(), string
.wx_str(), len
, &sizeRect
) )
1726 wxLogLastError(_T("GetTextExtentPoint32()"));
1729 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1730 // the result computed by GetTextExtentPoint32() may be too small as it
1731 // accounts for under/overhang of the first/last character while we want
1732 // just the bounding rect for this string so adjust the width as needed
1733 // (using API not available in 2002 SDKs of WinCE)
1737 const wxChar chFirst
= *string
.begin();
1738 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1740 if ( width
.abcA
< 0 )
1741 sizeRect
.cx
-= width
.abcA
;
1745 const wxChar chLast
= *string
.rbegin();
1746 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1748 //else: we already have the width of the last character
1750 if ( width
.abcC
< 0 )
1751 sizeRect
.cx
-= width
.abcC
;
1753 //else: GetCharABCWidths() failed, not a TrueType font?
1755 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1758 ::GetTextMetrics(GetHdc(), &tm
);
1765 *descent
= tm
.tmDescent
;
1766 if (externalLeading
)
1767 *externalLeading
= tm
.tmExternalLeading
;
1771 ::SelectObject(GetHdc(), hfontOld
);
1776 // Each element of the array will be the width of the string up to and
1777 // including the coresoponding character in text.
1779 bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1781 static int maxLenText
= -1;
1782 static int maxWidth
= -1;
1785 int stlen
= text
.length();
1787 if (maxLenText
== -1)
1789 // Win9x and WinNT+ have different limits
1790 int version
= wxGetOsVersion();
1791 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1792 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1796 widths
.Add(0, stlen
); // fill the array with zeros
1800 if (!::GetTextExtentExPoint(GetHdc(),
1801 text
.c_str(), // string to check
1802 wxMin(stlen
, maxLenText
),
1804 &fit
, // [out] count of chars
1806 &widths
[0], // array to fill
1810 wxLogLastError(wxT("GetTextExtentExPoint"));
1817 void wxMSWDCImpl::RealizeScaleAndOrigin()
1819 // although it may seem wasteful to always use MM_ANISOTROPIC here instead
1820 // of using MM_TEXT if there is no scaling, benchmarking doesn't detect any
1821 // noticeable difference between these mapping modes
1823 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1825 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1826 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1828 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1829 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1831 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1832 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1836 void wxMSWDCImpl::SetMapMode(wxMappingMode mode
)
1838 WXMICROWIN_CHECK_HDC
1840 m_mappingMode
= mode
;
1842 if ( mode
== wxMM_TEXT
)
1845 m_logicalScaleY
= 1.0;
1847 else // need to do some calculations
1849 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1850 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1851 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1852 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1854 if ( (mm_width
== 0) || (mm_height
== 0) )
1856 // we can't calculate mm2pixels[XY] then!
1860 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1861 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1866 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1867 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1871 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1872 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1876 m_logicalScaleX
= mm2pixelsX
;
1877 m_logicalScaleY
= mm2pixelsY
;
1881 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1882 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1886 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1890 ComputeScaleAndOrigin();
1892 RealizeScaleAndOrigin();
1895 void wxMSWDCImpl::SetUserScale(double x
, double y
)
1897 WXMICROWIN_CHECK_HDC
1899 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1902 wxDCImpl::SetUserScale(x
,y
);
1904 RealizeScaleAndOrigin();
1907 void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight
,
1910 WXMICROWIN_CHECK_HDC
1912 int signX
= xLeftRight
? 1 : -1,
1913 signY
= yBottomUp
? -1 : 1;
1915 if (signX
== m_signX
&& signY
== m_signY
)
1918 wxDCImpl::SetAxisOrientation( xLeftRight
, yBottomUp
);
1920 RealizeScaleAndOrigin();
1923 void wxMSWDCImpl::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1925 WXMICROWIN_CHECK_HDC
1927 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1930 wxDCImpl::SetLogicalOrigin( x
, y
);
1932 RealizeScaleAndOrigin();
1935 // For use by wxWidgets only, unless custom units are required.
1936 void wxMSWDCImpl::SetLogicalScale(double x
, double y
)
1938 WXMICROWIN_CHECK_HDC
1940 wxDCImpl::SetLogicalScale(x
,y
);
1943 void wxMSWDCImpl::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1945 WXMICROWIN_CHECK_HDC
1947 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1950 wxDCImpl::SetDeviceOrigin( x
, y
);
1952 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1955 // ---------------------------------------------------------------------------
1957 // ---------------------------------------------------------------------------
1959 bool wxMSWDCImpl::DoBlit(wxCoord dstX
, wxCoord dstY
,
1960 wxCoord dstWidth
, wxCoord dstHeight
,
1962 wxCoord srcX
, wxCoord srcY
,
1963 wxRasterOperationMode rop
, bool useMask
,
1964 wxCoord srcMaskX
, wxCoord srcMaskY
)
1966 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
1969 bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1970 wxCoord dstWidth
, wxCoord dstHeight
,
1972 wxCoord xsrc
, wxCoord ysrc
,
1973 wxCoord srcWidth
, wxCoord srcHeight
,
1974 wxRasterOperationMode rop
, bool useMask
,
1975 wxCoord xsrcMask
, wxCoord ysrcMask
)
1977 wxCHECK_MSG( source
, false, _T("wxMSWDCImpl::Blit(): NULL wxDC pointer") );
1979 WXMICROWIN_CHECK_HDC_RET(false)
1981 wxMSWDCImpl
*implSrc
= wxDynamicCast( source
->GetImpl(), wxMSWDCImpl
);
1984 // TODO: Do we want to be able to blit from other DCs too?
1988 const HDC hdcSrc
= GetHdcOf(*implSrc
);
1990 // if either the source or destination has alpha channel, we must use
1991 // AlphaBlt() as other function don't handle it correctly
1992 const wxBitmap
& bmpSrc
= implSrc
->GetSelectedBitmap();
1993 if ( bmpSrc
.IsOk() && (bmpSrc
.HasAlpha() ||
1994 (m_selectedBitmap
.IsOk() && m_selectedBitmap
.HasAlpha())) )
1996 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
1997 xsrc
, ysrc
, srcWidth
, srcHeight
, hdcSrc
, bmpSrc
) )
2001 wxMask
*mask
= NULL
;
2004 mask
= bmpSrc
.GetMask();
2006 if ( !(bmpSrc
.IsOk() && mask
&& mask
->GetMaskBitmap()) )
2008 // don't give assert here because this would break existing
2009 // programs - just silently ignore useMask parameter
2014 if (xsrcMask
== -1 && ysrcMask
== -1)
2016 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2019 wxTextColoursChanger
textCol(GetHdc(), *this);
2024 case wxXOR
: dwRop
= SRCINVERT
; break;
2025 case wxINVERT
: dwRop
= DSTINVERT
; break;
2026 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2027 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2028 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2029 case wxSET
: dwRop
= WHITENESS
; break;
2030 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2031 case wxAND
: dwRop
= SRCAND
; break;
2032 case wxOR
: dwRop
= SRCPAINT
; break;
2033 case wxEQUIV
: dwRop
= 0x00990066; break;
2034 case wxNAND
: dwRop
= 0x007700E6; break;
2035 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2036 case wxCOPY
: dwRop
= SRCCOPY
; break;
2037 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2038 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2039 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2041 wxFAIL_MSG( wxT("unsupported logical function") );
2045 bool success
= false;
2050 // we want the part of the image corresponding to the mask to be
2051 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2052 // meaning of fg and bg is inverted which corresponds to wxWin notion
2053 // of the mask which is also contrary to the Windows one)
2055 // On some systems, MaskBlt succeeds yet is much much slower
2056 // than the wxWidgets fall-back implementation. So we need
2057 // to be able to switch this on and off at runtime.
2058 #if wxUSE_SYSTEM_OPTIONS
2059 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2062 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2067 xdest
, ydest
, dstWidth
, dstHeight
,
2070 (HBITMAP
)mask
->GetMaskBitmap(),
2072 MAKEROP4(dwRop
, DSTCOPY
)
2080 // Blit bitmap with mask
2083 HBITMAP buffer_bmap
;
2085 #if wxUSE_DC_CACHEING
2086 // create a temp buffer bitmap and DCs to access it and the mask
2087 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, hdcSrc
);
2088 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2090 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2091 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2093 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2094 dstWidth
, dstHeight
);
2096 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2097 #else // !wxUSE_DC_CACHEING
2098 // create a temp buffer bitmap and DCs to access it and the mask
2099 dc_mask
= ::CreateCompatibleDC(hdcSrc
);
2100 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2101 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2102 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2103 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2104 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2106 // copy dest to buffer
2107 if ( !::BitBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2108 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2110 wxLogLastError(wxT("BitBlt"));
2113 SET_STRETCH_BLT_MODE(GetHdc());
2115 // copy src to buffer using selected raster op
2116 if ( !::StretchBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2117 hdcSrc
, xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2119 wxLogLastError(wxT("StretchBlt"));
2122 // set masked area in buffer to BLACK
2124 wxTextColoursChanger
textCol2(GetHdc(), *wxBLACK
, *wxWHITE
);
2125 if ( !::StretchBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2126 dc_mask
, xsrcMask
, ysrcMask
,
2127 srcWidth
, srcHeight
, SRCAND
) )
2129 wxLogLastError(wxT("StretchBlt"));
2132 // set unmasked area in dest to BLACK
2133 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2134 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2135 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2136 dc_mask
, xsrcMask
, ysrcMask
,
2137 srcWidth
, srcHeight
, SRCAND
) )
2139 wxLogLastError(wxT("StretchBlt"));
2141 } // restore the original text and background colours
2143 // OR buffer to dest
2144 success
= ::BitBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2145 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2148 wxLogLastError(wxT("BitBlt"));
2151 // tidy up temporary DCs and bitmap
2152 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2153 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2155 #if !wxUSE_DC_CACHEING
2157 ::DeleteDC(dc_mask
);
2158 ::DeleteDC(dc_buffer
);
2159 ::DeleteObject(buffer_bmap
);
2164 else // no mask, just BitBlt() it
2166 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2167 // use StretchBlt() if available and finally fall back to BitBlt()
2169 // FIXME: use appropriate WinCE functions
2171 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2172 if ( bmpSrc
.IsOk() && (caps
& RC_STRETCHDIB
) )
2177 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2179 &ds
) == sizeof(ds
) )
2181 SET_STRETCH_BLT_MODE(GetHdc());
2183 // Figure out what co-ordinate system we're supposed to specify
2185 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2189 ysrc
= hDIB
- (ysrc
+ srcHeight
);
2192 if ( ::StretchDIBits(GetHdc(),
2194 dstWidth
, dstHeight
,
2196 srcWidth
, srcHeight
,
2198 (LPBITMAPINFO
)&ds
.dsBmih
,
2201 ) == (int)GDI_ERROR
)
2203 // On Win9x this API fails most (all?) of the time, so
2204 // logging it becomes quite distracting. Since it falls
2205 // back to the code below this is not really serious, so
2207 //wxLogLastError(wxT("StretchDIBits"));
2216 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2220 SET_STRETCH_BLT_MODE(GetHdc());
2225 xdest
, ydest
, dstWidth
, dstHeight
,
2227 xsrc
, ysrc
, srcWidth
, srcHeight
,
2231 wxLogLastError(_T("StretchBlt"));
2241 if ( !::BitBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2242 hdcSrc
, xsrc
, ysrc
, dwRop
) )
2244 wxLogLastError(_T("BitBlt"));
2256 void wxMSWDCImpl::GetDeviceSize(int *width
, int *height
) const
2258 WXMICROWIN_CHECK_HDC
2261 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2263 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2266 void wxMSWDCImpl::DoGetSizeMM(int *w
, int *h
) const
2268 WXMICROWIN_CHECK_HDC
2270 // if we implement it in terms of DoGetSize() instead of directly using the
2271 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2272 // will also work for wxWindowDC and wxClientDC even though their size is
2273 // not the same as the total size of the screen
2274 int wPixels
, hPixels
;
2275 DoGetSize(&wPixels
, &hPixels
);
2279 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2281 wxCHECK_RET( wTotal
, _T("0 width device?") );
2283 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2288 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2290 wxCHECK_RET( hTotal
, _T("0 height device?") );
2292 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2296 wxSize
wxMSWDCImpl::GetPPI() const
2298 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2300 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2301 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2303 return wxSize(x
, y
);
2306 // ----------------------------------------------------------------------------
2308 // ----------------------------------------------------------------------------
2310 #if wxUSE_DC_CACHEING
2313 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2314 * improve it in due course, either using arrays, or simply storing pointers to one
2315 * entry for the bitmap, and two for the DCs. -- JACS
2318 wxObjectList
wxMSWDCImpl::sm_bitmapCache
;
2319 wxObjectList
wxMSWDCImpl::sm_dcCache
;
2321 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2330 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2339 wxDCCacheEntry::~wxDCCacheEntry()
2342 ::DeleteObject((HBITMAP
) m_bitmap
);
2344 ::DeleteDC((HDC
) m_dc
);
2347 wxDCCacheEntry
* wxMSWDCImpl::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2349 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2350 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2353 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2355 if (entry
->m_depth
== depth
)
2357 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2359 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2360 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2361 if ( !entry
->m_bitmap
)
2363 wxLogLastError(wxT("CreateCompatibleBitmap"));
2365 entry
->m_width
= w
; entry
->m_height
= h
;
2371 node
= node
->GetNext();
2373 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2376 wxLogLastError(wxT("CreateCompatibleBitmap"));
2378 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2379 AddToBitmapCache(entry
);
2383 wxDCCacheEntry
* wxMSWDCImpl::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2385 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2386 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2389 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2391 // Don't return the same one as we already have
2392 if (!notThis
|| (notThis
!= entry
))
2394 if (entry
->m_depth
== depth
)
2400 node
= node
->GetNext();
2402 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2405 wxLogLastError(wxT("CreateCompatibleDC"));
2407 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2408 AddToDCCache(entry
);
2412 void wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry
* entry
)
2414 sm_bitmapCache
.Append(entry
);
2417 void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry
* entry
)
2419 sm_dcCache
.Append(entry
);
2422 void wxMSWDCImpl::ClearCache()
2424 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2425 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2428 // Clean up cache at app exit
2429 class wxDCModule
: public wxModule
2432 virtual bool OnInit() { return true; }
2433 virtual void OnExit() { wxMSWDCImpl::ClearCache(); }
2436 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2439 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2441 #endif // wxUSE_DC_CACHEING
2443 // ----------------------------------------------------------------------------
2444 // alpha channel support
2445 // ----------------------------------------------------------------------------
2447 static bool AlphaBlt(HDC hdcDst
,
2448 int x
, int y
, int dstWidth
, int dstHeight
,
2450 int srcWidth
, int srcHeight
,
2452 const wxBitmap
& bmp
)
2454 wxASSERT_MSG( bmp
.IsOk() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2455 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2457 // do we have AlphaBlend() and company in the headers?
2458 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2459 // yes, now try to see if we have it during run-time
2460 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2461 HDC
,int,int,int,int,
2465 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2466 if ( pfnAlphaBlend
)
2469 bf
.BlendOp
= AC_SRC_OVER
;
2471 bf
.SourceConstantAlpha
= 0xff;
2472 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2474 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2475 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2478 // skip wxAlphaBlend() call below
2482 wxLogLastError(_T("AlphaBlend"));
2485 wxUnusedVar(hdcSrc
);
2486 #endif // defined(AC_SRC_OVER)
2488 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2490 #ifdef wxHAS_RAW_BITMAP
2491 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2494 #else // !wxHAS_RAW_BITMAP
2495 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2496 // alpha but at least something will be shown like this)
2499 #endif // wxHAS_RAW_BITMAP/!wxHAS_RAW_BITMAP
2503 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2504 #ifdef wxHAS_RAW_BITMAP
2507 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2508 int dstWidth
, int dstHeight
,
2510 int srcWidth
, int srcHeight
,
2511 const wxBitmap
& bmpSrc
)
2513 // get the destination DC pixels
2514 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2516 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2518 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2520 wxLogLastError(_T("BitBlt"));
2523 // combine them with the source bitmap using alpha
2524 wxAlphaPixelData
dataDst(bmpDst
),
2525 dataSrc((wxBitmap
&)bmpSrc
);
2527 wxCHECK_RET( dataDst
&& dataSrc
,
2528 _T("failed to get raw data in wxAlphaBlend") );
2530 wxAlphaPixelData::Iterator
pDst(dataDst
),
2534 for ( int y
= 0; y
< dstHeight
; y
++ )
2536 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2538 for ( int x
= 0; x
< dstWidth
; x
++ )
2540 // source is point sampled, Alpha StretchBlit is ugly on Win95
2541 // (but does not impact performance)
2542 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2544 // note that source bitmap uses premultiplied alpha (as required by
2545 // the real AlphaBlend)
2546 const unsigned beta
= 255 - pSrc
.Alpha();
2548 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2549 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2550 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2555 pDst
= pDstRowStart
;
2556 pDst
.OffsetY(dataDst
, 1);
2559 // and finally blit them back to the destination DC
2560 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2562 wxLogLastError(_T("BitBlt"));
2566 #endif // wxHAS_RAW_BITMAP
2568 void wxMSWDCImpl::DoGradientFillLinear (const wxRect
& rect
,
2569 const wxColour
& initialColour
,
2570 const wxColour
& destColour
,
2571 wxDirection nDirection
)
2573 // use native function if we have compile-time support it and can load it
2574 // during run-time (linking to it statically would make the program
2575 // unusable on earlier Windows versions)
2576 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2578 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2579 static GradientFill_t pfnGradientFill
=
2580 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2582 if ( pfnGradientFill
)
2584 GRADIENT_RECT grect
;
2585 grect
.UpperLeft
= 0;
2586 grect
.LowerRight
= 1;
2588 // invert colours direction if not filling from left-to-right or
2590 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2592 // one vertex for upper left and one for upper-right
2593 TRIVERTEX vertices
[2];
2595 vertices
[0].x
= rect
.GetLeft();
2596 vertices
[0].y
= rect
.GetTop();
2597 vertices
[1].x
= rect
.GetRight()+1;
2598 vertices
[1].y
= rect
.GetBottom()+1;
2600 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2601 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2602 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2603 vertices
[firstVertex
].Alpha
= 0;
2604 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2605 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2606 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2607 vertices
[1 - firstVertex
].Alpha
= 0;
2609 if ( (*pfnGradientFill
)
2616 nDirection
== wxWEST
|| nDirection
== wxEAST
2617 ? GRADIENT_FILL_RECT_H
2618 : GRADIENT_FILL_RECT_V
2621 // skip call of the base class version below
2625 wxLogLastError(_T("GradientFill"));
2627 #endif // wxUSE_DYNLIB_CLASS
2629 wxDCImpl::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2632 #if wxUSE_DYNLIB_CLASS
2634 static DWORD
wxGetDCLayout(HDC hdc
)
2636 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2638 wxDL_INIT_FUNC(s_pfn
, GetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2640 return s_pfnGetLayout
? s_pfnGetLayout(hdc
) : (DWORD
)-1;
2643 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2645 DWORD layout
= wxGetDCLayout(GetHdc());
2647 if ( layout
== (DWORD
)-1 )
2648 return wxLayout_Default
;
2650 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2653 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir
)
2655 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2657 wxDL_INIT_FUNC(s_pfn
, SetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2658 if ( !s_pfnSetLayout
)
2661 if ( dir
== wxLayout_Default
)
2663 dir
= wxTheApp
->GetLayoutDirection();
2664 if ( dir
== wxLayout_Default
)
2668 DWORD layout
= wxGetDCLayout(GetHdc());
2669 if ( dir
== wxLayout_RightToLeft
)
2670 layout
|= LAYOUT_RTL
;
2672 layout
&= ~LAYOUT_RTL
;
2674 s_pfnSetLayout(GetHdc(), layout
);
2677 #else // !wxUSE_DYNLIB_CLASS
2679 // we can't provide RTL support without dynamic loading, so stub it out
2680 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2682 return wxLayout_Default
;
2685 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection
WXUNUSED(dir
))
2689 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS