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 // helper class to cache dynamically loaded libraries and not attempt reloading
210 class wxOnceOnlyDLLLoader
213 // ctor argument must be a literal string as we don't make a copy of it!
214 wxOnceOnlyDLLLoader(const wxChar
*dllName
)
220 // return the symbol with the given name or NULL if the DLL not loaded
221 // or symbol not present
222 void *GetSymbol(const wxChar
*name
)
224 // we're prepared to handle errors here
229 m_dll
.Load(m_dllName
);
231 // reset the name whether we succeeded or failed so that we don't
232 // try again the next time
236 return m_dll
.IsLoaded() ? m_dll
.GetSymbol(name
) : NULL
;
240 wxDynamicLibrary m_dll
;
241 const wxChar
*m_dllName
;
244 static wxOnceOnlyDLLLoader
wxGDI32DLL(_T("gdi32"));
245 static wxOnceOnlyDLLLoader
wxMSIMG32DLL(_T("msimg32"));
247 // ===========================================================================
249 // ===========================================================================
251 // ----------------------------------------------------------------------------
253 // ----------------------------------------------------------------------------
255 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
257 const wxBrush
& brush
= dc
.GetBrush();
258 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
260 HDC hdc
= GetHdcOf(dc
);
261 m_colFgOld
= ::GetTextColor(hdc
);
262 m_colBgOld
= ::GetBkColor(hdc
);
264 // note that Windows convention is opposite to wxWidgets one, this is
265 // why text colour becomes the background one and vice versa
266 const wxColour
& colFg
= dc
.GetTextForeground();
269 ::SetBkColor(hdc
, colFg
.GetPixel());
272 const wxColour
& colBg
= dc
.GetTextBackground();
275 ::SetTextColor(hdc
, colBg
.GetPixel());
279 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
282 // flag which telsl us to undo changes in the dtor
287 // nothing done, nothing to undo
292 wxColourChanger::~wxColourChanger()
296 // restore the colours we changed
297 HDC hdc
= GetHdcOf(m_dc
);
299 ::SetBkMode(hdc
, TRANSPARENT
);
300 ::SetTextColor(hdc
, m_colFgOld
);
301 ::SetBkColor(hdc
, m_colBgOld
);
305 // ---------------------------------------------------------------------------
307 // ---------------------------------------------------------------------------
313 SelectOldObjects(m_hDC
);
315 // if we own the HDC, we delete it, otherwise we just release it
319 ::DeleteDC(GetHdc());
321 else // we don't own our HDC
325 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
329 // Must have been a wxScreenDC
330 ::ReleaseDC((HWND
) NULL
, GetHdc());
336 // This will select current objects out of the DC,
337 // which is what you have to do before deleting the
339 void wxDC::SelectOldObjects(WXHDC dc
)
345 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
347 if (m_selectedBitmap
.Ok())
349 m_selectedBitmap
.SetSelectedInto(NULL
);
356 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
361 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
366 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
373 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
376 #endif // wxUSE_PALETTE
379 m_brush
= wxNullBrush
;
382 m_palette
= wxNullPalette
;
383 #endif // wxUSE_PALETTE
385 m_backgroundBrush
= wxNullBrush
;
386 m_selectedBitmap
= wxNullBitmap
;
389 // ---------------------------------------------------------------------------
391 // ---------------------------------------------------------------------------
393 void wxDC::UpdateClipBox()
398 ::GetClipBox(GetHdc(), &rect
);
400 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
401 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
402 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
403 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
407 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
409 // check if we should try to retrieve the clipping region possibly not set
410 // by our SetClippingRegion() but preset by Windows:this can only happen
411 // when we're associated with an existing HDC usign SetHDC(), see there
412 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
414 wxDC
*self
= wxConstCast(this, wxDC
);
415 self
->UpdateClipBox();
417 if ( !m_clipX1
&& !m_clipX2
)
418 self
->m_clipping
= false;
421 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
424 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
425 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
427 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
431 // note that we combine the new clipping region with the existing one: this
432 // is compatible with what the other ports do and is the documented
433 // behaviour now (starting with 2.3.3)
434 #if defined(__WXWINCE__)
436 if ( !::GetClipBox(GetHdc(), &rectClip
) )
439 // GetClipBox returns logical coordinates, so transform to device
440 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
441 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
442 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
443 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
445 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
446 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
447 rectClip
.right
, rectClip
.bottom
);
449 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
451 ::SelectClipRgn(GetHdc(), hrgnDest
);
454 ::DeleteObject(hrgnClipOld
);
455 ::DeleteObject(hrgnDest
);
457 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
459 wxLogLastError(_T("ExtSelectClipRgn"));
463 #endif // WinCE/!WinCE
470 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
472 // the region coords are always the device ones, so do the translation
475 // FIXME: possible +/-1 error here, to check!
476 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
478 LogicalToDeviceX(x
+ w
),
479 LogicalToDeviceY(y
+ h
));
482 wxLogLastError(_T("CreateRectRgn"));
486 SetClippingHrgn((WXHRGN
)hrgn
);
488 ::DeleteObject(hrgn
);
492 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
494 SetClippingHrgn(region
.GetHRGN());
497 void wxDC::DestroyClippingRegion()
501 if (m_clipping
&& m_hDC
)
504 // On a PocketPC device (not necessarily emulator), resetting
505 // the clip region as per the old method causes bad display
506 // problems. In fact setting a null region is probably OK
507 // on desktop WIN32 also, since the WIN32 docs imply that the user
508 // clipping region is independent from the paint clipping region.
509 ::SelectClipRgn(GetHdc(), 0);
511 // TODO: this should restore the previous clipping region,
512 // so that OnPaint processing works correctly, and the update
513 // clipping region doesn't get destroyed after the first
514 // DestroyClippingRegion.
515 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
516 ::SelectClipRgn(GetHdc(), rgn
);
521 wxDCBase::DestroyClippingRegion();
524 // ---------------------------------------------------------------------------
525 // query capabilities
526 // ---------------------------------------------------------------------------
528 bool wxDC::CanDrawBitmap() const
533 bool wxDC::CanGetTextExtent() const
535 #ifdef __WXMICROWIN__
536 // TODO Extend MicroWindows' GetDeviceCaps function
539 // What sort of display is it?
540 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
542 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
546 int wxDC::GetDepth() const
548 WXMICROWIN_CHECK_HDC_RET(16)
550 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
553 // ---------------------------------------------------------------------------
555 // ---------------------------------------------------------------------------
564 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
568 // No, I think we should simply ignore this if printing on e.g.
570 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
571 if (!m_selectedBitmap
.Ok())
574 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
575 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
576 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
580 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
583 DWORD colour
= ::GetBkColor(GetHdc());
584 HBRUSH brush
= ::CreateSolidBrush(colour
);
585 ::FillRect(GetHdc(), &rect
, brush
);
586 ::DeleteObject(brush
);
588 RealizeScaleAndOrigin();
591 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
592 wxCoord
WXUNUSED_IN_WINCE(y
),
593 const wxColour
& WXUNUSED_IN_WINCE(col
),
594 int WXUNUSED_IN_WINCE(style
))
599 WXMICROWIN_CHECK_HDC_RET(false)
601 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
603 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
604 : FLOODFILLBORDER
) ) ;
607 // quoting from the MSDN docs:
609 // Following are some of the reasons this function might fail:
611 // * The filling could not be completed.
612 // * The specified point has the boundary color specified by the
613 // crColor parameter (if FLOODFILLBORDER was requested).
614 // * The specified point does not have the color specified by
615 // crColor (if FLOODFILLSURFACE was requested)
616 // * The point is outside the clipping region that is, it is not
617 // visible on the device.
619 wxLogLastError(wxT("ExtFloodFill"));
622 CalcBoundingBox(x
, y
);
628 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
630 WXMICROWIN_CHECK_HDC_RET(false)
632 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
634 // get the color of the pixel
635 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
637 wxRGBToColour(*col
, pixelcolor
);
642 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
646 wxCoord x1
= x
-VIEWPORT_EXTENT
;
647 wxCoord y1
= y
-VIEWPORT_EXTENT
;
648 wxCoord x2
= x
+VIEWPORT_EXTENT
;
649 wxCoord y2
= y
+VIEWPORT_EXTENT
;
651 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
652 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
654 CalcBoundingBox(x1
, y1
);
655 CalcBoundingBox(x2
, y2
);
658 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
662 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
664 CalcBoundingBox(x1
, y1
);
665 CalcBoundingBox(x2
, y2
);
668 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
669 // and ending at (x2, y2)
670 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
671 wxCoord x2
, wxCoord y2
,
672 wxCoord xc
, wxCoord yc
)
675 // Slower emulation since WinCE doesn't support Pie and Arc
676 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
677 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
678 if( y1
>yc
) sa
= -sa
; // below center
679 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
680 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
685 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
689 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
690 wxCoord r
= (wxCoord
)radius
;
692 // treat the special case of full circle separately
693 if ( x1
== x2
&& y1
== y2
)
695 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
699 wxCoord xx1
= XLOG2DEV(x1
);
700 wxCoord yy1
= YLOG2DEV(y1
);
701 wxCoord xx2
= XLOG2DEV(x2
);
702 wxCoord yy2
= YLOG2DEV(y2
);
703 wxCoord xxc
= XLOG2DEV(xc
);
704 wxCoord yyc
= YLOG2DEV(yc
);
705 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
707 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
708 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
709 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
710 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
712 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
714 // Have to add 1 to bottom-right corner of rectangle
715 // to make semi-circles look right (crooked line otherwise).
716 // Unfortunately this is not a reliable method, depends
717 // on the size of shape.
718 // TODO: figure out why this happens!
719 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
723 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
726 CalcBoundingBox(xc
- r
, yc
- r
);
727 CalcBoundingBox(xc
+ r
, yc
+ r
);
731 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
732 wxCoord width
, wxCoord height
)
734 // cases when we don't have DrawFrameControl()
735 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
736 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
738 wxCoord x2
= x1
+ width
,
748 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
750 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
753 CalcBoundingBox(x1
, y1
);
754 CalcBoundingBox(x2
, y2
);
755 #endif // Microwin/Normal
758 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
762 COLORREF color
= 0x00ffffff;
765 color
= m_pen
.GetColour().GetPixel();
768 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
770 CalcBoundingBox(x
, y
);
773 void wxDC::DoDrawPolygon(int n
,
777 int WXUNUSED_IN_WINCE(fillStyle
))
781 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
783 // Do things less efficiently if we have offsets
784 if (xoffset
!= 0 || yoffset
!= 0)
786 POINT
*cpoints
= new POINT
[n
];
788 for (i
= 0; i
< n
; i
++)
790 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
791 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
793 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
796 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
798 (void)Polygon(GetHdc(), cpoints
, n
);
800 SetPolyFillMode(GetHdc(),prev
);
807 for (i
= 0; i
< n
; i
++)
808 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
811 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
813 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
815 SetPolyFillMode(GetHdc(),prev
);
821 wxDC::DoDrawPolyPolygon(int n
,
829 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
833 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
835 for (i
= cnt
= 0; i
< n
; i
++)
838 // Do things less efficiently if we have offsets
839 if (xoffset
!= 0 || yoffset
!= 0)
841 POINT
*cpoints
= new POINT
[cnt
];
842 for (i
= 0; i
< cnt
; i
++)
844 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
845 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
847 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
850 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
852 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
854 SetPolyFillMode(GetHdc(),prev
);
860 for (i
= 0; i
< cnt
; i
++)
861 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
864 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
866 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
868 SetPolyFillMode(GetHdc(),prev
);
875 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
879 // Do things less efficiently if we have offsets
880 if (xoffset
!= 0 || yoffset
!= 0)
882 POINT
*cpoints
= new POINT
[n
];
884 for (i
= 0; i
< n
; i
++)
886 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
887 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
889 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
891 (void)Polyline(GetHdc(), cpoints
, n
);
897 for (i
= 0; i
< n
; i
++)
898 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
900 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
904 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
908 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
910 wxCoord x2
= x
+ width
;
911 wxCoord y2
= y
+ height
;
913 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
916 rect
.left
= XLOG2DEV(x
);
917 rect
.top
= YLOG2DEV(y
);
918 rect
.right
= XLOG2DEV(x2
);
919 rect
.bottom
= YLOG2DEV(y2
);
920 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
924 // Windows draws the filled rectangles without outline (i.e. drawn with a
925 // transparent pen) one pixel smaller in both directions and we want them
926 // to have the same size regardless of which pen is used - adjust
928 // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
929 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
931 // Apparently not needed for WinCE (see e.g. Life! demo)
938 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
942 CalcBoundingBox(x
, y
);
943 CalcBoundingBox(x2
, y2
);
946 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
950 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
952 // Now, a negative radius value is interpreted to mean
953 // 'the proportion of the smallest X or Y dimension'
957 double smallest
= (width
< height
) ? width
: height
;
958 radius
= (- radius
* smallest
);
961 wxCoord x2
= (x
+width
);
962 wxCoord y2
= (y
+height
);
964 // Windows draws the filled rectangles without outline (i.e. drawn with a
965 // transparent pen) one pixel smaller in both directions and we want them
966 // to have the same size regardless of which pen is used - adjust
967 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
973 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
974 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
976 CalcBoundingBox(x
, y
);
977 CalcBoundingBox(x2
, y2
);
980 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
984 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
986 wxCoord x2
= (x
+width
);
987 wxCoord y2
= (y
+height
);
989 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
991 CalcBoundingBox(x
, y
);
992 CalcBoundingBox(x2
, y2
);
996 void wxDC::DoDrawSpline(wxList
*points
)
999 // WinCE does not support ::PolyBezier so use generic version
1000 wxDCBase::DoDrawSpline(points
);
1002 // quadratic b-spline to cubic bezier spline conversion
1004 // quadratic spline with control points P0,P1,P2
1005 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1007 // bezier spline with control points B0,B1,B2,B3
1008 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1010 // control points of bezier spline calculated from b-spline
1012 // B1 = (2*P1 + P0)/3
1013 // B2 = (2*P1 + P2)/3
1016 WXMICROWIN_CHECK_HDC
1018 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1020 const size_t n_points
= points
->GetCount();
1021 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1023 const size_t n_bezier_points
= n_points
* 3 + 1;
1024 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1025 size_t bezier_pos
= 0;
1026 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1028 wxList::compatibility_iterator node
= points
->GetFirst();
1029 wxPoint
*p
= (wxPoint
*)node
->GetData();
1030 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1031 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1033 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1036 node
= node
->GetNext();
1037 p
= (wxPoint
*)node
->GetData();
1041 cx1
= ( x1
+ x2
) / 2;
1042 cy1
= ( y1
+ y2
) / 2;
1043 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1044 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1046 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1050 while ((node
= node
->GetNext()) != NULL
)
1052 while ((node
= node
->GetNext()))
1053 #endif // !wxUSE_STL
1055 p
= (wxPoint
*)node
->GetData();
1060 cx4
= (x1
+ x2
) / 2;
1061 cy4
= (y1
+ y2
) / 2;
1062 // B0 is B3 of previous segment
1064 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1065 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1068 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1069 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1072 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1073 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1079 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1081 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1082 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1084 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1087 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1094 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1095 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1098 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1101 WXMICROWIN_CHECK_HDC
1103 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1108 int rx1
= XLOG2DEV(x
+w
/2);
1109 int ry1
= YLOG2DEV(y
+h
/2);
1116 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1117 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1118 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1119 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1121 // draw pie with NULL_PEN first and then outline otherwise a line is
1122 // drawn from the start and end points to the centre
1123 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1126 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1127 rx1
, ry1
, rx2
, ry2
);
1131 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1132 rx1
, ry1
-1, rx2
, ry2
-1);
1135 ::SelectObject(GetHdc(), hpenOld
);
1137 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1138 rx1
, ry1
, rx2
, ry2
);
1140 CalcBoundingBox(x
, y
);
1141 CalcBoundingBox(x2
, y2
);
1145 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1147 WXMICROWIN_CHECK_HDC
1149 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1152 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1154 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1157 CalcBoundingBox(x
, y
);
1158 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1161 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1163 WXMICROWIN_CHECK_HDC
1165 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1167 int width
= bmp
.GetWidth(),
1168 height
= bmp
.GetHeight();
1170 HBITMAP hbmpMask
= 0;
1173 HPALETTE oldPal
= 0;
1174 #endif // wxUSE_PALETTE
1176 if ( bmp
.HasAlpha() )
1179 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1181 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1187 wxMask
*mask
= bmp
.GetMask();
1189 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1193 // don't give assert here because this would break existing
1194 // programs - just silently ignore useMask parameter
1201 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1203 // On some systems, MaskBlt succeeds yet is much much slower
1204 // than the wxWidgets fall-back implementation. So we need
1205 // to be able to switch this on and off at runtime.
1207 #if wxUSE_SYSTEM_OPTIONS
1208 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1212 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1213 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1215 wxPalette
*pal
= bmp
.GetPalette();
1216 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1218 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1219 ::RealizePalette(hdcMem
);
1221 #endif // wxUSE_PALETTE
1223 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1226 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1230 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1231 #endif // wxUSE_PALETTE
1233 ::SelectObject(hdcMem
, hOldBitmap
);
1240 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1244 memDC
.SelectObjectAsSource(bmp
);
1246 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1248 memDC
.SelectObject(wxNullBitmap
);
1251 else // no mask, just use BitBlt()
1254 HDC memdc
= ::CreateCompatibleDC( cdc
);
1255 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1257 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1259 COLORREF old_textground
= ::GetTextColor(GetHdc());
1260 COLORREF old_background
= ::GetBkColor(GetHdc());
1261 if (m_textForegroundColour
.Ok())
1263 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1265 if (m_textBackgroundColour
.Ok())
1267 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1271 wxPalette
*pal
= bmp
.GetPalette();
1272 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1274 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1275 ::RealizePalette(memdc
);
1277 #endif // wxUSE_PALETTE
1279 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1280 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1284 ::SelectPalette(memdc
, oldPal
, FALSE
);
1285 #endif // wxUSE_PALETTE
1287 ::SelectObject( memdc
, hOldBitmap
);
1288 ::DeleteDC( memdc
);
1290 ::SetTextColor(GetHdc(), old_textground
);
1291 ::SetBkColor(GetHdc(), old_background
);
1295 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1297 WXMICROWIN_CHECK_HDC
1299 DrawAnyText(text
, x
, y
);
1301 // update the bounding box
1302 CalcBoundingBox(x
, y
);
1305 GetTextExtent(text
, &w
, &h
);
1306 CalcBoundingBox(x
+ w
, y
+ h
);
1309 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1311 WXMICROWIN_CHECK_HDC
1313 // prepare for drawing the text
1314 if ( m_textForegroundColour
.Ok() )
1315 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1317 DWORD old_background
= 0;
1318 if ( m_textBackgroundColour
.Ok() )
1320 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1323 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1327 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1328 text
.c_str(), text
.length(), NULL
) == 0 )
1330 wxLogLastError(wxT("TextOut"));
1333 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1334 text
.c_str(), text
.length()) == 0 )
1336 wxLogLastError(wxT("TextOut"));
1340 // restore the old parameters (text foreground colour may be left because
1341 // it never is set to anything else, but background should remain
1342 // transparent even if we just drew an opaque string)
1343 if ( m_textBackgroundColour
.Ok() )
1344 (void)SetBkColor(GetHdc(), old_background
);
1346 SetBkMode(GetHdc(), TRANSPARENT
);
1349 void wxDC::DoDrawRotatedText(const wxString
& text
,
1350 wxCoord x
, wxCoord y
,
1353 WXMICROWIN_CHECK_HDC
1355 // we test that we have some font because otherwise we should still use the
1356 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1357 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1358 // font for drawing rotated fonts unfortunately)
1359 if ( (angle
== 0.0) && m_font
.Ok() )
1361 DoDrawText(text
, x
, y
);
1363 #ifndef __WXMICROWIN__
1366 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1367 // because it's not TrueType and so can't have non zero
1368 // orientation/escapement under Win9x
1369 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1370 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1372 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1374 wxLogLastError(wxT("GetObject(hfont)"));
1377 // GDI wants the angle in tenth of degree
1378 long angle10
= (long)(angle
* 10);
1379 lf
.lfEscapement
= angle10
;
1380 lf
. lfOrientation
= angle10
;
1382 hfont
= ::CreateFontIndirect(&lf
);
1385 wxLogLastError(wxT("CreateFont"));
1389 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1391 DrawAnyText(text
, x
, y
);
1393 (void)::SelectObject(GetHdc(), hfontOld
);
1394 (void)::DeleteObject(hfont
);
1397 // call the bounding box by adding all four vertices of the rectangle
1398 // containing the text to it (simpler and probably not slower than
1399 // determining which of them is really topmost/leftmost/...)
1401 GetTextExtent(text
, &w
, &h
);
1403 double rad
= DegToRad(angle
);
1405 // "upper left" and "upper right"
1406 CalcBoundingBox(x
, y
);
1407 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1409 // "bottom left" and "bottom right"
1410 x
+= (wxCoord
)(h
*sin(rad
));
1411 y
+= (wxCoord
)(h
*cos(rad
));
1412 CalcBoundingBox(x
, y
);
1413 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1418 // ---------------------------------------------------------------------------
1420 // ---------------------------------------------------------------------------
1424 void wxDC::DoSelectPalette(bool realize
)
1426 WXMICROWIN_CHECK_HDC
1428 // Set the old object temporarily, in case the assignment deletes an object
1429 // that's not yet selected out.
1432 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1436 if ( m_palette
.Ok() )
1438 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1439 GetHpaletteOf(m_palette
),
1442 m_oldPalette
= (WXHPALETTE
) oldPal
;
1445 ::RealizePalette(GetHdc());
1449 void wxDC::SetPalette(const wxPalette
& palette
)
1453 m_palette
= palette
;
1454 DoSelectPalette(true);
1458 void wxDC::InitializePalette()
1460 if ( wxDisplayDepth() <= 8 )
1462 // look for any window or parent that has a custom palette. If any has
1463 // one then we need to use it in drawing operations
1464 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1466 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1467 if ( m_hasCustomPalette
)
1469 m_palette
= win
->GetPalette();
1471 // turn on MSW translation for this palette
1477 #endif // wxUSE_PALETTE
1479 // SetFont/Pen/Brush() really ask to be implemented as a single template
1480 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1482 void wxDC::SetFont(const wxFont
& font
)
1484 WXMICROWIN_CHECK_HDC
1486 if ( font
== m_font
)
1491 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1492 if ( hfont
== HGDI_ERROR
)
1494 wxLogLastError(_T("SelectObject(font)"));
1499 m_oldFont
= (WXHFONT
)hfont
;
1504 else // invalid font, reset the current font
1508 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1510 wxLogLastError(_T("SelectObject(old font)"));
1516 m_font
= wxNullFont
;
1520 void wxDC::SetPen(const wxPen
& pen
)
1522 WXMICROWIN_CHECK_HDC
1529 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1530 if ( hpen
== HGDI_ERROR
)
1532 wxLogLastError(_T("SelectObject(pen)"));
1537 m_oldPen
= (WXHPEN
)hpen
;
1542 else // invalid pen, reset the current pen
1546 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1548 wxLogLastError(_T("SelectObject(old pen)"));
1558 void wxDC::SetBrush(const wxBrush
& brush
)
1560 WXMICROWIN_CHECK_HDC
1562 if ( brush
== m_brush
)
1567 // we must make sure the brush is aligned with the logical coordinates
1568 // before selecting it
1569 wxBitmap
*stipple
= brush
.GetStipple();
1570 if ( stipple
&& stipple
->Ok() )
1572 if ( !::SetBrushOrgEx
1575 m_deviceOriginX
% stipple
->GetWidth(),
1576 m_deviceOriginY
% stipple
->GetHeight(),
1577 NULL
// [out] previous brush origin
1580 wxLogLastError(_T("SetBrushOrgEx()"));
1584 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1585 if ( hbrush
== HGDI_ERROR
)
1587 wxLogLastError(_T("SelectObject(brush)"));
1592 m_oldBrush
= (WXHBRUSH
)hbrush
;
1597 else // invalid brush, reset the current brush
1601 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1603 wxLogLastError(_T("SelectObject(old brush)"));
1609 m_brush
= wxNullBrush
;
1613 void wxDC::SetBackground(const wxBrush
& brush
)
1615 WXMICROWIN_CHECK_HDC
1617 m_backgroundBrush
= brush
;
1619 if ( m_backgroundBrush
.Ok() )
1621 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1625 void wxDC::SetBackgroundMode(int mode
)
1627 WXMICROWIN_CHECK_HDC
1629 m_backgroundMode
= mode
;
1631 // SetBackgroundColour now only refers to text background
1632 // and m_backgroundMode is used there
1635 void wxDC::SetLogicalFunction(int function
)
1637 WXMICROWIN_CHECK_HDC
1639 m_logicalFunction
= function
;
1644 void wxDC::SetRop(WXHDC dc
)
1646 if ( !dc
|| m_logicalFunction
< 0 )
1651 switch (m_logicalFunction
)
1653 case wxCLEAR
: rop
= R2_BLACK
; break;
1654 case wxXOR
: rop
= R2_XORPEN
; break;
1655 case wxINVERT
: rop
= R2_NOT
; break;
1656 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1657 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1658 case wxCOPY
: rop
= R2_COPYPEN
; break;
1659 case wxAND
: rop
= R2_MASKPEN
; break;
1660 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1661 case wxNO_OP
: rop
= R2_NOP
; break;
1662 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1663 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1664 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1665 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1666 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1667 case wxOR
: rop
= R2_MERGEPEN
; break;
1668 case wxSET
: rop
= R2_WHITE
; break;
1671 wxFAIL_MSG( wxT("unsupported logical function") );
1675 SetROP2(GetHdc(), rop
);
1678 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1680 // We might be previewing, so return true to let it continue.
1688 void wxDC::StartPage()
1692 void wxDC::EndPage()
1696 // ---------------------------------------------------------------------------
1698 // ---------------------------------------------------------------------------
1700 wxCoord
wxDC::GetCharHeight() const
1702 WXMICROWIN_CHECK_HDC_RET(0)
1704 TEXTMETRIC lpTextMetric
;
1706 GetTextMetrics(GetHdc(), &lpTextMetric
);
1708 return lpTextMetric
.tmHeight
;
1711 wxCoord
wxDC::GetCharWidth() const
1713 WXMICROWIN_CHECK_HDC_RET(0)
1715 TEXTMETRIC lpTextMetric
;
1717 GetTextMetrics(GetHdc(), &lpTextMetric
);
1719 return lpTextMetric
.tmAveCharWidth
;
1722 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1723 wxCoord
*descent
, wxCoord
*externalLeading
,
1724 const wxFont
*font
) const
1726 #ifdef __WXMICROWIN__
1731 if (descent
) *descent
= 0;
1732 if (externalLeading
) *externalLeading
= 0;
1735 #endif // __WXMICROWIN__
1740 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1742 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1744 else // don't change the font
1750 const size_t len
= string
.length();
1751 if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) )
1753 wxLogLastError(_T("GetTextExtentPoint32()"));
1756 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1757 // the result computed by GetTextExtentPoint32() may be too small as it
1758 // accounts for under/overhang of the first/last character while we want
1759 // just the bounding rect for this string so adjust the width as needed
1760 // (using API not available in 2002 SDKs of WinCE)
1764 const wxChar chFirst
= *string
.begin();
1765 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1767 if ( width
.abcA
< 0 )
1768 sizeRect
.cx
-= width
.abcA
;
1772 const wxChar chLast
= *string
.rbegin();
1773 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1775 //else: we already have the width of the last character
1777 if ( width
.abcC
< 0 )
1778 sizeRect
.cx
-= width
.abcC
;
1780 //else: GetCharABCWidths() failed, not a TrueType font?
1782 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1785 ::GetTextMetrics(GetHdc(), &tm
);
1792 *descent
= tm
.tmDescent
;
1793 if (externalLeading
)
1794 *externalLeading
= tm
.tmExternalLeading
;
1798 ::SelectObject(GetHdc(), hfontOld
);
1803 // Each element of the array will be the width of the string up to and
1804 // including the coresoponding character in text.
1806 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1808 static int maxLenText
= -1;
1809 static int maxWidth
= -1;
1812 int stlen
= text
.length();
1814 if (maxLenText
== -1)
1816 // Win9x and WinNT+ have different limits
1817 int version
= wxGetOsVersion();
1818 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1819 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1823 widths
.Add(0, stlen
); // fill the array with zeros
1827 if (!::GetTextExtentExPoint(GetHdc(),
1828 text
.c_str(), // string to check
1829 wxMin(stlen
, maxLenText
),
1831 &fit
, // [out] count of chars
1833 &widths
[0], // array to fill
1837 wxLogLastError(wxT("GetTextExtentExPoint"));
1844 void wxDC::RealizeScaleAndOrigin()
1846 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1847 // cases we could do with MM_TEXT and in the remaining 0.9% with
1848 // MM_ISOTROPIC (TODO!)
1850 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1852 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1853 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1855 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1856 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1858 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1859 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1864 void wxDC::SetMapMode(int mode
)
1866 WXMICROWIN_CHECK_HDC
1868 m_mappingMode
= mode
;
1870 if ( mode
== wxMM_TEXT
)
1873 m_logicalScaleY
= 1.0;
1875 else // need to do some calculations
1877 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1878 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1879 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1880 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1882 if ( (mm_width
== 0) || (mm_height
== 0) )
1884 // we can't calculate mm2pixels[XY] then!
1888 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1889 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1894 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1895 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1899 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1900 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1904 m_logicalScaleX
= mm2pixelsX
;
1905 m_logicalScaleY
= mm2pixelsY
;
1909 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1910 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1914 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1918 ComputeScaleAndOrigin();
1920 RealizeScaleAndOrigin();
1923 void wxDC::SetUserScale(double x
, double y
)
1925 WXMICROWIN_CHECK_HDC
1927 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1930 wxDCBase::SetUserScale(x
,y
);
1932 RealizeScaleAndOrigin();
1935 void wxDC::SetAxisOrientation(bool xLeftRight
,
1938 WXMICROWIN_CHECK_HDC
1940 int signX
= xLeftRight
? 1 : -1,
1941 signY
= yBottomUp
? -1 : 1;
1943 if (signX
== m_signX
&& signY
== m_signY
)
1946 wxDCBase::SetAxisOrientation( xLeftRight
, yBottomUp
);
1948 RealizeScaleAndOrigin();
1951 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1953 WXMICROWIN_CHECK_HDC
1955 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1958 wxDCBase::SetLogicalOrigin( x
, y
);
1961 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1965 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1967 WXMICROWIN_CHECK_HDC
1969 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1972 wxDCBase::SetDeviceOrigin( x
, y
);
1974 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1977 // ---------------------------------------------------------------------------
1979 // ---------------------------------------------------------------------------
1981 bool wxDC::DoBlit(wxCoord dstX
, wxCoord dstY
,
1982 wxCoord dstWidth
, wxCoord dstHeight
,
1984 wxCoord srcX
, wxCoord srcY
,
1985 int rop
, bool useMask
,
1986 wxCoord srcMaskX
, wxCoord srcMaskY
)
1988 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
1991 bool wxDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
1992 wxCoord dstWidth
, wxCoord dstHeight
,
1994 wxCoord xsrc
, wxCoord ysrc
,
1995 wxCoord srcWidth
, wxCoord srcHeight
,
1996 int rop
, bool useMask
,
1997 wxCoord xsrcMask
, wxCoord ysrcMask
)
1999 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2001 WXMICROWIN_CHECK_HDC_RET(false)
2003 // if either the source or destination has alpha channel, we must use
2004 // AlphaBlt() as other function don't handle it correctly
2005 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2006 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2007 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2009 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2010 xsrc
, ysrc
, srcWidth
, srcHeight
, GetHdcOf(*source
), bmpSrc
) )
2014 wxMask
*mask
= NULL
;
2017 mask
= bmpSrc
.GetMask();
2019 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2021 // don't give assert here because this would break existing
2022 // programs - just silently ignore useMask parameter
2027 if (xsrcMask
== -1 && ysrcMask
== -1)
2029 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2032 COLORREF old_textground
= ::GetTextColor(GetHdc());
2033 COLORREF old_background
= ::GetBkColor(GetHdc());
2034 if (m_textForegroundColour
.Ok())
2036 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2038 if (m_textBackgroundColour
.Ok())
2040 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2046 case wxXOR
: dwRop
= SRCINVERT
; break;
2047 case wxINVERT
: dwRop
= DSTINVERT
; break;
2048 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2049 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2050 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2051 case wxSET
: dwRop
= WHITENESS
; break;
2052 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2053 case wxAND
: dwRop
= SRCAND
; break;
2054 case wxOR
: dwRop
= SRCPAINT
; break;
2055 case wxEQUIV
: dwRop
= 0x00990066; break;
2056 case wxNAND
: dwRop
= 0x007700E6; break;
2057 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2058 case wxCOPY
: dwRop
= SRCCOPY
; break;
2059 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2060 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2061 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2063 wxFAIL_MSG( wxT("unsupported logical function") );
2067 bool success
= false;
2072 // we want the part of the image corresponding to the mask to be
2073 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2074 // meaning of fg and bg is inverted which corresponds to wxWin notion
2075 // of the mask which is also contrary to the Windows one)
2077 // On some systems, MaskBlt succeeds yet is much much slower
2078 // than the wxWidgets fall-back implementation. So we need
2079 // to be able to switch this on and off at runtime.
2080 #if wxUSE_SYSTEM_OPTIONS
2081 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2084 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2089 xdest
, ydest
, dstWidth
, dstHeight
,
2092 (HBITMAP
)mask
->GetMaskBitmap(),
2094 MAKEROP4(dwRop
, DSTCOPY
)
2102 // Blit bitmap with mask
2105 HBITMAP buffer_bmap
;
2107 #if wxUSE_DC_CACHEING
2108 // create a temp buffer bitmap and DCs to access it and the mask
2109 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2110 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2112 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2113 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2115 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2116 dstWidth
, dstHeight
);
2118 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2119 #else // !wxUSE_DC_CACHEING
2120 // create a temp buffer bitmap and DCs to access it and the mask
2121 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2122 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2123 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2124 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2125 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2126 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2128 // copy dest to buffer
2129 if ( !::BitBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2130 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2132 wxLogLastError(wxT("BitBlt"));
2136 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2139 // copy src to buffer using selected raster op
2140 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2141 GetHdcOf(*source
), xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2143 wxLogLastError(wxT("StretchBlt"));
2146 // set masked area in buffer to BLACK (pixel value 0)
2147 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2148 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2149 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2150 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2152 wxLogLastError(wxT("StretchBlt"));
2155 // set unmasked area in dest to BLACK
2156 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2157 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2158 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, (int)dstWidth
, (int)dstHeight
,
2159 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2161 wxLogLastError(wxT("StretchBlt"));
2163 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2164 ::SetTextColor(GetHdc(), prevCol
);
2166 // OR buffer to dest
2167 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2168 (int)dstWidth
, (int)dstHeight
,
2169 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2172 wxLogLastError(wxT("BitBlt"));
2175 // tidy up temporary DCs and bitmap
2176 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2177 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2179 #if !wxUSE_DC_CACHEING
2181 ::DeleteDC(dc_mask
);
2182 ::DeleteDC(dc_buffer
);
2183 ::DeleteObject(buffer_bmap
);
2188 else // no mask, just BitBlt() it
2190 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2191 // use StretchBlt() if available and finally fall back to BitBlt()
2193 // FIXME: use appropriate WinCE functions
2195 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2196 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2201 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2203 &ds
) == sizeof(ds
) )
2205 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2207 // Figure out what co-ordinate system we're supposed to specify
2209 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2213 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2216 if ( ::StretchDIBits(GetHdc(),
2218 dstWidth
, dstHeight
,
2220 srcWidth
, srcHeight
,
2222 (LPBITMAPINFO
)&ds
.dsBmih
,
2225 ) == (int)GDI_ERROR
)
2227 // On Win9x this API fails most (all?) of the time, so
2228 // logging it becomes quite distracting. Since it falls
2229 // back to the code below this is not really serious, so
2231 //wxLogLastError(wxT("StretchDIBits"));
2240 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2245 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2251 xdest
, ydest
, dstWidth
, dstHeight
,
2253 xsrc
, ysrc
, srcWidth
, srcHeight
,
2257 wxLogLastError(_T("StretchBlt"));
2271 (int)dstWidth
, (int)dstHeight
,
2277 wxLogLastError(_T("BitBlt"));
2286 ::SetTextColor(GetHdc(), old_textground
);
2287 ::SetBkColor(GetHdc(), old_background
);
2292 void wxDC::GetDeviceSize(int *width
, int *height
) const
2294 WXMICROWIN_CHECK_HDC
2297 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2299 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2302 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2304 WXMICROWIN_CHECK_HDC
2306 // if we implement it in terms of DoGetSize() instead of directly using the
2307 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2308 // will also work for wxWindowDC and wxClientDC even though their size is
2309 // not the same as the total size of the screen
2310 int wPixels
, hPixels
;
2311 DoGetSize(&wPixels
, &hPixels
);
2315 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2317 wxCHECK_RET( wTotal
, _T("0 width device?") );
2319 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2324 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2326 wxCHECK_RET( hTotal
, _T("0 height device?") );
2328 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2332 wxSize
wxDC::GetPPI() const
2334 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2336 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2337 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2339 return wxSize(x
, y
);
2342 // For use by wxWidgets only, unless custom units are required.
2343 void wxDC::SetLogicalScale(double x
, double y
)
2345 WXMICROWIN_CHECK_HDC
2347 wxDCBase::SetLogicalScale(x
,y
);
2350 // ----------------------------------------------------------------------------
2352 // ----------------------------------------------------------------------------
2354 #if wxUSE_DC_CACHEING
2357 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2358 * improve it in due course, either using arrays, or simply storing pointers to one
2359 * entry for the bitmap, and two for the DCs. -- JACS
2362 wxList
wxDC::sm_bitmapCache
;
2363 wxList
wxDC::sm_dcCache
;
2365 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2374 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2383 wxDCCacheEntry::~wxDCCacheEntry()
2386 ::DeleteObject((HBITMAP
) m_bitmap
);
2388 ::DeleteDC((HDC
) m_dc
);
2391 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2393 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2394 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2397 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2399 if (entry
->m_depth
== depth
)
2401 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2403 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2404 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2405 if ( !entry
->m_bitmap
)
2407 wxLogLastError(wxT("CreateCompatibleBitmap"));
2409 entry
->m_width
= w
; entry
->m_height
= h
;
2415 node
= node
->GetNext();
2417 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2420 wxLogLastError(wxT("CreateCompatibleBitmap"));
2422 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2423 AddToBitmapCache(entry
);
2427 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2429 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2430 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2433 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2435 // Don't return the same one as we already have
2436 if (!notThis
|| (notThis
!= entry
))
2438 if (entry
->m_depth
== depth
)
2444 node
= node
->GetNext();
2446 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2449 wxLogLastError(wxT("CreateCompatibleDC"));
2451 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2452 AddToDCCache(entry
);
2456 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2458 sm_bitmapCache
.Append(entry
);
2461 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2463 sm_dcCache
.Append(entry
);
2466 void wxDC::ClearCache()
2468 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2469 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2472 // Clean up cache at app exit
2473 class wxDCModule
: public wxModule
2476 virtual bool OnInit() { return true; }
2477 virtual void OnExit() { wxDC::ClearCache(); }
2480 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2483 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2485 #endif // wxUSE_DC_CACHEING
2487 // ----------------------------------------------------------------------------
2488 // alpha channel support
2489 // ----------------------------------------------------------------------------
2491 static bool AlphaBlt(HDC hdcDst
,
2492 int x
, int y
, int dstWidth
, int dstHeight
,
2494 int srcWidth
, int srcHeight
,
2496 const wxBitmap
& bmp
)
2498 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2499 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2501 // do we have AlphaBlend() and company in the headers?
2502 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2503 // yes, now try to see if we have it during run-time
2504 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2505 HDC
,int,int,int,int,
2509 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2510 if ( pfnAlphaBlend
)
2513 bf
.BlendOp
= AC_SRC_OVER
;
2515 bf
.SourceConstantAlpha
= 0xff;
2516 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2518 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2519 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2522 // skip wxAlphaBlend() call below
2526 wxLogLastError(_T("AlphaBlend"));
2529 wxUnusedVar(hdcSrc
);
2530 #endif // defined(AC_SRC_OVER)
2532 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2534 #ifdef wxHAVE_RAW_BITMAP
2535 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2538 #else // !wxHAVE_RAW_BITMAP
2539 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2540 // alpha but at least something will be shown like this)
2543 #endif // wxHAVE_RAW_BITMAP
2547 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2548 #ifdef wxHAVE_RAW_BITMAP
2551 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2552 int dstWidth
, int dstHeight
,
2554 int srcWidth
, int srcHeight
,
2555 const wxBitmap
& bmpSrc
)
2557 // get the destination DC pixels
2558 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2560 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2562 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2564 wxLogLastError(_T("BitBlt"));
2567 // combine them with the source bitmap using alpha
2568 wxAlphaPixelData
dataDst(bmpDst
),
2569 dataSrc((wxBitmap
&)bmpSrc
);
2571 wxCHECK_RET( dataDst
&& dataSrc
,
2572 _T("failed to get raw data in wxAlphaBlend") );
2574 wxAlphaPixelData::Iterator
pDst(dataDst
),
2578 for ( int y
= 0; y
< dstHeight
; y
++ )
2580 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2582 for ( int x
= 0; x
< dstWidth
; x
++ )
2584 // source is point sampled, Alpha StretchBlit is ugly on Win95
2585 // (but does not impact performance)
2586 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2588 // note that source bitmap uses premultiplied alpha (as required by
2589 // the real AlphaBlend)
2590 const unsigned beta
= 255 - pSrc
.Alpha();
2592 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2593 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2594 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2599 pDst
= pDstRowStart
;
2600 pDst
.OffsetY(dataDst
, 1);
2603 // and finally blit them back to the destination DC
2604 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2606 wxLogLastError(_T("BitBlt"));
2610 #endif // #ifdef wxHAVE_RAW_BITMAP
2612 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2613 const wxColour
& initialColour
,
2614 const wxColour
& destColour
,
2615 wxDirection nDirection
)
2617 // use native function if we have compile-time support it and can load it
2618 // during run-time (linking to it statically would make the program
2619 // unusable on earlier Windows versions)
2620 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2622 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2623 static GradientFill_t pfnGradientFill
=
2624 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2626 if ( pfnGradientFill
)
2628 GRADIENT_RECT grect
;
2629 grect
.UpperLeft
= 0;
2630 grect
.LowerRight
= 1;
2632 // invert colours direction if not filling from left-to-right or
2634 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2636 // one vertex for upper left and one for upper-right
2637 TRIVERTEX vertices
[2];
2639 vertices
[0].x
= rect
.GetLeft();
2640 vertices
[0].y
= rect
.GetTop();
2641 vertices
[1].x
= rect
.GetRight()+1;
2642 vertices
[1].y
= rect
.GetBottom()+1;
2644 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2645 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2646 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2647 vertices
[firstVertex
].Alpha
= 0;
2648 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2649 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2650 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2651 vertices
[1 - firstVertex
].Alpha
= 0;
2653 if ( (*pfnGradientFill
)
2660 nDirection
== wxWEST
|| nDirection
== wxEAST
2661 ? GRADIENT_FILL_RECT_H
2662 : GRADIENT_FILL_RECT_V
2665 // skip call of the base class version below
2669 wxLogLastError(_T("GradientFill"));
2671 #endif // wxUSE_DYNLIB_CLASS
2673 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2676 static DWORD
wxGetDCLayout(HDC hdc
)
2678 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2680 pfnGetLayout
= (GetLayout_t
)wxGDI32DLL
.GetSymbol(_T("GetLayout"));
2682 return pfnGetLayout
? pfnGetLayout(hdc
) : (DWORD
)-1;
2685 wxLayoutDirection
wxDC::GetLayoutDirection() const
2687 DWORD layout
= wxGetDCLayout(GetHdc());
2689 if ( layout
== (DWORD
)-1 )
2690 return wxLayout_Default
;
2692 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2695 void wxDC::SetLayoutDirection(wxLayoutDirection dir
)
2697 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2699 pfnSetLayout
= (SetLayout_t
)wxGDI32DLL
.GetSymbol(_T("SetLayout"));
2700 if ( !pfnSetLayout
)
2703 if ( dir
== wxLayout_Default
)
2705 dir
= wxTheApp
->GetLayoutDirection();
2706 if ( dir
== wxLayout_Default
)
2710 DWORD layout
= wxGetDCLayout(GetHdc());
2711 if ( dir
== wxLayout_RightToLeft
)
2712 layout
|= LAYOUT_RTL
;
2714 layout
&= ~LAYOUT_RTL
;
2716 pfnSetLayout(GetHdc(), layout
);