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
);
589 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
590 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
592 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
594 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
595 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
596 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
597 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
601 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
602 wxCoord
WXUNUSED_IN_WINCE(y
),
603 const wxColour
& WXUNUSED_IN_WINCE(col
),
604 int WXUNUSED_IN_WINCE(style
))
609 WXMICROWIN_CHECK_HDC_RET(false)
611 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
613 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
614 : FLOODFILLBORDER
) ) ;
617 // quoting from the MSDN docs:
619 // Following are some of the reasons this function might fail:
621 // * The filling could not be completed.
622 // * The specified point has the boundary color specified by the
623 // crColor parameter (if FLOODFILLBORDER was requested).
624 // * The specified point does not have the color specified by
625 // crColor (if FLOODFILLSURFACE was requested)
626 // * The point is outside the clipping region that is, it is not
627 // visible on the device.
629 wxLogLastError(wxT("ExtFloodFill"));
632 CalcBoundingBox(x
, y
);
638 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
640 WXMICROWIN_CHECK_HDC_RET(false)
642 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
644 // get the color of the pixel
645 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
647 wxRGBToColour(*col
, pixelcolor
);
652 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
656 wxCoord x1
= x
-VIEWPORT_EXTENT
;
657 wxCoord y1
= y
-VIEWPORT_EXTENT
;
658 wxCoord x2
= x
+VIEWPORT_EXTENT
;
659 wxCoord y2
= y
+VIEWPORT_EXTENT
;
661 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
662 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
664 CalcBoundingBox(x1
, y1
);
665 CalcBoundingBox(x2
, y2
);
668 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
672 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
674 CalcBoundingBox(x1
, y1
);
675 CalcBoundingBox(x2
, y2
);
678 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
679 // and ending at (x2, y2)
680 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
681 wxCoord x2
, wxCoord y2
,
682 wxCoord xc
, wxCoord yc
)
685 // Slower emulation since WinCE doesn't support Pie and Arc
686 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
687 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
688 if( y1
>yc
) sa
= -sa
; // below center
689 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
690 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
695 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
699 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
700 wxCoord r
= (wxCoord
)radius
;
702 // treat the special case of full circle separately
703 if ( x1
== x2
&& y1
== y2
)
705 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
709 wxCoord xx1
= XLOG2DEV(x1
);
710 wxCoord yy1
= YLOG2DEV(y1
);
711 wxCoord xx2
= XLOG2DEV(x2
);
712 wxCoord yy2
= YLOG2DEV(y2
);
713 wxCoord xxc
= XLOG2DEV(xc
);
714 wxCoord yyc
= YLOG2DEV(yc
);
715 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
717 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
718 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
719 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
720 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
722 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
724 // Have to add 1 to bottom-right corner of rectangle
725 // to make semi-circles look right (crooked line otherwise).
726 // Unfortunately this is not a reliable method, depends
727 // on the size of shape.
728 // TODO: figure out why this happens!
729 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
733 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
736 CalcBoundingBox(xc
- r
, yc
- r
);
737 CalcBoundingBox(xc
+ r
, yc
+ r
);
741 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
742 wxCoord width
, wxCoord height
)
744 // cases when we don't have DrawFrameControl()
745 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
746 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
748 wxCoord x2
= x1
+ width
,
758 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
760 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
763 CalcBoundingBox(x1
, y1
);
764 CalcBoundingBox(x2
, y2
);
765 #endif // Microwin/Normal
768 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
772 COLORREF color
= 0x00ffffff;
775 color
= m_pen
.GetColour().GetPixel();
778 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
780 CalcBoundingBox(x
, y
);
783 void wxDC::DoDrawPolygon(int n
,
787 int WXUNUSED_IN_WINCE(fillStyle
))
791 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
793 // Do things less efficiently if we have offsets
794 if (xoffset
!= 0 || yoffset
!= 0)
796 POINT
*cpoints
= new POINT
[n
];
798 for (i
= 0; i
< n
; i
++)
800 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
801 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
803 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
806 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
808 (void)Polygon(GetHdc(), cpoints
, n
);
810 SetPolyFillMode(GetHdc(),prev
);
817 for (i
= 0; i
< n
; i
++)
818 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
821 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
823 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
825 SetPolyFillMode(GetHdc(),prev
);
831 wxDC::DoDrawPolyPolygon(int n
,
839 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
843 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
845 for (i
= cnt
= 0; i
< n
; i
++)
848 // Do things less efficiently if we have offsets
849 if (xoffset
!= 0 || yoffset
!= 0)
851 POINT
*cpoints
= new POINT
[cnt
];
852 for (i
= 0; i
< cnt
; i
++)
854 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
855 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
857 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
860 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
862 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
864 SetPolyFillMode(GetHdc(),prev
);
870 for (i
= 0; i
< cnt
; i
++)
871 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
874 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
876 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
878 SetPolyFillMode(GetHdc(),prev
);
885 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
889 // Do things less efficiently if we have offsets
890 if (xoffset
!= 0 || yoffset
!= 0)
892 POINT
*cpoints
= new POINT
[n
];
894 for (i
= 0; i
< n
; i
++)
896 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
897 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
899 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
901 (void)Polyline(GetHdc(), cpoints
, n
);
907 for (i
= 0; i
< n
; i
++)
908 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
910 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
914 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
918 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
920 wxCoord x2
= x
+ width
;
921 wxCoord y2
= y
+ height
;
923 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
926 rect
.left
= XLOG2DEV(x
);
927 rect
.top
= YLOG2DEV(y
);
928 rect
.right
= XLOG2DEV(x2
);
929 rect
.bottom
= YLOG2DEV(y2
);
930 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
934 // Windows draws the filled rectangles without outline (i.e. drawn with a
935 // transparent pen) one pixel smaller in both directions and we want them
936 // to have the same size regardless of which pen is used - adjust
938 // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
939 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
941 // Apparently not needed for WinCE (see e.g. Life! demo)
948 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
952 CalcBoundingBox(x
, y
);
953 CalcBoundingBox(x2
, y2
);
956 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
960 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
962 // Now, a negative radius value is interpreted to mean
963 // 'the proportion of the smallest X or Y dimension'
967 double smallest
= (width
< height
) ? width
: height
;
968 radius
= (- radius
* smallest
);
971 wxCoord x2
= (x
+width
);
972 wxCoord y2
= (y
+height
);
974 // Windows draws the filled rectangles without outline (i.e. drawn with a
975 // transparent pen) one pixel smaller in both directions and we want them
976 // to have the same size regardless of which pen is used - adjust
977 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
983 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
984 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
986 CalcBoundingBox(x
, y
);
987 CalcBoundingBox(x2
, y2
);
990 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
994 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
996 wxCoord x2
= (x
+width
);
997 wxCoord y2
= (y
+height
);
999 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
1001 CalcBoundingBox(x
, y
);
1002 CalcBoundingBox(x2
, y2
);
1006 void wxDC::DoDrawSpline(wxList
*points
)
1009 // WinCE does not support ::PolyBezier so use generic version
1010 wxDCBase::DoDrawSpline(points
);
1012 // quadratic b-spline to cubic bezier spline conversion
1014 // quadratic spline with control points P0,P1,P2
1015 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1017 // bezier spline with control points B0,B1,B2,B3
1018 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1020 // control points of bezier spline calculated from b-spline
1022 // B1 = (2*P1 + P0)/3
1023 // B2 = (2*P1 + P2)/3
1026 WXMICROWIN_CHECK_HDC
1028 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1030 const size_t n_points
= points
->GetCount();
1031 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1033 const size_t n_bezier_points
= n_points
* 3 + 1;
1034 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1035 size_t bezier_pos
= 0;
1036 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1038 wxList::compatibility_iterator node
= points
->GetFirst();
1039 wxPoint
*p
= (wxPoint
*)node
->GetData();
1040 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1041 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1043 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1046 node
= node
->GetNext();
1047 p
= (wxPoint
*)node
->GetData();
1051 cx1
= ( x1
+ x2
) / 2;
1052 cy1
= ( y1
+ y2
) / 2;
1053 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1054 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1056 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1060 while ((node
= node
->GetNext()) != NULL
)
1062 while ((node
= node
->GetNext()))
1063 #endif // !wxUSE_STL
1065 p
= (wxPoint
*)node
->GetData();
1070 cx4
= (x1
+ x2
) / 2;
1071 cy4
= (y1
+ y2
) / 2;
1072 // B0 is B3 of previous segment
1074 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1075 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1078 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1079 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1082 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1083 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1089 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1091 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1092 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1094 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1097 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1104 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1105 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1108 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1111 WXMICROWIN_CHECK_HDC
1113 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1118 int rx1
= XLOG2DEV(x
+w
/2);
1119 int ry1
= YLOG2DEV(y
+h
/2);
1126 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1127 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1128 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1129 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1131 // draw pie with NULL_PEN first and then outline otherwise a line is
1132 // drawn from the start and end points to the centre
1133 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1136 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1137 rx1
, ry1
, rx2
, ry2
);
1141 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1142 rx1
, ry1
-1, rx2
, ry2
-1);
1145 ::SelectObject(GetHdc(), hpenOld
);
1147 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1148 rx1
, ry1
, rx2
, ry2
);
1150 CalcBoundingBox(x
, y
);
1151 CalcBoundingBox(x2
, y2
);
1155 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1157 WXMICROWIN_CHECK_HDC
1159 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1162 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1164 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1167 CalcBoundingBox(x
, y
);
1168 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1171 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1173 WXMICROWIN_CHECK_HDC
1175 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1177 int width
= bmp
.GetWidth(),
1178 height
= bmp
.GetHeight();
1180 HBITMAP hbmpMask
= 0;
1183 HPALETTE oldPal
= 0;
1184 #endif // wxUSE_PALETTE
1186 if ( bmp
.HasAlpha() )
1189 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1191 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1197 wxMask
*mask
= bmp
.GetMask();
1199 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1203 // don't give assert here because this would break existing
1204 // programs - just silently ignore useMask parameter
1211 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1213 // On some systems, MaskBlt succeeds yet is much much slower
1214 // than the wxWidgets fall-back implementation. So we need
1215 // to be able to switch this on and off at runtime.
1217 #if wxUSE_SYSTEM_OPTIONS
1218 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1222 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1223 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1225 wxPalette
*pal
= bmp
.GetPalette();
1226 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1228 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1229 ::RealizePalette(hdcMem
);
1231 #endif // wxUSE_PALETTE
1233 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1236 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1240 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1241 #endif // wxUSE_PALETTE
1243 ::SelectObject(hdcMem
, hOldBitmap
);
1250 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1254 memDC
.SelectObjectAsSource(bmp
);
1256 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1258 memDC
.SelectObject(wxNullBitmap
);
1261 else // no mask, just use BitBlt()
1264 HDC memdc
= ::CreateCompatibleDC( cdc
);
1265 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1267 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1269 COLORREF old_textground
= ::GetTextColor(GetHdc());
1270 COLORREF old_background
= ::GetBkColor(GetHdc());
1271 if (m_textForegroundColour
.Ok())
1273 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1275 if (m_textBackgroundColour
.Ok())
1277 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1281 wxPalette
*pal
= bmp
.GetPalette();
1282 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1284 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1285 ::RealizePalette(memdc
);
1287 #endif // wxUSE_PALETTE
1289 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1290 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1294 ::SelectPalette(memdc
, oldPal
, FALSE
);
1295 #endif // wxUSE_PALETTE
1297 ::SelectObject( memdc
, hOldBitmap
);
1298 ::DeleteDC( memdc
);
1300 ::SetTextColor(GetHdc(), old_textground
);
1301 ::SetBkColor(GetHdc(), old_background
);
1305 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1307 WXMICROWIN_CHECK_HDC
1309 DrawAnyText(text
, x
, y
);
1311 // update the bounding box
1312 CalcBoundingBox(x
, y
);
1315 GetTextExtent(text
, &w
, &h
);
1316 CalcBoundingBox(x
+ w
, y
+ h
);
1319 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1321 WXMICROWIN_CHECK_HDC
1323 // prepare for drawing the text
1324 if ( m_textForegroundColour
.Ok() )
1325 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1327 DWORD old_background
= 0;
1328 if ( m_textBackgroundColour
.Ok() )
1330 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1333 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1337 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1338 text
.c_str(), text
.length(), NULL
) == 0 )
1340 wxLogLastError(wxT("TextOut"));
1343 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1344 text
.c_str(), text
.length()) == 0 )
1346 wxLogLastError(wxT("TextOut"));
1350 // restore the old parameters (text foreground colour may be left because
1351 // it never is set to anything else, but background should remain
1352 // transparent even if we just drew an opaque string)
1353 if ( m_textBackgroundColour
.Ok() )
1354 (void)SetBkColor(GetHdc(), old_background
);
1356 SetBkMode(GetHdc(), TRANSPARENT
);
1359 void wxDC::DoDrawRotatedText(const wxString
& text
,
1360 wxCoord x
, wxCoord y
,
1363 WXMICROWIN_CHECK_HDC
1365 // we test that we have some font because otherwise we should still use the
1366 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1367 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1368 // font for drawing rotated fonts unfortunately)
1369 if ( (angle
== 0.0) && m_font
.Ok() )
1371 DoDrawText(text
, x
, y
);
1373 #ifndef __WXMICROWIN__
1376 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1377 // because it's not TrueType and so can't have non zero
1378 // orientation/escapement under Win9x
1379 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1380 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1382 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1384 wxLogLastError(wxT("GetObject(hfont)"));
1387 // GDI wants the angle in tenth of degree
1388 long angle10
= (long)(angle
* 10);
1389 lf
.lfEscapement
= angle10
;
1390 lf
. lfOrientation
= angle10
;
1392 hfont
= ::CreateFontIndirect(&lf
);
1395 wxLogLastError(wxT("CreateFont"));
1399 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1401 DrawAnyText(text
, x
, y
);
1403 (void)::SelectObject(GetHdc(), hfontOld
);
1404 (void)::DeleteObject(hfont
);
1407 // call the bounding box by adding all four vertices of the rectangle
1408 // containing the text to it (simpler and probably not slower than
1409 // determining which of them is really topmost/leftmost/...)
1411 GetTextExtent(text
, &w
, &h
);
1413 double rad
= DegToRad(angle
);
1415 // "upper left" and "upper right"
1416 CalcBoundingBox(x
, y
);
1417 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1419 // "bottom left" and "bottom right"
1420 x
+= (wxCoord
)(h
*sin(rad
));
1421 y
+= (wxCoord
)(h
*cos(rad
));
1422 CalcBoundingBox(x
, y
);
1423 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1428 // ---------------------------------------------------------------------------
1430 // ---------------------------------------------------------------------------
1434 void wxDC::DoSelectPalette(bool realize
)
1436 WXMICROWIN_CHECK_HDC
1438 // Set the old object temporarily, in case the assignment deletes an object
1439 // that's not yet selected out.
1442 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1446 if ( m_palette
.Ok() )
1448 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1449 GetHpaletteOf(m_palette
),
1452 m_oldPalette
= (WXHPALETTE
) oldPal
;
1455 ::RealizePalette(GetHdc());
1459 void wxDC::SetPalette(const wxPalette
& palette
)
1463 m_palette
= palette
;
1464 DoSelectPalette(true);
1468 void wxDC::InitializePalette()
1470 if ( wxDisplayDepth() <= 8 )
1472 // look for any window or parent that has a custom palette. If any has
1473 // one then we need to use it in drawing operations
1474 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1476 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1477 if ( m_hasCustomPalette
)
1479 m_palette
= win
->GetPalette();
1481 // turn on MSW translation for this palette
1487 #endif // wxUSE_PALETTE
1489 // SetFont/Pen/Brush() really ask to be implemented as a single template
1490 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1492 void wxDC::SetFont(const wxFont
& font
)
1494 WXMICROWIN_CHECK_HDC
1496 if ( font
== m_font
)
1501 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1502 if ( hfont
== HGDI_ERROR
)
1504 wxLogLastError(_T("SelectObject(font)"));
1509 m_oldFont
= (WXHFONT
)hfont
;
1514 else // invalid font, reset the current font
1518 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1520 wxLogLastError(_T("SelectObject(old font)"));
1526 m_font
= wxNullFont
;
1530 void wxDC::SetPen(const wxPen
& pen
)
1532 WXMICROWIN_CHECK_HDC
1539 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1540 if ( hpen
== HGDI_ERROR
)
1542 wxLogLastError(_T("SelectObject(pen)"));
1547 m_oldPen
= (WXHPEN
)hpen
;
1552 else // invalid pen, reset the current pen
1556 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1558 wxLogLastError(_T("SelectObject(old pen)"));
1568 void wxDC::SetBrush(const wxBrush
& brush
)
1570 WXMICROWIN_CHECK_HDC
1572 if ( brush
== m_brush
)
1577 // we must make sure the brush is aligned with the logical coordinates
1578 // before selecting it
1579 wxBitmap
*stipple
= brush
.GetStipple();
1580 if ( stipple
&& stipple
->Ok() )
1582 if ( !::SetBrushOrgEx
1585 m_deviceOriginX
% stipple
->GetWidth(),
1586 m_deviceOriginY
% stipple
->GetHeight(),
1587 NULL
// [out] previous brush origin
1590 wxLogLastError(_T("SetBrushOrgEx()"));
1594 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1595 if ( hbrush
== HGDI_ERROR
)
1597 wxLogLastError(_T("SelectObject(brush)"));
1602 m_oldBrush
= (WXHBRUSH
)hbrush
;
1607 else // invalid brush, reset the current brush
1611 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1613 wxLogLastError(_T("SelectObject(old brush)"));
1619 m_brush
= wxNullBrush
;
1623 void wxDC::SetBackground(const wxBrush
& brush
)
1625 WXMICROWIN_CHECK_HDC
1627 m_backgroundBrush
= brush
;
1629 if ( m_backgroundBrush
.Ok() )
1631 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1635 void wxDC::SetBackgroundMode(int mode
)
1637 WXMICROWIN_CHECK_HDC
1639 m_backgroundMode
= mode
;
1641 // SetBackgroundColour now only refers to text background
1642 // and m_backgroundMode is used there
1645 void wxDC::SetLogicalFunction(int function
)
1647 WXMICROWIN_CHECK_HDC
1649 m_logicalFunction
= function
;
1654 void wxDC::SetRop(WXHDC dc
)
1656 if ( !dc
|| m_logicalFunction
< 0 )
1661 switch (m_logicalFunction
)
1663 case wxCLEAR
: rop
= R2_BLACK
; break;
1664 case wxXOR
: rop
= R2_XORPEN
; break;
1665 case wxINVERT
: rop
= R2_NOT
; break;
1666 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1667 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1668 case wxCOPY
: rop
= R2_COPYPEN
; break;
1669 case wxAND
: rop
= R2_MASKPEN
; break;
1670 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1671 case wxNO_OP
: rop
= R2_NOP
; break;
1672 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1673 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1674 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1675 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1676 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1677 case wxOR
: rop
= R2_MERGEPEN
; break;
1678 case wxSET
: rop
= R2_WHITE
; break;
1681 wxFAIL_MSG( wxT("unsupported logical function") );
1685 SetROP2(GetHdc(), rop
);
1688 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1690 // We might be previewing, so return true to let it continue.
1698 void wxDC::StartPage()
1702 void wxDC::EndPage()
1706 // ---------------------------------------------------------------------------
1708 // ---------------------------------------------------------------------------
1710 wxCoord
wxDC::GetCharHeight() const
1712 WXMICROWIN_CHECK_HDC_RET(0)
1714 TEXTMETRIC lpTextMetric
;
1716 GetTextMetrics(GetHdc(), &lpTextMetric
);
1718 return lpTextMetric
.tmHeight
;
1721 wxCoord
wxDC::GetCharWidth() const
1723 WXMICROWIN_CHECK_HDC_RET(0)
1725 TEXTMETRIC lpTextMetric
;
1727 GetTextMetrics(GetHdc(), &lpTextMetric
);
1729 return lpTextMetric
.tmAveCharWidth
;
1732 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1733 wxCoord
*descent
, wxCoord
*externalLeading
,
1736 #ifdef __WXMICROWIN__
1741 if (descent
) *descent
= 0;
1742 if (externalLeading
) *externalLeading
= 0;
1745 #endif // __WXMICROWIN__
1750 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1752 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1754 else // don't change the font
1760 const size_t len
= string
.length();
1761 if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) )
1763 wxLogLastError(_T("GetTextExtentPoint32()"));
1766 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1767 // the result computed by GetTextExtentPoint32() may be too small as it
1768 // accounts for under/overhang of the first/last character while we want
1769 // just the bounding rect for this string so adjust the width as needed
1770 // (using API not available in 2002 SDKs of WinCE)
1774 const wxChar chFirst
= *string
.begin();
1775 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1777 if ( width
.abcA
< 0 )
1778 sizeRect
.cx
-= width
.abcA
;
1782 const wxChar chLast
= *string
.rbegin();
1783 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1785 //else: we already have the width of the last character
1787 if ( width
.abcC
< 0 )
1788 sizeRect
.cx
-= width
.abcC
;
1790 //else: GetCharABCWidths() failed, not a TrueType font?
1792 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1795 ::GetTextMetrics(GetHdc(), &tm
);
1802 *descent
= tm
.tmDescent
;
1803 if (externalLeading
)
1804 *externalLeading
= tm
.tmExternalLeading
;
1808 ::SelectObject(GetHdc(), hfontOld
);
1813 // Each element of the array will be the width of the string up to and
1814 // including the coresoponding character in text.
1816 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1818 static int maxLenText
= -1;
1819 static int maxWidth
= -1;
1822 int stlen
= text
.length();
1824 if (maxLenText
== -1)
1826 // Win9x and WinNT+ have different limits
1827 int version
= wxGetOsVersion();
1828 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1829 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1833 widths
.Add(0, stlen
); // fill the array with zeros
1837 if (!::GetTextExtentExPoint(GetHdc(),
1838 text
.c_str(), // string to check
1839 wxMin(stlen
, maxLenText
),
1841 &fit
, // [out] count of chars
1843 &widths
[0], // array to fill
1847 wxLogLastError(wxT("GetTextExtentExPoint"));
1857 void wxDC::SetMapMode(int mode
)
1859 WXMICROWIN_CHECK_HDC
1861 m_mappingMode
= mode
;
1863 if ( mode
== wxMM_TEXT
)
1866 m_logicalScaleY
= 1.0;
1868 else // need to do some calculations
1870 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1871 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1872 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1873 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1875 if ( (mm_width
== 0) || (mm_height
== 0) )
1877 // we can't calculate mm2pixels[XY] then!
1881 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1882 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1887 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1888 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1892 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1893 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1897 m_logicalScaleX
= mm2pixelsX
;
1898 m_logicalScaleY
= mm2pixelsY
;
1902 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1903 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1907 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1911 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1912 // cases we could do with MM_TEXT and in the remaining 0.9% with
1913 // MM_ISOTROPIC (TODO!)
1915 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1917 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1918 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1920 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1921 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1923 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1924 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1928 void wxDC::SetUserScale(double x
, double y
)
1930 WXMICROWIN_CHECK_HDC
1932 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1938 this->SetMapMode(m_mappingMode
);
1941 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1942 bool WXUNUSED_IN_WINCE(yBottomUp
))
1944 WXMICROWIN_CHECK_HDC
1947 int signX
= xLeftRight
? 1 : -1,
1948 signY
= yBottomUp
? -1 : 1;
1950 if ( signX
!= m_signX
|| signY
!= m_signY
)
1955 SetMapMode(m_mappingMode
);
1960 void wxDC::SetSystemScale(double x
, double y
)
1962 WXMICROWIN_CHECK_HDC
1964 if ( x
== m_scaleX
&& y
== m_scaleY
)
1971 SetMapMode(m_mappingMode
);
1975 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1977 WXMICROWIN_CHECK_HDC
1979 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1982 m_logicalOriginX
= x
;
1983 m_logicalOriginY
= y
;
1986 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1990 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1992 WXMICROWIN_CHECK_HDC
1994 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1997 m_deviceOriginX
= x
;
1998 m_deviceOriginY
= y
;
2000 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
2003 // ---------------------------------------------------------------------------
2004 // coordinates transformations
2005 // ---------------------------------------------------------------------------
2007 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
2009 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
2012 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
2014 // axis orientation is not taken into account for conversion of a distance
2015 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
2018 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
2020 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
2023 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
2025 // axis orientation is not taken into account for conversion of a distance
2026 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
2029 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
2031 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
2034 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
2036 // axis orientation is not taken into account for conversion of a distance
2037 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
2040 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
2042 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
2045 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
2047 // axis orientation is not taken into account for conversion of a distance
2048 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
2051 // ---------------------------------------------------------------------------
2053 // ---------------------------------------------------------------------------
2054 bool wxDC::DoBlit(wxCoord dstX
, wxCoord dstY
,
2055 wxCoord dstWidth
, wxCoord dstHeight
,
2057 wxCoord srcX
, wxCoord srcY
,
2058 int rop
, bool useMask
,
2059 wxCoord srcMaskX
, wxCoord srcMaskY
)
2061 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
2064 bool wxDC::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
2065 wxCoord dstWidth
, wxCoord dstHeight
,
2067 wxCoord xsrc
, wxCoord ysrc
,
2068 wxCoord srcWidth
, wxCoord srcHeight
,
2069 int rop
, bool useMask
,
2070 wxCoord xsrcMask
, wxCoord ysrcMask
)
2072 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2074 WXMICROWIN_CHECK_HDC_RET(false)
2076 // if either the source or destination has alpha channel, we must use
2077 // AlphaBlt() as other function don't handle it correctly
2078 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2079 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2080 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2082 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2083 xsrc
, ysrc
, srcWidth
, srcHeight
, GetHdcOf(*source
), bmpSrc
) )
2087 wxMask
*mask
= NULL
;
2090 mask
= bmpSrc
.GetMask();
2092 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2094 // don't give assert here because this would break existing
2095 // programs - just silently ignore useMask parameter
2100 if (xsrcMask
== -1 && ysrcMask
== -1)
2102 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2105 COLORREF old_textground
= ::GetTextColor(GetHdc());
2106 COLORREF old_background
= ::GetBkColor(GetHdc());
2107 if (m_textForegroundColour
.Ok())
2109 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2111 if (m_textBackgroundColour
.Ok())
2113 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2119 case wxXOR
: dwRop
= SRCINVERT
; break;
2120 case wxINVERT
: dwRop
= DSTINVERT
; break;
2121 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2122 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2123 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2124 case wxSET
: dwRop
= WHITENESS
; break;
2125 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2126 case wxAND
: dwRop
= SRCAND
; break;
2127 case wxOR
: dwRop
= SRCPAINT
; break;
2128 case wxEQUIV
: dwRop
= 0x00990066; break;
2129 case wxNAND
: dwRop
= 0x007700E6; break;
2130 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2131 case wxCOPY
: dwRop
= SRCCOPY
; break;
2132 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2133 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2134 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2136 wxFAIL_MSG( wxT("unsupported logical function") );
2140 bool success
= false;
2145 // we want the part of the image corresponding to the mask to be
2146 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2147 // meaning of fg and bg is inverted which corresponds to wxWin notion
2148 // of the mask which is also contrary to the Windows one)
2150 // On some systems, MaskBlt succeeds yet is much much slower
2151 // than the wxWidgets fall-back implementation. So we need
2152 // to be able to switch this on and off at runtime.
2153 #if wxUSE_SYSTEM_OPTIONS
2154 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2157 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2162 xdest
, ydest
, dstWidth
, dstHeight
,
2165 (HBITMAP
)mask
->GetMaskBitmap(),
2167 MAKEROP4(dwRop
, DSTCOPY
)
2175 // Blit bitmap with mask
2178 HBITMAP buffer_bmap
;
2180 #if wxUSE_DC_CACHEING
2181 // create a temp buffer bitmap and DCs to access it and the mask
2182 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2183 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2185 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2186 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2188 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2189 dstWidth
, dstHeight
);
2191 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2192 #else // !wxUSE_DC_CACHEING
2193 // create a temp buffer bitmap and DCs to access it and the mask
2194 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2195 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2196 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2197 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2198 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2199 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2201 // copy dest to buffer
2202 if ( !::BitBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2203 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2205 wxLogLastError(wxT("BitBlt"));
2209 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2212 // copy src to buffer using selected raster op
2213 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2214 GetHdcOf(*source
), xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2216 wxLogLastError(wxT("StretchBlt"));
2219 // set masked area in buffer to BLACK (pixel value 0)
2220 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2221 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2222 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2223 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2225 wxLogLastError(wxT("StretchBlt"));
2228 // set unmasked area in dest to BLACK
2229 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2230 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2231 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, (int)dstWidth
, (int)dstHeight
,
2232 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2234 wxLogLastError(wxT("StretchBlt"));
2236 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2237 ::SetTextColor(GetHdc(), prevCol
);
2239 // OR buffer to dest
2240 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2241 (int)dstWidth
, (int)dstHeight
,
2242 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2245 wxLogLastError(wxT("BitBlt"));
2248 // tidy up temporary DCs and bitmap
2249 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2250 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2252 #if !wxUSE_DC_CACHEING
2254 ::DeleteDC(dc_mask
);
2255 ::DeleteDC(dc_buffer
);
2256 ::DeleteObject(buffer_bmap
);
2261 else // no mask, just BitBlt() it
2263 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2264 // use StretchBlt() if available and finally fall back to BitBlt()
2266 // FIXME: use appropriate WinCE functions
2268 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2269 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2274 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2276 &ds
) == sizeof(ds
) )
2278 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2280 // Figure out what co-ordinate system we're supposed to specify
2282 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2286 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2289 if ( ::StretchDIBits(GetHdc(),
2291 dstWidth
, dstHeight
,
2293 srcWidth
, srcHeight
,
2295 (LPBITMAPINFO
)&ds
.dsBmih
,
2298 ) == (int)GDI_ERROR
)
2300 // On Win9x this API fails most (all?) of the time, so
2301 // logging it becomes quite distracting. Since it falls
2302 // back to the code below this is not really serious, so
2304 //wxLogLastError(wxT("StretchDIBits"));
2313 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2318 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2324 xdest
, ydest
, dstWidth
, dstHeight
,
2326 xsrc
, ysrc
, srcWidth
, srcHeight
,
2330 wxLogLastError(_T("StretchBlt"));
2344 (int)dstWidth
, (int)dstHeight
,
2350 wxLogLastError(_T("BitBlt"));
2359 ::SetTextColor(GetHdc(), old_textground
);
2360 ::SetBkColor(GetHdc(), old_background
);
2365 void wxDC::GetDeviceSize(int *width
, int *height
) const
2367 WXMICROWIN_CHECK_HDC
2370 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2372 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2375 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2377 WXMICROWIN_CHECK_HDC
2379 // if we implement it in terms of DoGetSize() instead of directly using the
2380 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2381 // will also work for wxWindowDC and wxClientDC even though their size is
2382 // not the same as the total size of the screen
2383 int wPixels
, hPixels
;
2384 DoGetSize(&wPixels
, &hPixels
);
2388 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2390 wxCHECK_RET( wTotal
, _T("0 width device?") );
2392 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2397 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2399 wxCHECK_RET( hTotal
, _T("0 height device?") );
2401 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2405 wxSize
wxDC::GetPPI() const
2407 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2409 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2410 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2412 return wxSize(x
, y
);
2415 // For use by wxWidgets only, unless custom units are required.
2416 void wxDC::SetLogicalScale(double x
, double y
)
2418 WXMICROWIN_CHECK_HDC
2420 m_logicalScaleX
= x
;
2421 m_logicalScaleY
= y
;
2424 // ----------------------------------------------------------------------------
2426 // ----------------------------------------------------------------------------
2428 #if wxUSE_DC_CACHEING
2431 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2432 * improve it in due course, either using arrays, or simply storing pointers to one
2433 * entry for the bitmap, and two for the DCs. -- JACS
2436 wxList
wxDC::sm_bitmapCache
;
2437 wxList
wxDC::sm_dcCache
;
2439 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2448 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2457 wxDCCacheEntry::~wxDCCacheEntry()
2460 ::DeleteObject((HBITMAP
) m_bitmap
);
2462 ::DeleteDC((HDC
) m_dc
);
2465 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2467 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2468 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2471 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2473 if (entry
->m_depth
== depth
)
2475 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2477 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2478 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2479 if ( !entry
->m_bitmap
)
2481 wxLogLastError(wxT("CreateCompatibleBitmap"));
2483 entry
->m_width
= w
; entry
->m_height
= h
;
2489 node
= node
->GetNext();
2491 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2494 wxLogLastError(wxT("CreateCompatibleBitmap"));
2496 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2497 AddToBitmapCache(entry
);
2501 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2503 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2504 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2507 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2509 // Don't return the same one as we already have
2510 if (!notThis
|| (notThis
!= entry
))
2512 if (entry
->m_depth
== depth
)
2518 node
= node
->GetNext();
2520 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2523 wxLogLastError(wxT("CreateCompatibleDC"));
2525 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2526 AddToDCCache(entry
);
2530 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2532 sm_bitmapCache
.Append(entry
);
2535 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2537 sm_dcCache
.Append(entry
);
2540 void wxDC::ClearCache()
2542 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2543 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2546 // Clean up cache at app exit
2547 class wxDCModule
: public wxModule
2550 virtual bool OnInit() { return true; }
2551 virtual void OnExit() { wxDC::ClearCache(); }
2554 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2557 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2559 #endif // wxUSE_DC_CACHEING
2561 // ----------------------------------------------------------------------------
2562 // alpha channel support
2563 // ----------------------------------------------------------------------------
2565 static bool AlphaBlt(HDC hdcDst
,
2566 int x
, int y
, int dstWidth
, int dstHeight
,
2568 int srcWidth
, int srcHeight
,
2570 const wxBitmap
& bmp
)
2572 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2573 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2575 // do we have AlphaBlend() and company in the headers?
2576 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2577 // yes, now try to see if we have it during run-time
2578 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2579 HDC
,int,int,int,int,
2583 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2584 if ( pfnAlphaBlend
)
2587 bf
.BlendOp
= AC_SRC_OVER
;
2589 bf
.SourceConstantAlpha
= 0xff;
2590 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2592 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2593 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2596 // skip wxAlphaBlend() call below
2600 wxLogLastError(_T("AlphaBlend"));
2603 wxUnusedVar(hdcSrc
);
2604 #endif // defined(AC_SRC_OVER)
2606 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2608 #ifdef wxHAVE_RAW_BITMAP
2609 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2612 #else // !wxHAVE_RAW_BITMAP
2613 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2614 // alpha but at least something will be shown like this)
2617 #endif // wxHAVE_RAW_BITMAP
2621 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2622 #ifdef wxHAVE_RAW_BITMAP
2625 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2626 int dstWidth
, int dstHeight
,
2628 int srcWidth
, int srcHeight
,
2629 const wxBitmap
& bmpSrc
)
2631 // get the destination DC pixels
2632 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2634 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2636 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2638 wxLogLastError(_T("BitBlt"));
2641 // combine them with the source bitmap using alpha
2642 wxAlphaPixelData
dataDst(bmpDst
),
2643 dataSrc((wxBitmap
&)bmpSrc
);
2645 wxCHECK_RET( dataDst
&& dataSrc
,
2646 _T("failed to get raw data in wxAlphaBlend") );
2648 wxAlphaPixelData::Iterator
pDst(dataDst
),
2652 for ( int y
= 0; y
< dstHeight
; y
++ )
2654 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2656 for ( int x
= 0; x
< dstWidth
; x
++ )
2658 // source is point sampled, Alpha StretchBlit is ugly on Win95
2659 // (but does not impact performance)
2660 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2662 // note that source bitmap uses premultiplied alpha (as required by
2663 // the real AlphaBlend)
2664 const unsigned beta
= 255 - pSrc
.Alpha();
2666 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2667 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2668 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2673 pDst
= pDstRowStart
;
2674 pDst
.OffsetY(dataDst
, 1);
2677 // and finally blit them back to the destination DC
2678 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2680 wxLogLastError(_T("BitBlt"));
2684 #endif // #ifdef wxHAVE_RAW_BITMAP
2686 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2687 const wxColour
& initialColour
,
2688 const wxColour
& destColour
,
2689 wxDirection nDirection
)
2691 // use native function if we have compile-time support it and can load it
2692 // during run-time (linking to it statically would make the program
2693 // unusable on earlier Windows versions)
2694 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2696 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2697 static GradientFill_t pfnGradientFill
=
2698 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2700 if ( pfnGradientFill
)
2702 GRADIENT_RECT grect
;
2703 grect
.UpperLeft
= 0;
2704 grect
.LowerRight
= 1;
2706 // invert colours direction if not filling from left-to-right or
2708 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2710 // one vertex for upper left and one for upper-right
2711 TRIVERTEX vertices
[2];
2713 vertices
[0].x
= rect
.GetLeft();
2714 vertices
[0].y
= rect
.GetTop();
2715 vertices
[1].x
= rect
.GetRight()+1;
2716 vertices
[1].y
= rect
.GetBottom()+1;
2718 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2719 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2720 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2721 vertices
[firstVertex
].Alpha
= 0;
2722 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2723 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2724 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2725 vertices
[1 - firstVertex
].Alpha
= 0;
2727 if ( (*pfnGradientFill
)
2734 nDirection
== wxWEST
|| nDirection
== wxEAST
2735 ? GRADIENT_FILL_RECT_H
2736 : GRADIENT_FILL_RECT_V
2739 // skip call of the base class version below
2743 wxLogLastError(_T("GradientFill"));
2745 #endif // wxUSE_DYNLIB_CLASS
2747 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2750 static DWORD
wxGetDCLayout(HDC hdc
)
2752 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2754 pfnGetLayout
= (GetLayout_t
)wxGDI32DLL
.GetSymbol(_T("GetLayout"));
2756 return pfnGetLayout
? pfnGetLayout(hdc
) : (DWORD
)-1;
2759 wxLayoutDirection
wxDC::GetLayoutDirection() const
2761 DWORD layout
= wxGetDCLayout(GetHdc());
2763 if ( layout
== (DWORD
)-1 )
2764 return wxLayout_Default
;
2766 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2769 void wxDC::SetLayoutDirection(wxLayoutDirection dir
)
2771 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2773 pfnSetLayout
= (SetLayout_t
)wxGDI32DLL
.GetSymbol(_T("SetLayout"));
2774 if ( !pfnSetLayout
)
2777 if ( dir
== wxLayout_Default
)
2779 dir
= wxTheApp
->GetLayoutDirection();
2780 if ( dir
== wxLayout_Default
)
2784 DWORD layout
= wxGetDCLayout(GetHdc());
2785 if ( dir
== wxLayout_RightToLeft
)
2786 layout
|= LAYOUT_RTL
;
2788 layout
&= ~LAYOUT_RTL
;
2790 pfnSetLayout(GetHdc(), layout
);