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"
33 #include "wx/dialog.h"
35 #include "wx/bitmap.h"
36 #include "wx/dcmemory.h"
39 #include "wx/dcprint.h"
40 #include "wx/module.h"
43 #include "wx/sysopt.h"
44 #include "wx/dynlib.h"
46 #ifdef wxHAVE_RAW_BITMAP
47 #include "wx/rawbmp.h"
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(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 dstWidth
, int dstHeight
,
135 int srcWidth
, int srcHeight
,
137 const wxBitmap
& bmp
);
139 #ifdef wxHAVE_RAW_BITMAP
141 // our (limited) AlphaBlend() replacement for Windows versions not providing it
143 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
144 int dstWidth
, int dstHeight
,
146 int srcWidth
, int srcHeight
,
147 const wxBitmap
& bmpSrc
);
149 #endif // wxHAVE_RAW_BITMAP
151 // ----------------------------------------------------------------------------
153 // ----------------------------------------------------------------------------
155 // instead of duplicating the same code which sets and then restores text
156 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
157 // encapsulate this in a small helper class
159 // wxColourChanger: changes the text colours in the ctor if required and
160 // restores them in the dtor
161 class wxColourChanger
164 wxColourChanger(wxDC
& dc
);
170 COLORREF m_colFgOld
, m_colBgOld
;
174 DECLARE_NO_COPY_CLASS(wxColourChanger
)
177 // this class saves the old stretch blit mode during its life time
178 class StretchBltModeChanger
181 StretchBltModeChanger(HDC hdc
,
182 int WXUNUSED_IN_WINCE(mode
))
186 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
188 wxLogLastError(_T("SetStretchBltMode"));
192 ~StretchBltModeChanger()
195 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
196 wxLogLastError(_T("SetStretchBltMode"));
205 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
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
;
242 wxDynamicLibrary m_dll
;
243 const wxChar
*m_dllName
;
246 static wxOnceOnlyDLLLoader
wxGDI32DLL(_T("gdi32"));
247 static wxOnceOnlyDLLLoader
wxMSIMG32DLL(_T("msimg32"));
249 #endif // wxUSE_DYNLIB_CLASS
251 // ===========================================================================
253 // ===========================================================================
255 // ----------------------------------------------------------------------------
257 // ----------------------------------------------------------------------------
259 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
261 const wxBrush
& brush
= dc
.GetBrush();
262 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
264 HDC hdc
= GetHdcOf(dc
);
265 m_colFgOld
= ::GetTextColor(hdc
);
266 m_colBgOld
= ::GetBkColor(hdc
);
268 // note that Windows convention is opposite to wxWidgets one, this is
269 // why text colour becomes the background one and vice versa
270 const wxColour
& colFg
= dc
.GetTextForeground();
273 ::SetBkColor(hdc
, colFg
.GetPixel());
276 const wxColour
& colBg
= dc
.GetTextBackground();
279 ::SetTextColor(hdc
, colBg
.GetPixel());
283 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
286 // flag which telsl us to undo changes in the dtor
291 // nothing done, nothing to undo
296 wxColourChanger::~wxColourChanger()
300 // restore the colours we changed
301 HDC hdc
= GetHdcOf(m_dc
);
303 ::SetBkMode(hdc
, TRANSPARENT
);
304 ::SetTextColor(hdc
, m_colFgOld
);
305 ::SetBkColor(hdc
, m_colBgOld
);
309 // ---------------------------------------------------------------------------
311 // ---------------------------------------------------------------------------
317 SelectOldObjects(m_hDC
);
319 // if we own the HDC, we delete it, otherwise we just release it
323 ::DeleteDC(GetHdc());
325 else // we don't own our HDC
329 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
333 // Must have been a wxScreenDC
334 ::ReleaseDC((HWND
) NULL
, GetHdc());
340 // This will select current objects out of the DC,
341 // which is what you have to do before deleting the
343 void wxDC::SelectOldObjects(WXHDC dc
)
349 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
351 if (m_selectedBitmap
.Ok())
353 m_selectedBitmap
.SetSelectedInto(NULL
);
360 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
365 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
370 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
377 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
380 #endif // wxUSE_PALETTE
383 m_brush
= wxNullBrush
;
386 m_palette
= wxNullPalette
;
387 #endif // wxUSE_PALETTE
389 m_backgroundBrush
= wxNullBrush
;
390 m_selectedBitmap
= wxNullBitmap
;
393 // ---------------------------------------------------------------------------
395 // ---------------------------------------------------------------------------
397 void wxDC::UpdateClipBox()
402 ::GetClipBox(GetHdc(), &rect
);
404 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
405 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
406 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
407 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
411 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
413 // check if we should try to retrieve the clipping region possibly not set
414 // by our SetClippingRegion() but preset by Windows:this can only happen
415 // when we're associated with an existing HDC usign SetHDC(), see there
416 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
418 wxDC
*self
= wxConstCast(this, wxDC
);
419 self
->UpdateClipBox();
421 if ( !m_clipX1
&& !m_clipX2
)
422 self
->m_clipping
= false;
425 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
428 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
429 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
431 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
435 // note that we combine the new clipping region with the existing one: this
436 // is compatible with what the other ports do and is the documented
437 // behaviour now (starting with 2.3.3)
438 #if defined(__WXWINCE__)
440 if ( !::GetClipBox(GetHdc(), &rectClip
) )
443 // GetClipBox returns logical coordinates, so transform to device
444 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
445 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
446 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
447 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
449 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
450 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
451 rectClip
.right
, rectClip
.bottom
);
453 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
455 ::SelectClipRgn(GetHdc(), hrgnDest
);
458 ::DeleteObject(hrgnClipOld
);
459 ::DeleteObject(hrgnDest
);
461 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
463 wxLogLastError(_T("ExtSelectClipRgn"));
467 #endif // WinCE/!WinCE
474 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
476 // the region coords are always the device ones, so do the translation
479 // FIXME: possible +/-1 error here, to check!
480 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
482 LogicalToDeviceX(x
+ w
),
483 LogicalToDeviceY(y
+ h
));
486 wxLogLastError(_T("CreateRectRgn"));
490 SetClippingHrgn((WXHRGN
)hrgn
);
492 ::DeleteObject(hrgn
);
496 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
498 SetClippingHrgn(region
.GetHRGN());
501 void wxDC::DestroyClippingRegion()
505 if (m_clipping
&& m_hDC
)
508 // On a PocketPC device (not necessarily emulator), resetting
509 // the clip region as per the old method causes bad display
510 // problems. In fact setting a null region is probably OK
511 // on desktop WIN32 also, since the WIN32 docs imply that the user
512 // clipping region is independent from the paint clipping region.
513 ::SelectClipRgn(GetHdc(), 0);
515 // TODO: this should restore the previous clipping region,
516 // so that OnPaint processing works correctly, and the update
517 // clipping region doesn't get destroyed after the first
518 // DestroyClippingRegion.
519 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
520 ::SelectClipRgn(GetHdc(), rgn
);
525 wxDCBase::DestroyClippingRegion();
528 // ---------------------------------------------------------------------------
529 // query capabilities
530 // ---------------------------------------------------------------------------
532 bool wxDC::CanDrawBitmap() const
537 bool wxDC::CanGetTextExtent() const
539 #ifdef __WXMICROWIN__
540 // TODO Extend MicroWindows' GetDeviceCaps function
543 // What sort of display is it?
544 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
546 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
550 int wxDC::GetDepth() const
552 WXMICROWIN_CHECK_HDC_RET(16)
554 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
557 // ---------------------------------------------------------------------------
559 // ---------------------------------------------------------------------------
568 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
572 // No, I think we should simply ignore this if printing on e.g.
574 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
575 if (!m_selectedBitmap
.Ok())
578 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
579 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
580 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
584 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
587 DWORD colour
= ::GetBkColor(GetHdc());
588 HBRUSH brush
= ::CreateSolidBrush(colour
);
589 ::FillRect(GetHdc(), &rect
, brush
);
590 ::DeleteObject(brush
);
592 RealizeScaleAndOrigin();
595 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
596 wxCoord
WXUNUSED_IN_WINCE(y
),
597 const wxColour
& WXUNUSED_IN_WINCE(col
),
598 int WXUNUSED_IN_WINCE(style
))
603 WXMICROWIN_CHECK_HDC_RET(false)
605 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
607 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
608 : FLOODFILLBORDER
) ) ;
611 // quoting from the MSDN docs:
613 // Following are some of the reasons this function might fail:
615 // * The filling could not be completed.
616 // * The specified point has the boundary color specified by the
617 // crColor parameter (if FLOODFILLBORDER was requested).
618 // * The specified point does not have the color specified by
619 // crColor (if FLOODFILLSURFACE was requested)
620 // * The point is outside the clipping region that is, it is not
621 // visible on the device.
623 wxLogLastError(wxT("ExtFloodFill"));
626 CalcBoundingBox(x
, y
);
632 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
634 WXMICROWIN_CHECK_HDC_RET(false)
636 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
638 // get the color of the pixel
639 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
641 wxRGBToColour(*col
, pixelcolor
);
646 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
650 wxCoord x1
= x
-VIEWPORT_EXTENT
;
651 wxCoord y1
= y
-VIEWPORT_EXTENT
;
652 wxCoord x2
= x
+VIEWPORT_EXTENT
;
653 wxCoord y2
= y
+VIEWPORT_EXTENT
;
655 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
656 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
658 CalcBoundingBox(x1
, y1
);
659 CalcBoundingBox(x2
, y2
);
662 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
666 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
668 CalcBoundingBox(x1
, y1
);
669 CalcBoundingBox(x2
, y2
);
672 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
673 // and ending at (x2, y2)
674 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
675 wxCoord x2
, wxCoord y2
,
676 wxCoord xc
, wxCoord yc
)
679 // Slower emulation since WinCE doesn't support Pie and Arc
680 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
681 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
682 if( y1
>yc
) sa
= -sa
; // below center
683 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
684 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
689 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
693 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
694 wxCoord r
= (wxCoord
)radius
;
696 // treat the special case of full circle separately
697 if ( x1
== x2
&& y1
== y2
)
699 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
703 wxCoord xx1
= XLOG2DEV(x1
);
704 wxCoord yy1
= YLOG2DEV(y1
);
705 wxCoord xx2
= XLOG2DEV(x2
);
706 wxCoord yy2
= YLOG2DEV(y2
);
707 wxCoord xxc
= XLOG2DEV(xc
);
708 wxCoord yyc
= YLOG2DEV(yc
);
709 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
711 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
712 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
713 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
714 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
716 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
718 // Have to add 1 to bottom-right corner of rectangle
719 // to make semi-circles look right (crooked line otherwise).
720 // Unfortunately this is not a reliable method, depends
721 // on the size of shape.
722 // TODO: figure out why this happens!
723 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
727 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
730 CalcBoundingBox(xc
- r
, yc
- r
);
731 CalcBoundingBox(xc
+ r
, yc
+ r
);
735 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
736 wxCoord width
, wxCoord height
)
738 // cases when we don't have DrawFrameControl()
739 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
740 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
742 wxCoord x2
= x1
+ width
,
752 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
754 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
757 CalcBoundingBox(x1
, y1
);
758 CalcBoundingBox(x2
, y2
);
759 #endif // Microwin/Normal
762 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
766 COLORREF color
= 0x00ffffff;
769 color
= m_pen
.GetColour().GetPixel();
772 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
774 CalcBoundingBox(x
, y
);
777 void wxDC::DoDrawPolygon(int n
,
781 int WXUNUSED_IN_WINCE(fillStyle
))
785 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
787 // Do things less efficiently if we have offsets
788 if (xoffset
!= 0 || yoffset
!= 0)
790 POINT
*cpoints
= new POINT
[n
];
792 for (i
= 0; i
< n
; i
++)
794 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
795 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
797 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
800 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
802 (void)Polygon(GetHdc(), cpoints
, n
);
804 SetPolyFillMode(GetHdc(),prev
);
811 for (i
= 0; i
< n
; i
++)
812 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
815 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
817 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
819 SetPolyFillMode(GetHdc(),prev
);
825 wxDC::DoDrawPolyPolygon(int n
,
833 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
837 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
839 for (i
= cnt
= 0; i
< n
; i
++)
842 // Do things less efficiently if we have offsets
843 if (xoffset
!= 0 || yoffset
!= 0)
845 POINT
*cpoints
= new POINT
[cnt
];
846 for (i
= 0; i
< cnt
; i
++)
848 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
849 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
851 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
854 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
856 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
858 SetPolyFillMode(GetHdc(),prev
);
864 for (i
= 0; i
< cnt
; i
++)
865 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
868 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
870 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
872 SetPolyFillMode(GetHdc(),prev
);
879 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
883 // Do things less efficiently if we have offsets
884 if (xoffset
!= 0 || yoffset
!= 0)
886 POINT
*cpoints
= new POINT
[n
];
888 for (i
= 0; i
< n
; i
++)
890 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
891 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
893 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
895 (void)Polyline(GetHdc(), cpoints
, n
);
901 for (i
= 0; i
< n
; i
++)
902 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
904 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
908 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
912 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
914 wxCoord x2
= x
+ width
;
915 wxCoord y2
= y
+ height
;
917 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
920 rect
.left
= XLOG2DEV(x
);
921 rect
.top
= YLOG2DEV(y
);
922 rect
.right
= XLOG2DEV(x2
);
923 rect
.bottom
= YLOG2DEV(y2
);
924 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
928 // Windows draws the filled rectangles without outline (i.e. drawn with a
929 // transparent pen) one pixel smaller in both directions and we want them
930 // to have the same size regardless of which pen is used - adjust
932 // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
933 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
935 // Apparently not needed for WinCE (see e.g. Life! demo)
942 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
946 CalcBoundingBox(x
, y
);
947 CalcBoundingBox(x2
, y2
);
950 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
954 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
956 // Now, a negative radius value is interpreted to mean
957 // 'the proportion of the smallest X or Y dimension'
961 double smallest
= (width
< height
) ? width
: height
;
962 radius
= (- radius
* smallest
);
965 wxCoord x2
= (x
+width
);
966 wxCoord y2
= (y
+height
);
968 // Windows draws the filled rectangles without outline (i.e. drawn with a
969 // transparent pen) one pixel smaller in both directions and we want them
970 // to have the same size regardless of which pen is used - adjust
971 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
977 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
978 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
980 CalcBoundingBox(x
, y
);
981 CalcBoundingBox(x2
, y2
);
984 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
988 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
990 wxCoord x2
= (x
+width
);
991 wxCoord y2
= (y
+height
);
993 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
995 CalcBoundingBox(x
, y
);
996 CalcBoundingBox(x2
, y2
);
1000 void wxDC::DoDrawSpline(const wxPointList
*points
)
1003 // WinCE does not support ::PolyBezier so use generic version
1004 wxDCBase::DoDrawSpline(points
);
1006 // quadratic b-spline to cubic bezier spline conversion
1008 // quadratic spline with control points P0,P1,P2
1009 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1011 // bezier spline with control points B0,B1,B2,B3
1012 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1014 // control points of bezier spline calculated from b-spline
1016 // B1 = (2*P1 + P0)/3
1017 // B2 = (2*P1 + P2)/3
1020 WXMICROWIN_CHECK_HDC
1022 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1024 const size_t n_points
= points
->GetCount();
1025 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1027 const size_t n_bezier_points
= n_points
* 3 + 1;
1028 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1029 size_t bezier_pos
= 0;
1030 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1032 wxPointList::compatibility_iterator node
= points
->GetFirst();
1033 wxPoint
*p
= node
->GetData();
1034 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1035 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1037 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1040 node
= node
->GetNext();
1041 p
= node
->GetData();
1045 cx1
= ( x1
+ x2
) / 2;
1046 cy1
= ( y1
+ y2
) / 2;
1047 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1048 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1050 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1054 while ((node
= node
->GetNext()) != NULL
)
1056 while ((node
= node
->GetNext()))
1057 #endif // !wxUSE_STL
1059 p
= (wxPoint
*)node
->GetData();
1064 cx4
= (x1
+ x2
) / 2;
1065 cy4
= (y1
+ y2
) / 2;
1066 // B0 is B3 of previous segment
1068 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1069 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1072 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1073 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1076 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1077 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1083 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1085 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1086 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1088 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1091 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1098 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1099 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1102 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1105 WXMICROWIN_CHECK_HDC
1107 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1112 int rx1
= XLOG2DEV(x
+w
/2);
1113 int ry1
= YLOG2DEV(y
+h
/2);
1120 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1121 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1122 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1123 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1125 // Swap start and end positions if the end angle is less than the start angle.
1136 // draw pie with NULL_PEN first and then outline otherwise a line is
1137 // drawn from the start and end points to the centre
1138 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1141 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1142 rx1
, ry1
, rx2
, ry2
);
1146 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1147 rx1
, ry1
-1, rx2
, ry2
-1);
1150 ::SelectObject(GetHdc(), hpenOld
);
1152 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1153 rx1
, ry1
, rx2
, ry2
);
1155 CalcBoundingBox(x
, y
);
1156 CalcBoundingBox(x2
, y2
);
1160 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1162 WXMICROWIN_CHECK_HDC
1164 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1167 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1169 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1172 CalcBoundingBox(x
, y
);
1173 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1176 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1178 WXMICROWIN_CHECK_HDC
1180 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1182 int width
= bmp
.GetWidth(),
1183 height
= bmp
.GetHeight();
1185 HBITMAP hbmpMask
= 0;
1188 HPALETTE oldPal
= 0;
1189 #endif // wxUSE_PALETTE
1191 if ( bmp
.HasAlpha() )
1194 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1196 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1202 wxMask
*mask
= bmp
.GetMask();
1204 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1208 // don't give assert here because this would break existing
1209 // programs - just silently ignore useMask parameter
1216 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1218 // On some systems, MaskBlt succeeds yet is much much slower
1219 // than the wxWidgets fall-back implementation. So we need
1220 // to be able to switch this on and off at runtime.
1222 #if wxUSE_SYSTEM_OPTIONS
1223 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1227 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1228 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1230 wxPalette
*pal
= bmp
.GetPalette();
1231 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1233 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1234 ::RealizePalette(hdcMem
);
1236 #endif // wxUSE_PALETTE
1238 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1241 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1245 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1246 #endif // wxUSE_PALETTE
1248 ::SelectObject(hdcMem
, hOldBitmap
);
1255 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1259 memDC
.SelectObjectAsSource(bmp
);
1261 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1263 memDC
.SelectObject(wxNullBitmap
);
1266 else // no mask, just use BitBlt()
1269 HDC memdc
= ::CreateCompatibleDC( cdc
);
1270 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1272 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1274 COLORREF old_textground
= ::GetTextColor(GetHdc());
1275 COLORREF old_background
= ::GetBkColor(GetHdc());
1276 if (m_textForegroundColour
.Ok())
1278 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1280 if (m_textBackgroundColour
.Ok())
1282 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1286 wxPalette
*pal
= bmp
.GetPalette();
1287 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1289 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1290 ::RealizePalette(memdc
);
1292 #endif // wxUSE_PALETTE
1294 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1295 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1299 ::SelectPalette(memdc
, oldPal
, FALSE
);
1300 #endif // wxUSE_PALETTE
1302 ::SelectObject( memdc
, hOldBitmap
);
1303 ::DeleteDC( memdc
);
1305 ::SetTextColor(GetHdc(), old_textground
);
1306 ::SetBkColor(GetHdc(), old_background
);
1310 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1312 WXMICROWIN_CHECK_HDC
1314 DrawAnyText(text
, x
, y
);
1316 // update the bounding box
1317 CalcBoundingBox(x
, y
);
1320 GetTextExtent(text
, &w
, &h
);
1321 CalcBoundingBox(x
+ w
, y
+ h
);
1324 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1326 WXMICROWIN_CHECK_HDC
1328 // prepare for drawing the text
1329 if ( m_textForegroundColour
.Ok() )
1330 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1332 DWORD old_background
= 0;
1333 if ( m_textBackgroundColour
.Ok() )
1335 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1338 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1342 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1343 text
.c_str(), text
.length(), NULL
) == 0 )
1345 wxLogLastError(wxT("TextOut"));
1348 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1349 text
.c_str(), text
.length()) == 0 )
1351 wxLogLastError(wxT("TextOut"));
1355 // restore the old parameters (text foreground colour may be left because
1356 // it never is set to anything else, but background should remain
1357 // transparent even if we just drew an opaque string)
1358 if ( m_textBackgroundColour
.Ok() )
1359 (void)SetBkColor(GetHdc(), old_background
);
1361 SetBkMode(GetHdc(), TRANSPARENT
);
1364 void wxDC::DoDrawRotatedText(const wxString
& text
,
1365 wxCoord x
, wxCoord y
,
1368 WXMICROWIN_CHECK_HDC
1370 // we test that we have some font because otherwise we should still use the
1371 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1372 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1373 // font for drawing rotated fonts unfortunately)
1374 if ( (angle
== 0.0) && m_font
.Ok() )
1376 DoDrawText(text
, x
, y
);
1378 #ifndef __WXMICROWIN__
1381 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1382 // because it's not TrueType and so can't have non zero
1383 // orientation/escapement under Win9x
1384 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1385 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1387 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1389 wxLogLastError(wxT("GetObject(hfont)"));
1392 // GDI wants the angle in tenth of degree
1393 long angle10
= (long)(angle
* 10);
1394 lf
.lfEscapement
= angle10
;
1395 lf
. lfOrientation
= angle10
;
1397 hfont
= ::CreateFontIndirect(&lf
);
1400 wxLogLastError(wxT("CreateFont"));
1404 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1406 DrawAnyText(text
, x
, y
);
1408 (void)::SelectObject(GetHdc(), hfontOld
);
1409 (void)::DeleteObject(hfont
);
1412 // call the bounding box by adding all four vertices of the rectangle
1413 // containing the text to it (simpler and probably not slower than
1414 // determining which of them is really topmost/leftmost/...)
1416 GetTextExtent(text
, &w
, &h
);
1418 double rad
= DegToRad(angle
);
1420 // "upper left" and "upper right"
1421 CalcBoundingBox(x
, y
);
1422 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1424 // "bottom left" and "bottom right"
1425 x
+= (wxCoord
)(h
*sin(rad
));
1426 y
+= (wxCoord
)(h
*cos(rad
));
1427 CalcBoundingBox(x
, y
);
1428 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1433 // ---------------------------------------------------------------------------
1435 // ---------------------------------------------------------------------------
1439 void wxDC::DoSelectPalette(bool realize
)
1441 WXMICROWIN_CHECK_HDC
1443 // Set the old object temporarily, in case the assignment deletes an object
1444 // that's not yet selected out.
1447 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1451 if ( m_palette
.Ok() )
1453 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1454 GetHpaletteOf(m_palette
),
1457 m_oldPalette
= (WXHPALETTE
) oldPal
;
1460 ::RealizePalette(GetHdc());
1464 void wxDC::SetPalette(const wxPalette
& palette
)
1468 m_palette
= palette
;
1469 DoSelectPalette(true);
1473 void wxDC::InitializePalette()
1475 if ( wxDisplayDepth() <= 8 )
1477 // look for any window or parent that has a custom palette. If any has
1478 // one then we need to use it in drawing operations
1479 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1481 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1482 if ( m_hasCustomPalette
)
1484 m_palette
= win
->GetPalette();
1486 // turn on MSW translation for this palette
1492 #endif // wxUSE_PALETTE
1494 // SetFont/Pen/Brush() really ask to be implemented as a single template
1495 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1497 void wxDC::SetFont(const wxFont
& font
)
1499 WXMICROWIN_CHECK_HDC
1501 if ( font
== m_font
)
1506 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1507 if ( hfont
== HGDI_ERROR
)
1509 wxLogLastError(_T("SelectObject(font)"));
1514 m_oldFont
= (WXHFONT
)hfont
;
1519 else // invalid font, reset the current font
1523 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1525 wxLogLastError(_T("SelectObject(old font)"));
1531 m_font
= wxNullFont
;
1535 void wxDC::SetPen(const wxPen
& pen
)
1537 WXMICROWIN_CHECK_HDC
1544 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1545 if ( hpen
== HGDI_ERROR
)
1547 wxLogLastError(_T("SelectObject(pen)"));
1552 m_oldPen
= (WXHPEN
)hpen
;
1557 else // invalid pen, reset the current pen
1561 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1563 wxLogLastError(_T("SelectObject(old pen)"));
1573 void wxDC::SetBrush(const wxBrush
& brush
)
1575 WXMICROWIN_CHECK_HDC
1577 if ( brush
== m_brush
)
1582 // we must make sure the brush is aligned with the logical coordinates
1583 // before selecting it
1584 wxBitmap
*stipple
= brush
.GetStipple();
1585 if ( stipple
&& stipple
->Ok() )
1587 if ( !::SetBrushOrgEx
1590 m_deviceOriginX
% stipple
->GetWidth(),
1591 m_deviceOriginY
% stipple
->GetHeight(),
1592 NULL
// [out] previous brush origin
1595 wxLogLastError(_T("SetBrushOrgEx()"));
1599 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1600 if ( hbrush
== HGDI_ERROR
)
1602 wxLogLastError(_T("SelectObject(brush)"));
1607 m_oldBrush
= (WXHBRUSH
)hbrush
;
1612 else // invalid brush, reset the current brush
1616 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1618 wxLogLastError(_T("SelectObject(old brush)"));
1624 m_brush
= wxNullBrush
;
1628 void wxDC::SetBackground(const wxBrush
& brush
)
1630 WXMICROWIN_CHECK_HDC
1632 m_backgroundBrush
= brush
;
1634 if ( m_backgroundBrush
.Ok() )
1636 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1640 void wxDC::SetBackgroundMode(int mode
)
1642 WXMICROWIN_CHECK_HDC
1644 m_backgroundMode
= mode
;
1646 // SetBackgroundColour now only refers to text background
1647 // and m_backgroundMode is used there
1650 void wxDC::SetLogicalFunction(int function
)
1652 WXMICROWIN_CHECK_HDC
1654 m_logicalFunction
= function
;
1659 void wxDC::SetRop(WXHDC dc
)
1661 if ( !dc
|| m_logicalFunction
< 0 )
1666 switch (m_logicalFunction
)
1668 case wxCLEAR
: rop
= R2_BLACK
; break;
1669 case wxXOR
: rop
= R2_XORPEN
; break;
1670 case wxINVERT
: rop
= R2_NOT
; break;
1671 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1672 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1673 case wxCOPY
: rop
= R2_COPYPEN
; break;
1674 case wxAND
: rop
= R2_MASKPEN
; break;
1675 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1676 case wxNO_OP
: rop
= R2_NOP
; break;
1677 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1678 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1679 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1680 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1681 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1682 case wxOR
: rop
= R2_MERGEPEN
; break;
1683 case wxSET
: rop
= R2_WHITE
; break;
1686 wxFAIL_MSG( wxT("unsupported logical function") );
1690 SetROP2(GetHdc(), rop
);
1693 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1695 // We might be previewing, so return true to let it continue.
1703 void wxDC::StartPage()
1707 void wxDC::EndPage()
1711 // ---------------------------------------------------------------------------
1713 // ---------------------------------------------------------------------------
1715 wxCoord
wxDC::GetCharHeight() const
1717 WXMICROWIN_CHECK_HDC_RET(0)
1719 TEXTMETRIC lpTextMetric
;
1721 GetTextMetrics(GetHdc(), &lpTextMetric
);
1723 return lpTextMetric
.tmHeight
;
1726 wxCoord
wxDC::GetCharWidth() const
1728 WXMICROWIN_CHECK_HDC_RET(0)
1730 TEXTMETRIC lpTextMetric
;
1732 GetTextMetrics(GetHdc(), &lpTextMetric
);
1734 return lpTextMetric
.tmAveCharWidth
;
1737 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1738 wxCoord
*descent
, wxCoord
*externalLeading
,
1739 const wxFont
*font
) const
1741 #ifdef __WXMICROWIN__
1746 if (descent
) *descent
= 0;
1747 if (externalLeading
) *externalLeading
= 0;
1750 #endif // __WXMICROWIN__
1755 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1757 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1759 else // don't change the font
1765 const size_t len
= string
.length();
1766 if ( !::GetTextExtentPoint32(GetHdc(), string
.wx_str(), len
, &sizeRect
) )
1768 wxLogLastError(_T("GetTextExtentPoint32()"));
1771 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1772 // the result computed by GetTextExtentPoint32() may be too small as it
1773 // accounts for under/overhang of the first/last character while we want
1774 // just the bounding rect for this string so adjust the width as needed
1775 // (using API not available in 2002 SDKs of WinCE)
1779 const wxChar chFirst
= *string
.begin();
1780 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1782 if ( width
.abcA
< 0 )
1783 sizeRect
.cx
-= width
.abcA
;
1787 const wxChar chLast
= *string
.rbegin();
1788 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1790 //else: we already have the width of the last character
1792 if ( width
.abcC
< 0 )
1793 sizeRect
.cx
-= width
.abcC
;
1795 //else: GetCharABCWidths() failed, not a TrueType font?
1797 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1800 ::GetTextMetrics(GetHdc(), &tm
);
1807 *descent
= tm
.tmDescent
;
1808 if (externalLeading
)
1809 *externalLeading
= tm
.tmExternalLeading
;
1813 ::SelectObject(GetHdc(), hfontOld
);
1818 // Each element of the array will be the width of the string up to and
1819 // including the coresoponding character in text.
1821 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1823 static int maxLenText
= -1;
1824 static int maxWidth
= -1;
1827 int stlen
= text
.length();
1829 if (maxLenText
== -1)
1831 // Win9x and WinNT+ have different limits
1832 int version
= wxGetOsVersion();
1833 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1834 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1838 widths
.Add(0, stlen
); // fill the array with zeros
1842 if (!::GetTextExtentExPoint(GetHdc(),
1843 text
.c_str(), // string to check
1844 wxMin(stlen
, maxLenText
),
1846 &fit
, // [out] count of chars
1848 &widths
[0], // array to fill
1852 wxLogLastError(wxT("GetTextExtentExPoint"));
1859 void wxDC::RealizeScaleAndOrigin()
1861 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1862 // cases we could do with MM_TEXT and in the remaining 0.9% with
1863 // MM_ISOTROPIC (TODO!)
1865 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1867 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1868 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1870 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1871 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1873 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1874 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1879 void wxDC::SetMapMode(int mode
)
1881 WXMICROWIN_CHECK_HDC
1883 m_mappingMode
= mode
;
1885 if ( mode
== wxMM_TEXT
)
1888 m_logicalScaleY
= 1.0;
1890 else // need to do some calculations
1892 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1893 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1894 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1895 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1897 if ( (mm_width
== 0) || (mm_height
== 0) )
1899 // we can't calculate mm2pixels[XY] then!
1903 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1904 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1909 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1910 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1914 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1915 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1919 m_logicalScaleX
= mm2pixelsX
;
1920 m_logicalScaleY
= mm2pixelsY
;
1924 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1925 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1929 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1933 ComputeScaleAndOrigin();
1935 RealizeScaleAndOrigin();
1938 void wxDC::SetUserScale(double x
, double y
)
1940 WXMICROWIN_CHECK_HDC
1942 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1945 wxDCBase::SetUserScale(x
,y
);
1947 RealizeScaleAndOrigin();
1950 void wxDC::SetAxisOrientation(bool xLeftRight
,
1953 WXMICROWIN_CHECK_HDC
1955 int signX
= xLeftRight
? 1 : -1,
1956 signY
= yBottomUp
? -1 : 1;
1958 if (signX
== m_signX
&& signY
== m_signY
)
1961 wxDCBase::SetAxisOrientation( xLeftRight
, yBottomUp
);
1963 RealizeScaleAndOrigin();
1966 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1968 WXMICROWIN_CHECK_HDC
1970 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1973 wxDCBase::SetLogicalOrigin( x
, y
);
1976 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1980 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1982 WXMICROWIN_CHECK_HDC
1984 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1987 wxDCBase::SetDeviceOrigin( x
, y
);
1989 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1992 // ---------------------------------------------------------------------------
1994 // ---------------------------------------------------------------------------
1996 bool wxDC::DoBlit(wxCoord dstX
, wxCoord dstY
,
1997 wxCoord dstWidth
, wxCoord dstHeight
,
1999 wxCoord srcX
, wxCoord srcY
,
2000 int rop
, bool useMask
,
2001 wxCoord srcMaskX
, wxCoord srcMaskY
)
2003 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
2006 bool wxDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
2007 wxCoord dstWidth
, wxCoord dstHeight
,
2009 wxCoord xsrc
, wxCoord ysrc
,
2010 wxCoord srcWidth
, wxCoord srcHeight
,
2011 int rop
, bool useMask
,
2012 wxCoord xsrcMask
, wxCoord ysrcMask
)
2014 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2016 WXMICROWIN_CHECK_HDC_RET(false)
2018 // if either the source or destination has alpha channel, we must use
2019 // AlphaBlt() as other function don't handle it correctly
2020 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2021 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2022 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2024 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2025 xsrc
, ysrc
, srcWidth
, srcHeight
, GetHdcOf(*source
), bmpSrc
) )
2029 wxMask
*mask
= NULL
;
2032 mask
= bmpSrc
.GetMask();
2034 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2036 // don't give assert here because this would break existing
2037 // programs - just silently ignore useMask parameter
2042 if (xsrcMask
== -1 && ysrcMask
== -1)
2044 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2047 COLORREF old_textground
= ::GetTextColor(GetHdc());
2048 COLORREF old_background
= ::GetBkColor(GetHdc());
2049 if (m_textForegroundColour
.Ok())
2051 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2053 if (m_textBackgroundColour
.Ok())
2055 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2061 case wxXOR
: dwRop
= SRCINVERT
; break;
2062 case wxINVERT
: dwRop
= DSTINVERT
; break;
2063 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2064 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2065 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2066 case wxSET
: dwRop
= WHITENESS
; break;
2067 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2068 case wxAND
: dwRop
= SRCAND
; break;
2069 case wxOR
: dwRop
= SRCPAINT
; break;
2070 case wxEQUIV
: dwRop
= 0x00990066; break;
2071 case wxNAND
: dwRop
= 0x007700E6; break;
2072 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2073 case wxCOPY
: dwRop
= SRCCOPY
; break;
2074 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2075 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2076 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2078 wxFAIL_MSG( wxT("unsupported logical function") );
2082 bool success
= false;
2087 // we want the part of the image corresponding to the mask to be
2088 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2089 // meaning of fg and bg is inverted which corresponds to wxWin notion
2090 // of the mask which is also contrary to the Windows one)
2092 // On some systems, MaskBlt succeeds yet is much much slower
2093 // than the wxWidgets fall-back implementation. So we need
2094 // to be able to switch this on and off at runtime.
2095 #if wxUSE_SYSTEM_OPTIONS
2096 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2099 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2104 xdest
, ydest
, dstWidth
, dstHeight
,
2107 (HBITMAP
)mask
->GetMaskBitmap(),
2109 MAKEROP4(dwRop
, DSTCOPY
)
2117 // Blit bitmap with mask
2120 HBITMAP buffer_bmap
;
2122 #if wxUSE_DC_CACHEING
2123 // create a temp buffer bitmap and DCs to access it and the mask
2124 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2125 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2127 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2128 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2130 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2131 dstWidth
, dstHeight
);
2133 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2134 #else // !wxUSE_DC_CACHEING
2135 // create a temp buffer bitmap and DCs to access it and the mask
2136 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2137 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2138 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2139 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2140 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2141 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2143 // copy dest to buffer
2144 if ( !::BitBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2145 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2147 wxLogLastError(wxT("BitBlt"));
2151 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2154 // copy src to buffer using selected raster op
2155 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2156 GetHdcOf(*source
), xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2158 wxLogLastError(wxT("StretchBlt"));
2161 // set masked area in buffer to BLACK (pixel value 0)
2162 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2163 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2164 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2165 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2167 wxLogLastError(wxT("StretchBlt"));
2170 // set unmasked area in dest to BLACK
2171 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2172 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2173 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, (int)dstWidth
, (int)dstHeight
,
2174 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2176 wxLogLastError(wxT("StretchBlt"));
2178 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2179 ::SetTextColor(GetHdc(), prevCol
);
2181 // OR buffer to dest
2182 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2183 (int)dstWidth
, (int)dstHeight
,
2184 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2187 wxLogLastError(wxT("BitBlt"));
2190 // tidy up temporary DCs and bitmap
2191 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2192 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2194 #if !wxUSE_DC_CACHEING
2196 ::DeleteDC(dc_mask
);
2197 ::DeleteDC(dc_buffer
);
2198 ::DeleteObject(buffer_bmap
);
2203 else // no mask, just BitBlt() it
2205 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2206 // use StretchBlt() if available and finally fall back to BitBlt()
2208 // FIXME: use appropriate WinCE functions
2210 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2211 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2216 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2218 &ds
) == sizeof(ds
) )
2220 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2222 // Figure out what co-ordinate system we're supposed to specify
2224 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2228 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2231 if ( ::StretchDIBits(GetHdc(),
2233 dstWidth
, dstHeight
,
2235 srcWidth
, srcHeight
,
2237 (LPBITMAPINFO
)&ds
.dsBmih
,
2240 ) == (int)GDI_ERROR
)
2242 // On Win9x this API fails most (all?) of the time, so
2243 // logging it becomes quite distracting. Since it falls
2244 // back to the code below this is not really serious, so
2246 //wxLogLastError(wxT("StretchDIBits"));
2255 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2260 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2266 xdest
, ydest
, dstWidth
, dstHeight
,
2268 xsrc
, ysrc
, srcWidth
, srcHeight
,
2272 wxLogLastError(_T("StretchBlt"));
2286 (int)dstWidth
, (int)dstHeight
,
2292 wxLogLastError(_T("BitBlt"));
2301 ::SetTextColor(GetHdc(), old_textground
);
2302 ::SetBkColor(GetHdc(), old_background
);
2307 void wxDC::GetDeviceSize(int *width
, int *height
) const
2309 WXMICROWIN_CHECK_HDC
2312 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2314 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2317 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2319 WXMICROWIN_CHECK_HDC
2321 // if we implement it in terms of DoGetSize() instead of directly using the
2322 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2323 // will also work for wxWindowDC and wxClientDC even though their size is
2324 // not the same as the total size of the screen
2325 int wPixels
, hPixels
;
2326 DoGetSize(&wPixels
, &hPixels
);
2330 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2332 wxCHECK_RET( wTotal
, _T("0 width device?") );
2334 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2339 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2341 wxCHECK_RET( hTotal
, _T("0 height device?") );
2343 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2347 wxSize
wxDC::GetPPI() const
2349 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2351 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2352 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2354 return wxSize(x
, y
);
2357 // For use by wxWidgets only, unless custom units are required.
2358 void wxDC::SetLogicalScale(double x
, double y
)
2360 WXMICROWIN_CHECK_HDC
2362 wxDCBase::SetLogicalScale(x
,y
);
2365 // ----------------------------------------------------------------------------
2367 // ----------------------------------------------------------------------------
2369 #if wxUSE_DC_CACHEING
2372 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2373 * improve it in due course, either using arrays, or simply storing pointers to one
2374 * entry for the bitmap, and two for the DCs. -- JACS
2377 wxList
wxDC::sm_bitmapCache
;
2378 wxList
wxDC::sm_dcCache
;
2380 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2389 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2398 wxDCCacheEntry::~wxDCCacheEntry()
2401 ::DeleteObject((HBITMAP
) m_bitmap
);
2403 ::DeleteDC((HDC
) m_dc
);
2406 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2408 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2409 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2412 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2414 if (entry
->m_depth
== depth
)
2416 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2418 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2419 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2420 if ( !entry
->m_bitmap
)
2422 wxLogLastError(wxT("CreateCompatibleBitmap"));
2424 entry
->m_width
= w
; entry
->m_height
= h
;
2430 node
= node
->GetNext();
2432 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2435 wxLogLastError(wxT("CreateCompatibleBitmap"));
2437 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2438 AddToBitmapCache(entry
);
2442 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2444 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2445 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2448 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2450 // Don't return the same one as we already have
2451 if (!notThis
|| (notThis
!= entry
))
2453 if (entry
->m_depth
== depth
)
2459 node
= node
->GetNext();
2461 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2464 wxLogLastError(wxT("CreateCompatibleDC"));
2466 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2467 AddToDCCache(entry
);
2471 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2473 sm_bitmapCache
.Append(entry
);
2476 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2478 sm_dcCache
.Append(entry
);
2481 void wxDC::ClearCache()
2483 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2484 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2487 // Clean up cache at app exit
2488 class wxDCModule
: public wxModule
2491 virtual bool OnInit() { return true; }
2492 virtual void OnExit() { wxDC::ClearCache(); }
2495 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2498 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2500 #endif // wxUSE_DC_CACHEING
2502 // ----------------------------------------------------------------------------
2503 // alpha channel support
2504 // ----------------------------------------------------------------------------
2506 static bool AlphaBlt(HDC hdcDst
,
2507 int x
, int y
, int dstWidth
, int dstHeight
,
2509 int srcWidth
, int srcHeight
,
2511 const wxBitmap
& bmp
)
2513 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2514 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2516 // do we have AlphaBlend() and company in the headers?
2517 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2518 // yes, now try to see if we have it during run-time
2519 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2520 HDC
,int,int,int,int,
2524 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2525 if ( pfnAlphaBlend
)
2528 bf
.BlendOp
= AC_SRC_OVER
;
2530 bf
.SourceConstantAlpha
= 0xff;
2531 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2533 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2534 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2537 // skip wxAlphaBlend() call below
2541 wxLogLastError(_T("AlphaBlend"));
2544 wxUnusedVar(hdcSrc
);
2545 #endif // defined(AC_SRC_OVER)
2547 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2549 #ifdef wxHAVE_RAW_BITMAP
2550 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2553 #else // !wxHAVE_RAW_BITMAP
2554 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2555 // alpha but at least something will be shown like this)
2558 #endif // wxHAVE_RAW_BITMAP
2562 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2563 #ifdef wxHAVE_RAW_BITMAP
2566 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2567 int dstWidth
, int dstHeight
,
2569 int srcWidth
, int srcHeight
,
2570 const wxBitmap
& bmpSrc
)
2572 // get the destination DC pixels
2573 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2575 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2577 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2579 wxLogLastError(_T("BitBlt"));
2582 // combine them with the source bitmap using alpha
2583 wxAlphaPixelData
dataDst(bmpDst
),
2584 dataSrc((wxBitmap
&)bmpSrc
);
2586 wxCHECK_RET( dataDst
&& dataSrc
,
2587 _T("failed to get raw data in wxAlphaBlend") );
2589 wxAlphaPixelData::Iterator
pDst(dataDst
),
2593 for ( int y
= 0; y
< dstHeight
; y
++ )
2595 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2597 for ( int x
= 0; x
< dstWidth
; x
++ )
2599 // source is point sampled, Alpha StretchBlit is ugly on Win95
2600 // (but does not impact performance)
2601 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2603 // note that source bitmap uses premultiplied alpha (as required by
2604 // the real AlphaBlend)
2605 const unsigned beta
= 255 - pSrc
.Alpha();
2607 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2608 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2609 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2614 pDst
= pDstRowStart
;
2615 pDst
.OffsetY(dataDst
, 1);
2618 // and finally blit them back to the destination DC
2619 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2621 wxLogLastError(_T("BitBlt"));
2625 #endif // #ifdef wxHAVE_RAW_BITMAP
2627 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2628 const wxColour
& initialColour
,
2629 const wxColour
& destColour
,
2630 wxDirection nDirection
)
2632 // use native function if we have compile-time support it and can load it
2633 // during run-time (linking to it statically would make the program
2634 // unusable on earlier Windows versions)
2635 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2637 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2638 static GradientFill_t pfnGradientFill
=
2639 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2641 if ( pfnGradientFill
)
2643 GRADIENT_RECT grect
;
2644 grect
.UpperLeft
= 0;
2645 grect
.LowerRight
= 1;
2647 // invert colours direction if not filling from left-to-right or
2649 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2651 // one vertex for upper left and one for upper-right
2652 TRIVERTEX vertices
[2];
2654 vertices
[0].x
= rect
.GetLeft();
2655 vertices
[0].y
= rect
.GetTop();
2656 vertices
[1].x
= rect
.GetRight()+1;
2657 vertices
[1].y
= rect
.GetBottom()+1;
2659 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2660 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2661 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2662 vertices
[firstVertex
].Alpha
= 0;
2663 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2664 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2665 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2666 vertices
[1 - firstVertex
].Alpha
= 0;
2668 if ( (*pfnGradientFill
)
2675 nDirection
== wxWEST
|| nDirection
== wxEAST
2676 ? GRADIENT_FILL_RECT_H
2677 : GRADIENT_FILL_RECT_V
2680 // skip call of the base class version below
2684 wxLogLastError(_T("GradientFill"));
2686 #endif // wxUSE_DYNLIB_CLASS
2688 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2691 #if wxUSE_DYNLIB_CLASS
2693 static DWORD
wxGetDCLayout(HDC hdc
)
2695 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2697 pfnGetLayout
= (GetLayout_t
)wxGDI32DLL
.GetSymbol(_T("GetLayout"));
2699 return pfnGetLayout
? pfnGetLayout(hdc
) : (DWORD
)-1;
2702 wxLayoutDirection
wxDC::GetLayoutDirection() const
2704 DWORD layout
= wxGetDCLayout(GetHdc());
2706 if ( layout
== (DWORD
)-1 )
2707 return wxLayout_Default
;
2709 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2712 void wxDC::SetLayoutDirection(wxLayoutDirection dir
)
2714 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2716 pfnSetLayout
= (SetLayout_t
)wxGDI32DLL
.GetSymbol(_T("SetLayout"));
2717 if ( !pfnSetLayout
)
2720 if ( dir
== wxLayout_Default
)
2722 dir
= wxTheApp
->GetLayoutDirection();
2723 if ( dir
== wxLayout_Default
)
2727 DWORD layout
= wxGetDCLayout(GetHdc());
2728 if ( dir
== wxLayout_RightToLeft
)
2729 layout
|= LAYOUT_RTL
;
2731 layout
&= ~LAYOUT_RTL
;
2733 pfnSetLayout(GetHdc(), layout
);
2736 #else // !wxUSE_DYNLIB_CLASS
2738 // we can't provide RTL support without dynamic loading, so stub it out
2739 wxLayoutDirection
wxDC::GetLayoutDirection() const
2741 return wxLayout_Default
;
2744 void wxDC::SetLayoutDirection(wxLayoutDirection
WXUNUSED(dir
))
2748 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS