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(wxList
*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 wxList::compatibility_iterator node
= points
->GetFirst();
1033 wxPoint
*p
= (wxPoint
*)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
= (wxPoint
*)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 // draw pie with NULL_PEN first and then outline otherwise a line is
1126 // drawn from the start and end points to the centre
1127 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1130 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1131 rx1
, ry1
, rx2
, ry2
);
1135 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1136 rx1
, ry1
-1, rx2
, ry2
-1);
1139 ::SelectObject(GetHdc(), hpenOld
);
1141 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1142 rx1
, ry1
, rx2
, ry2
);
1144 CalcBoundingBox(x
, y
);
1145 CalcBoundingBox(x2
, y2
);
1149 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1151 WXMICROWIN_CHECK_HDC
1153 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1156 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1158 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1161 CalcBoundingBox(x
, y
);
1162 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1165 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1167 WXMICROWIN_CHECK_HDC
1169 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1171 int width
= bmp
.GetWidth(),
1172 height
= bmp
.GetHeight();
1174 HBITMAP hbmpMask
= 0;
1177 HPALETTE oldPal
= 0;
1178 #endif // wxUSE_PALETTE
1180 if ( bmp
.HasAlpha() )
1183 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1185 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1191 wxMask
*mask
= bmp
.GetMask();
1193 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1197 // don't give assert here because this would break existing
1198 // programs - just silently ignore useMask parameter
1205 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1207 // On some systems, MaskBlt succeeds yet is much much slower
1208 // than the wxWidgets fall-back implementation. So we need
1209 // to be able to switch this on and off at runtime.
1211 #if wxUSE_SYSTEM_OPTIONS
1212 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1216 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1217 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1219 wxPalette
*pal
= bmp
.GetPalette();
1220 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1222 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1223 ::RealizePalette(hdcMem
);
1225 #endif // wxUSE_PALETTE
1227 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1230 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1234 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1235 #endif // wxUSE_PALETTE
1237 ::SelectObject(hdcMem
, hOldBitmap
);
1244 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1248 memDC
.SelectObjectAsSource(bmp
);
1250 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1252 memDC
.SelectObject(wxNullBitmap
);
1255 else // no mask, just use BitBlt()
1258 HDC memdc
= ::CreateCompatibleDC( cdc
);
1259 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1261 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1263 COLORREF old_textground
= ::GetTextColor(GetHdc());
1264 COLORREF old_background
= ::GetBkColor(GetHdc());
1265 if (m_textForegroundColour
.Ok())
1267 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1269 if (m_textBackgroundColour
.Ok())
1271 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1275 wxPalette
*pal
= bmp
.GetPalette();
1276 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1278 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1279 ::RealizePalette(memdc
);
1281 #endif // wxUSE_PALETTE
1283 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1284 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1288 ::SelectPalette(memdc
, oldPal
, FALSE
);
1289 #endif // wxUSE_PALETTE
1291 ::SelectObject( memdc
, hOldBitmap
);
1292 ::DeleteDC( memdc
);
1294 ::SetTextColor(GetHdc(), old_textground
);
1295 ::SetBkColor(GetHdc(), old_background
);
1299 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1301 WXMICROWIN_CHECK_HDC
1303 DrawAnyText(text
, x
, y
);
1305 // update the bounding box
1306 CalcBoundingBox(x
, y
);
1309 GetTextExtent(text
, &w
, &h
);
1310 CalcBoundingBox(x
+ w
, y
+ h
);
1313 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1315 WXMICROWIN_CHECK_HDC
1317 // prepare for drawing the text
1318 if ( m_textForegroundColour
.Ok() )
1319 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1321 DWORD old_background
= 0;
1322 if ( m_textBackgroundColour
.Ok() )
1324 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1327 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1331 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1332 text
.c_str(), text
.length(), NULL
) == 0 )
1334 wxLogLastError(wxT("TextOut"));
1337 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1338 text
.c_str(), text
.length()) == 0 )
1340 wxLogLastError(wxT("TextOut"));
1344 // restore the old parameters (text foreground colour may be left because
1345 // it never is set to anything else, but background should remain
1346 // transparent even if we just drew an opaque string)
1347 if ( m_textBackgroundColour
.Ok() )
1348 (void)SetBkColor(GetHdc(), old_background
);
1350 SetBkMode(GetHdc(), TRANSPARENT
);
1353 void wxDC::DoDrawRotatedText(const wxString
& text
,
1354 wxCoord x
, wxCoord y
,
1357 WXMICROWIN_CHECK_HDC
1359 // we test that we have some font because otherwise we should still use the
1360 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1361 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1362 // font for drawing rotated fonts unfortunately)
1363 if ( (angle
== 0.0) && m_font
.Ok() )
1365 DoDrawText(text
, x
, y
);
1367 #ifndef __WXMICROWIN__
1370 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1371 // because it's not TrueType and so can't have non zero
1372 // orientation/escapement under Win9x
1373 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1374 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1376 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1378 wxLogLastError(wxT("GetObject(hfont)"));
1381 // GDI wants the angle in tenth of degree
1382 long angle10
= (long)(angle
* 10);
1383 lf
.lfEscapement
= angle10
;
1384 lf
. lfOrientation
= angle10
;
1386 hfont
= ::CreateFontIndirect(&lf
);
1389 wxLogLastError(wxT("CreateFont"));
1393 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1395 DrawAnyText(text
, x
, y
);
1397 (void)::SelectObject(GetHdc(), hfontOld
);
1398 (void)::DeleteObject(hfont
);
1401 // call the bounding box by adding all four vertices of the rectangle
1402 // containing the text to it (simpler and probably not slower than
1403 // determining which of them is really topmost/leftmost/...)
1405 GetTextExtent(text
, &w
, &h
);
1407 double rad
= DegToRad(angle
);
1409 // "upper left" and "upper right"
1410 CalcBoundingBox(x
, y
);
1411 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1413 // "bottom left" and "bottom right"
1414 x
+= (wxCoord
)(h
*sin(rad
));
1415 y
+= (wxCoord
)(h
*cos(rad
));
1416 CalcBoundingBox(x
, y
);
1417 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1422 // ---------------------------------------------------------------------------
1424 // ---------------------------------------------------------------------------
1428 void wxDC::DoSelectPalette(bool realize
)
1430 WXMICROWIN_CHECK_HDC
1432 // Set the old object temporarily, in case the assignment deletes an object
1433 // that's not yet selected out.
1436 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1440 if ( m_palette
.Ok() )
1442 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1443 GetHpaletteOf(m_palette
),
1446 m_oldPalette
= (WXHPALETTE
) oldPal
;
1449 ::RealizePalette(GetHdc());
1453 void wxDC::SetPalette(const wxPalette
& palette
)
1457 m_palette
= palette
;
1458 DoSelectPalette(true);
1462 void wxDC::InitializePalette()
1464 if ( wxDisplayDepth() <= 8 )
1466 // look for any window or parent that has a custom palette. If any has
1467 // one then we need to use it in drawing operations
1468 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1470 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1471 if ( m_hasCustomPalette
)
1473 m_palette
= win
->GetPalette();
1475 // turn on MSW translation for this palette
1481 #endif // wxUSE_PALETTE
1483 // SetFont/Pen/Brush() really ask to be implemented as a single template
1484 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1486 void wxDC::SetFont(const wxFont
& font
)
1488 WXMICROWIN_CHECK_HDC
1490 if ( font
== m_font
)
1495 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1496 if ( hfont
== HGDI_ERROR
)
1498 wxLogLastError(_T("SelectObject(font)"));
1503 m_oldFont
= (WXHFONT
)hfont
;
1508 else // invalid font, reset the current font
1512 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1514 wxLogLastError(_T("SelectObject(old font)"));
1520 m_font
= wxNullFont
;
1524 void wxDC::SetPen(const wxPen
& pen
)
1526 WXMICROWIN_CHECK_HDC
1533 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1534 if ( hpen
== HGDI_ERROR
)
1536 wxLogLastError(_T("SelectObject(pen)"));
1541 m_oldPen
= (WXHPEN
)hpen
;
1546 else // invalid pen, reset the current pen
1550 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1552 wxLogLastError(_T("SelectObject(old pen)"));
1562 void wxDC::SetBrush(const wxBrush
& brush
)
1564 WXMICROWIN_CHECK_HDC
1566 if ( brush
== m_brush
)
1571 // we must make sure the brush is aligned with the logical coordinates
1572 // before selecting it
1573 wxBitmap
*stipple
= brush
.GetStipple();
1574 if ( stipple
&& stipple
->Ok() )
1576 if ( !::SetBrushOrgEx
1579 m_deviceOriginX
% stipple
->GetWidth(),
1580 m_deviceOriginY
% stipple
->GetHeight(),
1581 NULL
// [out] previous brush origin
1584 wxLogLastError(_T("SetBrushOrgEx()"));
1588 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1589 if ( hbrush
== HGDI_ERROR
)
1591 wxLogLastError(_T("SelectObject(brush)"));
1596 m_oldBrush
= (WXHBRUSH
)hbrush
;
1601 else // invalid brush, reset the current brush
1605 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1607 wxLogLastError(_T("SelectObject(old brush)"));
1613 m_brush
= wxNullBrush
;
1617 void wxDC::SetBackground(const wxBrush
& brush
)
1619 WXMICROWIN_CHECK_HDC
1621 m_backgroundBrush
= brush
;
1623 if ( m_backgroundBrush
.Ok() )
1625 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1629 void wxDC::SetBackgroundMode(int mode
)
1631 WXMICROWIN_CHECK_HDC
1633 m_backgroundMode
= mode
;
1635 // SetBackgroundColour now only refers to text background
1636 // and m_backgroundMode is used there
1639 void wxDC::SetLogicalFunction(int function
)
1641 WXMICROWIN_CHECK_HDC
1643 m_logicalFunction
= function
;
1648 void wxDC::SetRop(WXHDC dc
)
1650 if ( !dc
|| m_logicalFunction
< 0 )
1655 switch (m_logicalFunction
)
1657 case wxCLEAR
: rop
= R2_BLACK
; break;
1658 case wxXOR
: rop
= R2_XORPEN
; break;
1659 case wxINVERT
: rop
= R2_NOT
; break;
1660 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1661 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1662 case wxCOPY
: rop
= R2_COPYPEN
; break;
1663 case wxAND
: rop
= R2_MASKPEN
; break;
1664 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1665 case wxNO_OP
: rop
= R2_NOP
; break;
1666 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1667 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1668 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1669 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1670 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1671 case wxOR
: rop
= R2_MERGEPEN
; break;
1672 case wxSET
: rop
= R2_WHITE
; break;
1675 wxFAIL_MSG( wxT("unsupported logical function") );
1679 SetROP2(GetHdc(), rop
);
1682 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1684 // We might be previewing, so return true to let it continue.
1692 void wxDC::StartPage()
1696 void wxDC::EndPage()
1700 // ---------------------------------------------------------------------------
1702 // ---------------------------------------------------------------------------
1704 wxCoord
wxDC::GetCharHeight() const
1706 WXMICROWIN_CHECK_HDC_RET(0)
1708 TEXTMETRIC lpTextMetric
;
1710 GetTextMetrics(GetHdc(), &lpTextMetric
);
1712 return lpTextMetric
.tmHeight
;
1715 wxCoord
wxDC::GetCharWidth() const
1717 WXMICROWIN_CHECK_HDC_RET(0)
1719 TEXTMETRIC lpTextMetric
;
1721 GetTextMetrics(GetHdc(), &lpTextMetric
);
1723 return lpTextMetric
.tmAveCharWidth
;
1726 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1727 wxCoord
*descent
, wxCoord
*externalLeading
,
1728 const wxFont
*font
) const
1730 #ifdef __WXMICROWIN__
1735 if (descent
) *descent
= 0;
1736 if (externalLeading
) *externalLeading
= 0;
1739 #endif // __WXMICROWIN__
1744 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1746 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1748 else // don't change the font
1754 const size_t len
= string
.length();
1755 if ( !::GetTextExtentPoint32(GetHdc(), string
.wx_str(), len
, &sizeRect
) )
1757 wxLogLastError(_T("GetTextExtentPoint32()"));
1760 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1761 // the result computed by GetTextExtentPoint32() may be too small as it
1762 // accounts for under/overhang of the first/last character while we want
1763 // just the bounding rect for this string so adjust the width as needed
1764 // (using API not available in 2002 SDKs of WinCE)
1768 const wxChar chFirst
= *string
.begin();
1769 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1771 if ( width
.abcA
< 0 )
1772 sizeRect
.cx
-= width
.abcA
;
1776 const wxChar chLast
= *string
.rbegin();
1777 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1779 //else: we already have the width of the last character
1781 if ( width
.abcC
< 0 )
1782 sizeRect
.cx
-= width
.abcC
;
1784 //else: GetCharABCWidths() failed, not a TrueType font?
1786 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1789 ::GetTextMetrics(GetHdc(), &tm
);
1796 *descent
= tm
.tmDescent
;
1797 if (externalLeading
)
1798 *externalLeading
= tm
.tmExternalLeading
;
1802 ::SelectObject(GetHdc(), hfontOld
);
1807 // Each element of the array will be the width of the string up to and
1808 // including the coresoponding character in text.
1810 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1812 static int maxLenText
= -1;
1813 static int maxWidth
= -1;
1816 int stlen
= text
.length();
1818 if (maxLenText
== -1)
1820 // Win9x and WinNT+ have different limits
1821 int version
= wxGetOsVersion();
1822 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1823 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1827 widths
.Add(0, stlen
); // fill the array with zeros
1831 if (!::GetTextExtentExPoint(GetHdc(),
1832 text
.c_str(), // string to check
1833 wxMin(stlen
, maxLenText
),
1835 &fit
, // [out] count of chars
1837 &widths
[0], // array to fill
1841 wxLogLastError(wxT("GetTextExtentExPoint"));
1848 void wxDC::RealizeScaleAndOrigin()
1850 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1851 // cases we could do with MM_TEXT and in the remaining 0.9% with
1852 // MM_ISOTROPIC (TODO!)
1854 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1856 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1857 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1859 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1860 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1862 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1863 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1868 void wxDC::SetMapMode(int mode
)
1870 WXMICROWIN_CHECK_HDC
1872 m_mappingMode
= mode
;
1874 if ( mode
== wxMM_TEXT
)
1877 m_logicalScaleY
= 1.0;
1879 else // need to do some calculations
1881 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1882 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1883 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1884 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1886 if ( (mm_width
== 0) || (mm_height
== 0) )
1888 // we can't calculate mm2pixels[XY] then!
1892 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1893 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1898 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1899 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1903 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1904 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1908 m_logicalScaleX
= mm2pixelsX
;
1909 m_logicalScaleY
= mm2pixelsY
;
1913 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1914 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1918 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1922 ComputeScaleAndOrigin();
1924 RealizeScaleAndOrigin();
1927 void wxDC::SetUserScale(double x
, double y
)
1929 WXMICROWIN_CHECK_HDC
1931 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1934 wxDCBase::SetUserScale(x
,y
);
1936 RealizeScaleAndOrigin();
1939 void wxDC::SetAxisOrientation(bool xLeftRight
,
1942 WXMICROWIN_CHECK_HDC
1944 int signX
= xLeftRight
? 1 : -1,
1945 signY
= yBottomUp
? -1 : 1;
1947 if (signX
== m_signX
&& signY
== m_signY
)
1950 wxDCBase::SetAxisOrientation( xLeftRight
, yBottomUp
);
1952 RealizeScaleAndOrigin();
1955 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1957 WXMICROWIN_CHECK_HDC
1959 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1962 wxDCBase::SetLogicalOrigin( x
, y
);
1965 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1969 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1971 WXMICROWIN_CHECK_HDC
1973 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1976 wxDCBase::SetDeviceOrigin( x
, y
);
1978 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1981 // ---------------------------------------------------------------------------
1983 // ---------------------------------------------------------------------------
1985 bool wxDC::DoBlit(wxCoord dstX
, wxCoord dstY
,
1986 wxCoord dstWidth
, wxCoord dstHeight
,
1988 wxCoord srcX
, wxCoord srcY
,
1989 int rop
, bool useMask
,
1990 wxCoord srcMaskX
, wxCoord srcMaskY
)
1992 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
1995 bool wxDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1996 wxCoord dstWidth
, wxCoord dstHeight
,
1998 wxCoord xsrc
, wxCoord ysrc
,
1999 wxCoord srcWidth
, wxCoord srcHeight
,
2000 int rop
, bool useMask
,
2001 wxCoord xsrcMask
, wxCoord ysrcMask
)
2003 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2005 WXMICROWIN_CHECK_HDC_RET(false)
2007 // if either the source or destination has alpha channel, we must use
2008 // AlphaBlt() as other function don't handle it correctly
2009 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2010 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2011 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2013 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2014 xsrc
, ysrc
, srcWidth
, srcHeight
, GetHdcOf(*source
), bmpSrc
) )
2018 wxMask
*mask
= NULL
;
2021 mask
= bmpSrc
.GetMask();
2023 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2025 // don't give assert here because this would break existing
2026 // programs - just silently ignore useMask parameter
2031 if (xsrcMask
== -1 && ysrcMask
== -1)
2033 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2036 COLORREF old_textground
= ::GetTextColor(GetHdc());
2037 COLORREF old_background
= ::GetBkColor(GetHdc());
2038 if (m_textForegroundColour
.Ok())
2040 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2042 if (m_textBackgroundColour
.Ok())
2044 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2050 case wxXOR
: dwRop
= SRCINVERT
; break;
2051 case wxINVERT
: dwRop
= DSTINVERT
; break;
2052 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2053 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2054 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2055 case wxSET
: dwRop
= WHITENESS
; break;
2056 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2057 case wxAND
: dwRop
= SRCAND
; break;
2058 case wxOR
: dwRop
= SRCPAINT
; break;
2059 case wxEQUIV
: dwRop
= 0x00990066; break;
2060 case wxNAND
: dwRop
= 0x007700E6; break;
2061 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2062 case wxCOPY
: dwRop
= SRCCOPY
; break;
2063 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2064 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2065 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2067 wxFAIL_MSG( wxT("unsupported logical function") );
2071 bool success
= false;
2076 // we want the part of the image corresponding to the mask to be
2077 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2078 // meaning of fg and bg is inverted which corresponds to wxWin notion
2079 // of the mask which is also contrary to the Windows one)
2081 // On some systems, MaskBlt succeeds yet is much much slower
2082 // than the wxWidgets fall-back implementation. So we need
2083 // to be able to switch this on and off at runtime.
2084 #if wxUSE_SYSTEM_OPTIONS
2085 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2088 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2093 xdest
, ydest
, dstWidth
, dstHeight
,
2096 (HBITMAP
)mask
->GetMaskBitmap(),
2098 MAKEROP4(dwRop
, DSTCOPY
)
2106 // Blit bitmap with mask
2109 HBITMAP buffer_bmap
;
2111 #if wxUSE_DC_CACHEING
2112 // create a temp buffer bitmap and DCs to access it and the mask
2113 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2114 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2116 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2117 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2119 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2120 dstWidth
, dstHeight
);
2122 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2123 #else // !wxUSE_DC_CACHEING
2124 // create a temp buffer bitmap and DCs to access it and the mask
2125 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2126 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2127 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2128 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2129 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2130 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2132 // copy dest to buffer
2133 if ( !::BitBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2134 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2136 wxLogLastError(wxT("BitBlt"));
2140 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2143 // copy src to buffer using selected raster op
2144 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2145 GetHdcOf(*source
), xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2147 wxLogLastError(wxT("StretchBlt"));
2150 // set masked area in buffer to BLACK (pixel value 0)
2151 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2152 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2153 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2154 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2156 wxLogLastError(wxT("StretchBlt"));
2159 // set unmasked area in dest to BLACK
2160 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2161 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2162 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, (int)dstWidth
, (int)dstHeight
,
2163 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2165 wxLogLastError(wxT("StretchBlt"));
2167 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2168 ::SetTextColor(GetHdc(), prevCol
);
2170 // OR buffer to dest
2171 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2172 (int)dstWidth
, (int)dstHeight
,
2173 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2176 wxLogLastError(wxT("BitBlt"));
2179 // tidy up temporary DCs and bitmap
2180 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2181 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2183 #if !wxUSE_DC_CACHEING
2185 ::DeleteDC(dc_mask
);
2186 ::DeleteDC(dc_buffer
);
2187 ::DeleteObject(buffer_bmap
);
2192 else // no mask, just BitBlt() it
2194 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2195 // use StretchBlt() if available and finally fall back to BitBlt()
2197 // FIXME: use appropriate WinCE functions
2199 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2200 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2205 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2207 &ds
) == sizeof(ds
) )
2209 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2211 // Figure out what co-ordinate system we're supposed to specify
2213 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2217 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2220 if ( ::StretchDIBits(GetHdc(),
2222 dstWidth
, dstHeight
,
2224 srcWidth
, srcHeight
,
2226 (LPBITMAPINFO
)&ds
.dsBmih
,
2229 ) == (int)GDI_ERROR
)
2231 // On Win9x this API fails most (all?) of the time, so
2232 // logging it becomes quite distracting. Since it falls
2233 // back to the code below this is not really serious, so
2235 //wxLogLastError(wxT("StretchDIBits"));
2244 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2249 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2255 xdest
, ydest
, dstWidth
, dstHeight
,
2257 xsrc
, ysrc
, srcWidth
, srcHeight
,
2261 wxLogLastError(_T("StretchBlt"));
2275 (int)dstWidth
, (int)dstHeight
,
2281 wxLogLastError(_T("BitBlt"));
2290 ::SetTextColor(GetHdc(), old_textground
);
2291 ::SetBkColor(GetHdc(), old_background
);
2296 void wxDC::GetDeviceSize(int *width
, int *height
) const
2298 WXMICROWIN_CHECK_HDC
2301 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2303 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2306 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2308 WXMICROWIN_CHECK_HDC
2310 // if we implement it in terms of DoGetSize() instead of directly using the
2311 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2312 // will also work for wxWindowDC and wxClientDC even though their size is
2313 // not the same as the total size of the screen
2314 int wPixels
, hPixels
;
2315 DoGetSize(&wPixels
, &hPixels
);
2319 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2321 wxCHECK_RET( wTotal
, _T("0 width device?") );
2323 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2328 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2330 wxCHECK_RET( hTotal
, _T("0 height device?") );
2332 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2336 wxSize
wxDC::GetPPI() const
2338 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2340 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2341 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2343 return wxSize(x
, y
);
2346 // For use by wxWidgets only, unless custom units are required.
2347 void wxDC::SetLogicalScale(double x
, double y
)
2349 WXMICROWIN_CHECK_HDC
2351 wxDCBase::SetLogicalScale(x
,y
);
2354 // ----------------------------------------------------------------------------
2356 // ----------------------------------------------------------------------------
2358 #if wxUSE_DC_CACHEING
2361 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2362 * improve it in due course, either using arrays, or simply storing pointers to one
2363 * entry for the bitmap, and two for the DCs. -- JACS
2366 wxList
wxDC::sm_bitmapCache
;
2367 wxList
wxDC::sm_dcCache
;
2369 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2378 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2387 wxDCCacheEntry::~wxDCCacheEntry()
2390 ::DeleteObject((HBITMAP
) m_bitmap
);
2392 ::DeleteDC((HDC
) m_dc
);
2395 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2397 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2398 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2401 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2403 if (entry
->m_depth
== depth
)
2405 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2407 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2408 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2409 if ( !entry
->m_bitmap
)
2411 wxLogLastError(wxT("CreateCompatibleBitmap"));
2413 entry
->m_width
= w
; entry
->m_height
= h
;
2419 node
= node
->GetNext();
2421 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2424 wxLogLastError(wxT("CreateCompatibleBitmap"));
2426 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2427 AddToBitmapCache(entry
);
2431 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2433 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2434 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2437 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2439 // Don't return the same one as we already have
2440 if (!notThis
|| (notThis
!= entry
))
2442 if (entry
->m_depth
== depth
)
2448 node
= node
->GetNext();
2450 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2453 wxLogLastError(wxT("CreateCompatibleDC"));
2455 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2456 AddToDCCache(entry
);
2460 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2462 sm_bitmapCache
.Append(entry
);
2465 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2467 sm_dcCache
.Append(entry
);
2470 void wxDC::ClearCache()
2472 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2473 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2476 // Clean up cache at app exit
2477 class wxDCModule
: public wxModule
2480 virtual bool OnInit() { return true; }
2481 virtual void OnExit() { wxDC::ClearCache(); }
2484 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2487 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2489 #endif // wxUSE_DC_CACHEING
2491 // ----------------------------------------------------------------------------
2492 // alpha channel support
2493 // ----------------------------------------------------------------------------
2495 static bool AlphaBlt(HDC hdcDst
,
2496 int x
, int y
, int dstWidth
, int dstHeight
,
2498 int srcWidth
, int srcHeight
,
2500 const wxBitmap
& bmp
)
2502 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2503 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2505 // do we have AlphaBlend() and company in the headers?
2506 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2507 // yes, now try to see if we have it during run-time
2508 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2509 HDC
,int,int,int,int,
2513 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2514 if ( pfnAlphaBlend
)
2517 bf
.BlendOp
= AC_SRC_OVER
;
2519 bf
.SourceConstantAlpha
= 0xff;
2520 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2522 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2523 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2526 // skip wxAlphaBlend() call below
2530 wxLogLastError(_T("AlphaBlend"));
2533 wxUnusedVar(hdcSrc
);
2534 #endif // defined(AC_SRC_OVER)
2536 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2538 #ifdef wxHAVE_RAW_BITMAP
2539 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2542 #else // !wxHAVE_RAW_BITMAP
2543 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2544 // alpha but at least something will be shown like this)
2547 #endif // wxHAVE_RAW_BITMAP
2551 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2552 #ifdef wxHAVE_RAW_BITMAP
2555 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2556 int dstWidth
, int dstHeight
,
2558 int srcWidth
, int srcHeight
,
2559 const wxBitmap
& bmpSrc
)
2561 // get the destination DC pixels
2562 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2564 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2566 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2568 wxLogLastError(_T("BitBlt"));
2571 // combine them with the source bitmap using alpha
2572 wxAlphaPixelData
dataDst(bmpDst
),
2573 dataSrc((wxBitmap
&)bmpSrc
);
2575 wxCHECK_RET( dataDst
&& dataSrc
,
2576 _T("failed to get raw data in wxAlphaBlend") );
2578 wxAlphaPixelData::Iterator
pDst(dataDst
),
2582 for ( int y
= 0; y
< dstHeight
; y
++ )
2584 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2586 for ( int x
= 0; x
< dstWidth
; x
++ )
2588 // source is point sampled, Alpha StretchBlit is ugly on Win95
2589 // (but does not impact performance)
2590 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2592 // note that source bitmap uses premultiplied alpha (as required by
2593 // the real AlphaBlend)
2594 const unsigned beta
= 255 - pSrc
.Alpha();
2596 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2597 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2598 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2603 pDst
= pDstRowStart
;
2604 pDst
.OffsetY(dataDst
, 1);
2607 // and finally blit them back to the destination DC
2608 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2610 wxLogLastError(_T("BitBlt"));
2614 #endif // #ifdef wxHAVE_RAW_BITMAP
2616 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2617 const wxColour
& initialColour
,
2618 const wxColour
& destColour
,
2619 wxDirection nDirection
)
2621 // use native function if we have compile-time support it and can load it
2622 // during run-time (linking to it statically would make the program
2623 // unusable on earlier Windows versions)
2624 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2626 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2627 static GradientFill_t pfnGradientFill
=
2628 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2630 if ( pfnGradientFill
)
2632 GRADIENT_RECT grect
;
2633 grect
.UpperLeft
= 0;
2634 grect
.LowerRight
= 1;
2636 // invert colours direction if not filling from left-to-right or
2638 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2640 // one vertex for upper left and one for upper-right
2641 TRIVERTEX vertices
[2];
2643 vertices
[0].x
= rect
.GetLeft();
2644 vertices
[0].y
= rect
.GetTop();
2645 vertices
[1].x
= rect
.GetRight()+1;
2646 vertices
[1].y
= rect
.GetBottom()+1;
2648 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2649 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2650 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2651 vertices
[firstVertex
].Alpha
= 0;
2652 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2653 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2654 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2655 vertices
[1 - firstVertex
].Alpha
= 0;
2657 if ( (*pfnGradientFill
)
2664 nDirection
== wxWEST
|| nDirection
== wxEAST
2665 ? GRADIENT_FILL_RECT_H
2666 : GRADIENT_FILL_RECT_V
2669 // skip call of the base class version below
2673 wxLogLastError(_T("GradientFill"));
2675 #endif // wxUSE_DYNLIB_CLASS
2677 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2680 #if wxUSE_DYNLIB_CLASS
2682 static DWORD
wxGetDCLayout(HDC hdc
)
2684 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2686 pfnGetLayout
= (GetLayout_t
)wxGDI32DLL
.GetSymbol(_T("GetLayout"));
2688 return pfnGetLayout
? pfnGetLayout(hdc
) : (DWORD
)-1;
2691 wxLayoutDirection
wxDC::GetLayoutDirection() const
2693 DWORD layout
= wxGetDCLayout(GetHdc());
2695 if ( layout
== (DWORD
)-1 )
2696 return wxLayout_Default
;
2698 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2701 void wxDC::SetLayoutDirection(wxLayoutDirection dir
)
2703 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2705 pfnSetLayout
= (SetLayout_t
)wxGDI32DLL
.GetSymbol(_T("SetLayout"));
2706 if ( !pfnSetLayout
)
2709 if ( dir
== wxLayout_Default
)
2711 dir
= wxTheApp
->GetLayoutDirection();
2712 if ( dir
== wxLayout_Default
)
2716 DWORD layout
= wxGetDCLayout(GetHdc());
2717 if ( dir
== wxLayout_RightToLeft
)
2718 layout
|= LAYOUT_RTL
;
2720 layout
&= ~LAYOUT_RTL
;
2722 pfnSetLayout(GetHdc(), layout
);
2725 #else // !wxUSE_DYNLIB_CLASS
2727 // we can't provide RTL support without dynamic loading, so stub it out
2728 wxLayoutDirection
wxDC::GetLayoutDirection() const
2730 return wxLayout_Default
;
2733 void wxDC::SetLayoutDirection(wxLayoutDirection
WXUNUSED(dir
))
2737 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS