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"
29 #include "wx/window.h"
32 #include "wx/dialog.h"
34 #include "wx/bitmap.h"
35 #include "wx/dcmemory.h"
40 #include "wx/sysopt.h"
41 #include "wx/dcprint.h"
42 #include "wx/module.h"
43 #include "wx/dynlib.h"
45 #ifdef wxHAVE_RAW_BITMAP
46 #include "wx/rawbmp.h"
51 #include "wx/msw/wrapcdlg.h"
57 #define AC_SRC_ALPHA 1
60 /* Quaternary raster codes */
62 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
65 // apparently with MicroWindows it is possible that HDC is 0 so we have to
66 // check for this ourselves
68 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
69 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
71 #define WXMICROWIN_CHECK_HDC
72 #define WXMICROWIN_CHECK_HDC_RET(x)
75 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
77 // ---------------------------------------------------------------------------
79 // ---------------------------------------------------------------------------
81 static const int VIEWPORT_EXTENT
= 1000;
83 static const int MM_POINTS
= 9;
84 static const int MM_METRIC
= 10;
86 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
87 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
88 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
90 // ----------------------------------------------------------------------------
91 // macros for logical <-> device coords conversion
92 // ----------------------------------------------------------------------------
95 We currently let Windows do all the translations itself so these macros are
96 not really needed (any more) but keep them to enhance readability of the
97 code by allowing to see where are the logical and where are the device
102 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
103 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
104 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
105 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
107 #define XLOG2DEV(x) (x)
108 #define YLOG2DEV(y) (y)
109 #define XDEV2LOG(x) (x)
110 #define YDEV2LOG(y) (y)
113 // ---------------------------------------------------------------------------
115 // ---------------------------------------------------------------------------
117 // convert degrees to radians
118 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
120 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
122 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
123 // to pass it to this function but as we already have it at the point
124 // of call anyhow we do
126 // return true if we could draw the bitmap in one way or the other, false
128 static bool AlphaBlt(HDC hdcDst
,
129 int x
, int y
, int w
, int h
,
130 int srcX
, int srcY
, HDC hdcSrc
,
131 const wxBitmap
& bmpSrc
);
133 #ifdef wxHAVE_RAW_BITMAP
135 // our (limited) AlphaBlend() replacement for Windows versions not providing it
137 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
,
138 int srcX
, int srcY
, const wxBitmap
& bmp
);
140 #endif // wxHAVE_RAW_BITMAP
142 // ----------------------------------------------------------------------------
144 // ----------------------------------------------------------------------------
146 // instead of duplicating the same code which sets and then restores text
147 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
148 // encapsulate this in a small helper class
150 // wxColourChanger: changes the text colours in the ctor if required and
151 // restores them in the dtor
152 class wxColourChanger
155 wxColourChanger(wxDC
& dc
);
161 COLORREF m_colFgOld
, m_colBgOld
;
165 DECLARE_NO_COPY_CLASS(wxColourChanger
)
168 // this class saves the old stretch blit mode during its life time
169 class StretchBltModeChanger
172 StretchBltModeChanger(HDC hdc
,
173 int WXUNUSED_IN_WINCE(mode
))
177 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
179 wxLogLastError(_T("SetStretchBltMode"));
183 ~StretchBltModeChanger()
186 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
187 wxLogLastError(_T("SetStretchBltMode"));
196 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
199 // support for dynamic loading of msimg32.dll which we use for some functions
203 // return the symbol with the given name if the DLL not loaded or symbol
205 static void *GetSymbol(const wxChar
*name
)
209 if ( !ms_triedToLoad
)
211 ms_triedToLoad
= true;
212 ms_dll
.Load(_T("msimg32"));
215 return ms_dll
.IsLoaded() ? ms_dll
.GetSymbol(name
) : NULL
;
219 static wxDynamicLibrary ms_dll
;
220 static bool ms_triedToLoad
;
223 wxDynamicLibrary
wxMSImg32DLL::ms_dll
;
224 bool wxMSImg32DLL::ms_triedToLoad
= false;
226 // helper macro for getting the symbols from msimg32.dll: it supposes that a
227 // type "name_t" is defined and casts the returned symbol to it automatically
228 #define wxMSIMG32_SYMBOL(name) (name ## _t)wxMSImg32DLL::GetSymbol(_T(#name))
230 // ===========================================================================
232 // ===========================================================================
234 // ----------------------------------------------------------------------------
236 // ----------------------------------------------------------------------------
238 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
240 const wxBrush
& brush
= dc
.GetBrush();
241 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
243 HDC hdc
= GetHdcOf(dc
);
244 m_colFgOld
= ::GetTextColor(hdc
);
245 m_colBgOld
= ::GetBkColor(hdc
);
247 // note that Windows convention is opposite to wxWidgets one, this is
248 // why text colour becomes the background one and vice versa
249 const wxColour
& colFg
= dc
.GetTextForeground();
252 ::SetBkColor(hdc
, colFg
.GetPixel());
255 const wxColour
& colBg
= dc
.GetTextBackground();
258 ::SetTextColor(hdc
, colBg
.GetPixel());
262 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
265 // flag which telsl us to undo changes in the dtor
270 // nothing done, nothing to undo
275 wxColourChanger::~wxColourChanger()
279 // restore the colours we changed
280 HDC hdc
= GetHdcOf(m_dc
);
282 ::SetBkMode(hdc
, TRANSPARENT
);
283 ::SetTextColor(hdc
, m_colFgOld
);
284 ::SetBkColor(hdc
, m_colBgOld
);
288 // ---------------------------------------------------------------------------
290 // ---------------------------------------------------------------------------
296 SelectOldObjects(m_hDC
);
298 // if we own the HDC, we delete it, otherwise we just release it
302 ::DeleteDC(GetHdc());
304 else // we don't own our HDC
308 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
312 // Must have been a wxScreenDC
313 ::ReleaseDC((HWND
) NULL
, GetHdc());
319 // This will select current objects out of the DC,
320 // which is what you have to do before deleting the
322 void wxDC::SelectOldObjects(WXHDC dc
)
328 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
330 if (m_selectedBitmap
.Ok())
332 m_selectedBitmap
.SetSelectedInto(NULL
);
339 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
344 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
349 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
356 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
359 #endif // wxUSE_PALETTE
362 m_brush
= wxNullBrush
;
365 m_palette
= wxNullPalette
;
366 #endif // wxUSE_PALETTE
368 m_backgroundBrush
= wxNullBrush
;
369 m_selectedBitmap
= wxNullBitmap
;
372 // ---------------------------------------------------------------------------
374 // ---------------------------------------------------------------------------
376 void wxDC::UpdateClipBox()
381 ::GetClipBox(GetHdc(), &rect
);
383 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
384 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
385 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
386 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
390 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
392 // check if we should try to retrieve the clipping region possibly not set
393 // by our SetClippingRegion() but preset by Windows:this can only happen
394 // when we're associated with an existing HDC usign SetHDC(), see there
395 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
397 wxDC
*self
= wxConstCast(this, wxDC
);
398 self
->UpdateClipBox();
400 if ( !m_clipX1
&& !m_clipX2
)
401 self
->m_clipping
= false;
404 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
407 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
408 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
410 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
414 // note that we combine the new clipping region with the existing one: this
415 // is compatible with what the other ports do and is the documented
416 // behaviour now (starting with 2.3.3)
417 #if defined(__WXWINCE__)
419 if ( !::GetClipBox(GetHdc(), &rectClip
) )
422 // GetClipBox returns logical coordinates, so transform to device
423 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
424 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
425 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
426 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
428 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
429 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
430 rectClip
.right
, rectClip
.bottom
);
432 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
434 ::SelectClipRgn(GetHdc(), hrgnDest
);
437 ::DeleteObject(hrgnClipOld
);
438 ::DeleteObject(hrgnDest
);
440 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
442 wxLogLastError(_T("ExtSelectClipRgn"));
446 #endif // WinCE/!WinCE
453 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
455 // the region coords are always the device ones, so do the translation
458 // FIXME: possible +/-1 error here, to check!
459 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
461 LogicalToDeviceX(x
+ w
),
462 LogicalToDeviceY(y
+ h
));
465 wxLogLastError(_T("CreateRectRgn"));
469 SetClippingHrgn((WXHRGN
)hrgn
);
471 ::DeleteObject(hrgn
);
475 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
477 SetClippingHrgn(region
.GetHRGN());
480 void wxDC::DestroyClippingRegion()
484 if (m_clipping
&& m_hDC
)
487 // On a PocketPC device (not necessarily emulator), resetting
488 // the clip region as per the old method causes bad display
489 // problems. In fact setting a null region is probably OK
490 // on desktop WIN32 also, since the WIN32 docs imply that the user
491 // clipping region is independent from the paint clipping region.
492 ::SelectClipRgn(GetHdc(), 0);
494 // TODO: this should restore the previous clipping region,
495 // so that OnPaint processing works correctly, and the update
496 // clipping region doesn't get destroyed after the first
497 // DestroyClippingRegion.
498 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
499 ::SelectClipRgn(GetHdc(), rgn
);
504 wxDCBase::DestroyClippingRegion();
507 // ---------------------------------------------------------------------------
508 // query capabilities
509 // ---------------------------------------------------------------------------
511 bool wxDC::CanDrawBitmap() const
516 bool wxDC::CanGetTextExtent() const
518 #ifdef __WXMICROWIN__
519 // TODO Extend MicroWindows' GetDeviceCaps function
522 // What sort of display is it?
523 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
525 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
529 int wxDC::GetDepth() const
531 WXMICROWIN_CHECK_HDC_RET(16)
533 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
536 // ---------------------------------------------------------------------------
538 // ---------------------------------------------------------------------------
547 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
551 // No, I think we should simply ignore this if printing on e.g.
553 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
554 if (!m_selectedBitmap
.Ok())
557 rect
.left
= 0; rect
.top
= 0;
558 rect
.right
= m_selectedBitmap
.GetWidth();
559 rect
.bottom
= m_selectedBitmap
.GetHeight();
563 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
566 DWORD colour
= ::GetBkColor(GetHdc());
567 HBRUSH brush
= ::CreateSolidBrush(colour
);
568 ::FillRect(GetHdc(), &rect
, brush
);
569 ::DeleteObject(brush
);
572 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
573 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
575 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
577 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
578 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
579 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
580 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
584 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
585 wxCoord
WXUNUSED_IN_WINCE(y
),
586 const wxColour
& WXUNUSED_IN_WINCE(col
),
587 int WXUNUSED_IN_WINCE(style
))
592 WXMICROWIN_CHECK_HDC_RET(false)
594 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
596 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
597 : FLOODFILLBORDER
) ) ;
600 // quoting from the MSDN docs:
602 // Following are some of the reasons this function might fail:
604 // * The filling could not be completed.
605 // * The specified point has the boundary color specified by the
606 // crColor parameter (if FLOODFILLBORDER was requested).
607 // * The specified point does not have the color specified by
608 // crColor (if FLOODFILLSURFACE was requested)
609 // * The point is outside the clipping region that is, it is not
610 // visible on the device.
612 wxLogLastError(wxT("ExtFloodFill"));
615 CalcBoundingBox(x
, y
);
621 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
623 WXMICROWIN_CHECK_HDC_RET(false)
625 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
627 // get the color of the pixel
628 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
630 wxRGBToColour(*col
, pixelcolor
);
635 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
639 wxCoord x1
= x
-VIEWPORT_EXTENT
;
640 wxCoord y1
= y
-VIEWPORT_EXTENT
;
641 wxCoord x2
= x
+VIEWPORT_EXTENT
;
642 wxCoord y2
= y
+VIEWPORT_EXTENT
;
644 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
645 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
647 CalcBoundingBox(x1
, y1
);
648 CalcBoundingBox(x2
, y2
);
651 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
655 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
657 CalcBoundingBox(x1
, y1
);
658 CalcBoundingBox(x2
, y2
);
661 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
662 // and ending at (x2, y2)
663 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
664 wxCoord x2
, wxCoord y2
,
665 wxCoord xc
, wxCoord yc
)
668 // Slower emulation since WinCE doesn't support Pie and Arc
669 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
670 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
671 if( y1
>yc
) sa
= -sa
; // below center
672 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
673 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
678 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
682 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
683 wxCoord r
= (wxCoord
)radius
;
685 // treat the special case of full circle separately
686 if ( x1
== x2
&& y1
== y2
)
688 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
692 wxCoord xx1
= XLOG2DEV(x1
);
693 wxCoord yy1
= YLOG2DEV(y1
);
694 wxCoord xx2
= XLOG2DEV(x2
);
695 wxCoord yy2
= YLOG2DEV(y2
);
696 wxCoord xxc
= XLOG2DEV(xc
);
697 wxCoord yyc
= YLOG2DEV(yc
);
698 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
700 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
701 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
702 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
703 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
705 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
707 // Have to add 1 to bottom-right corner of rectangle
708 // to make semi-circles look right (crooked line otherwise).
709 // Unfortunately this is not a reliable method, depends
710 // on the size of shape.
711 // TODO: figure out why this happens!
712 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
716 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
719 CalcBoundingBox(xc
- r
, yc
- r
);
720 CalcBoundingBox(xc
+ r
, yc
+ r
);
724 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
725 wxCoord width
, wxCoord height
)
727 // cases when we don't have DrawFrameControl()
728 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
729 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
731 wxCoord x2
= x1
+ width
,
741 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
743 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
746 CalcBoundingBox(x1
, y1
);
747 CalcBoundingBox(x2
, y2
);
748 #endif // Microwin/Normal
751 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
755 COLORREF color
= 0x00ffffff;
758 color
= m_pen
.GetColour().GetPixel();
761 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
763 CalcBoundingBox(x
, y
);
766 void wxDC::DoDrawPolygon(int n
,
770 int WXUNUSED_IN_WINCE(fillStyle
))
774 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
776 // Do things less efficiently if we have offsets
777 if (xoffset
!= 0 || yoffset
!= 0)
779 POINT
*cpoints
= new POINT
[n
];
781 for (i
= 0; i
< n
; i
++)
783 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
784 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
786 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
789 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
791 (void)Polygon(GetHdc(), cpoints
, n
);
793 SetPolyFillMode(GetHdc(),prev
);
800 for (i
= 0; i
< n
; i
++)
801 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
804 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
806 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
808 SetPolyFillMode(GetHdc(),prev
);
814 wxDC::DoDrawPolyPolygon(int n
,
822 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
826 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
828 for (i
= cnt
= 0; i
< n
; i
++)
831 // Do things less efficiently if we have offsets
832 if (xoffset
!= 0 || yoffset
!= 0)
834 POINT
*cpoints
= new POINT
[cnt
];
835 for (i
= 0; i
< cnt
; i
++)
837 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
838 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
840 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
843 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
845 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
847 SetPolyFillMode(GetHdc(),prev
);
853 for (i
= 0; i
< cnt
; i
++)
854 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
857 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
859 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
861 SetPolyFillMode(GetHdc(),prev
);
868 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
872 // Do things less efficiently if we have offsets
873 if (xoffset
!= 0 || yoffset
!= 0)
875 POINT
*cpoints
= new POINT
[n
];
877 for (i
= 0; i
< n
; i
++)
879 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
880 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
882 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
884 (void)Polyline(GetHdc(), cpoints
, n
);
890 for (i
= 0; i
< n
; i
++)
891 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
893 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
897 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
901 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
903 wxCoord x2
= x
+ width
;
904 wxCoord y2
= y
+ height
;
906 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
909 rect
.left
= XLOG2DEV(x
);
910 rect
.top
= YLOG2DEV(y
);
911 rect
.right
= XLOG2DEV(x2
);
912 rect
.bottom
= YLOG2DEV(y2
);
913 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
917 // Windows draws the filled rectangles without outline (i.e. drawn with a
918 // transparent pen) one pixel smaller in both directions and we want them
919 // to have the same size regardless of which pen is used - adjust
921 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
922 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
924 // Apparently not needed for WinCE (see e.g. Life! demo)
931 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
935 CalcBoundingBox(x
, y
);
936 CalcBoundingBox(x2
, y2
);
939 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
943 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
945 // Now, a negative radius value is interpreted to mean
946 // 'the proportion of the smallest X or Y dimension'
950 double smallest
= (width
< height
) ? width
: height
;
951 radius
= (- radius
* smallest
);
954 wxCoord x2
= (x
+width
);
955 wxCoord y2
= (y
+height
);
957 // Windows draws the filled rectangles without outline (i.e. drawn with a
958 // transparent pen) one pixel smaller in both directions and we want them
959 // to have the same size regardless of which pen is used - adjust
960 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
966 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
967 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
969 CalcBoundingBox(x
, y
);
970 CalcBoundingBox(x2
, y2
);
973 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
977 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
979 wxCoord x2
= (x
+width
);
980 wxCoord y2
= (y
+height
);
982 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
984 CalcBoundingBox(x
, y
);
985 CalcBoundingBox(x2
, y2
);
989 void wxDC::DoDrawSpline(wxList
*points
)
992 // WinCE does not support ::PolyBezier so use generic version
993 wxDCBase::DoDrawSpline(points
);
995 // quadratic b-spline to cubic bezier spline conversion
997 // quadratic spline with control points P0,P1,P2
998 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1000 // bezier spline with control points B0,B1,B2,B3
1001 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1003 // control points of bezier spline calculated from b-spline
1005 // B1 = (2*P1 + P0)/3
1006 // B2 = (2*P1 + P2)/3
1009 WXMICROWIN_CHECK_HDC
1011 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1013 const size_t n_points
= points
->GetCount();
1014 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1016 const size_t n_bezier_points
= n_points
* 3 + 1;
1017 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1018 size_t bezier_pos
= 0;
1019 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1021 wxList::compatibility_iterator node
= points
->GetFirst();
1022 wxPoint
*p
= (wxPoint
*)node
->GetData();
1023 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1024 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1026 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1029 node
= node
->GetNext();
1030 p
= (wxPoint
*)node
->GetData();
1034 cx1
= ( x1
+ x2
) / 2;
1035 cy1
= ( y1
+ y2
) / 2;
1036 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1037 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1039 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1043 while ((node
= node
->GetNext()) != NULL
)
1045 while ((node
= node
->GetNext()))
1046 #endif // !wxUSE_STL
1048 p
= (wxPoint
*)node
->GetData();
1053 cx4
= (x1
+ x2
) / 2;
1054 cy4
= (y1
+ y2
) / 2;
1055 // B0 is B3 of previous segment
1057 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1058 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1061 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1062 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1065 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1066 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1072 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1074 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1075 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1077 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1080 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1087 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1088 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1091 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1094 WXMICROWIN_CHECK_HDC
1096 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1101 int rx1
= XLOG2DEV(x
+w
/2);
1102 int ry1
= YLOG2DEV(y
+h
/2);
1109 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1110 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1111 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1112 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1114 // draw pie with NULL_PEN first and then outline otherwise a line is
1115 // drawn from the start and end points to the centre
1116 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1119 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1120 rx1
, ry1
, rx2
, ry2
);
1124 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1125 rx1
, ry1
-1, rx2
, ry2
-1);
1128 ::SelectObject(GetHdc(), hpenOld
);
1130 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1131 rx1
, ry1
, rx2
, ry2
);
1133 CalcBoundingBox(x
, y
);
1134 CalcBoundingBox(x2
, y2
);
1138 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1140 WXMICROWIN_CHECK_HDC
1142 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1145 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1147 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1150 CalcBoundingBox(x
, y
);
1151 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1154 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1156 WXMICROWIN_CHECK_HDC
1158 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1160 int width
= bmp
.GetWidth(),
1161 height
= bmp
.GetHeight();
1163 HBITMAP hbmpMask
= 0;
1166 HPALETTE oldPal
= 0;
1167 #endif // wxUSE_PALETTE
1169 if ( bmp
.HasAlpha() )
1172 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1174 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1180 wxMask
*mask
= bmp
.GetMask();
1182 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1186 // don't give assert here because this would break existing
1187 // programs - just silently ignore useMask parameter
1194 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1196 // On some systems, MaskBlt succeeds yet is much much slower
1197 // than the wxWidgets fall-back implementation. So we need
1198 // to be able to switch this on and off at runtime.
1200 #if wxUSE_SYSTEM_OPTIONS
1201 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1205 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1206 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1208 wxPalette
*pal
= bmp
.GetPalette();
1209 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1211 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1212 ::RealizePalette(hdcMem
);
1214 #endif // wxUSE_PALETTE
1216 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1219 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1223 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1224 #endif // wxUSE_PALETTE
1226 ::SelectObject(hdcMem
, hOldBitmap
);
1233 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1236 memDC
.SelectObject(bmp
);
1238 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1240 memDC
.SelectObject(wxNullBitmap
);
1243 else // no mask, just use BitBlt()
1246 HDC memdc
= ::CreateCompatibleDC( cdc
);
1247 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1249 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1251 COLORREF old_textground
= ::GetTextColor(GetHdc());
1252 COLORREF old_background
= ::GetBkColor(GetHdc());
1253 if (m_textForegroundColour
.Ok())
1255 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1257 if (m_textBackgroundColour
.Ok())
1259 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1263 wxPalette
*pal
= bmp
.GetPalette();
1264 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1266 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1267 ::RealizePalette(memdc
);
1269 #endif // wxUSE_PALETTE
1271 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1272 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1276 ::SelectPalette(memdc
, oldPal
, FALSE
);
1277 #endif // wxUSE_PALETTE
1279 ::SelectObject( memdc
, hOldBitmap
);
1280 ::DeleteDC( memdc
);
1282 ::SetTextColor(GetHdc(), old_textground
);
1283 ::SetBkColor(GetHdc(), old_background
);
1287 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1289 WXMICROWIN_CHECK_HDC
1291 DrawAnyText(text
, x
, y
);
1293 // update the bounding box
1294 CalcBoundingBox(x
, y
);
1297 GetTextExtent(text
, &w
, &h
);
1298 CalcBoundingBox(x
+ w
, y
+ h
);
1301 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1303 WXMICROWIN_CHECK_HDC
1305 // prepare for drawing the text
1306 if ( m_textForegroundColour
.Ok() )
1307 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1309 DWORD old_background
= 0;
1310 if ( m_textBackgroundColour
.Ok() )
1312 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1315 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1319 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1320 text
.c_str(), text
.length(), NULL
) == 0 )
1322 wxLogLastError(wxT("TextOut"));
1325 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1326 text
.c_str(), text
.length()) == 0 )
1328 wxLogLastError(wxT("TextOut"));
1332 // restore the old parameters (text foreground colour may be left because
1333 // it never is set to anything else, but background should remain
1334 // transparent even if we just drew an opaque string)
1335 if ( m_textBackgroundColour
.Ok() )
1336 (void)SetBkColor(GetHdc(), old_background
);
1338 SetBkMode(GetHdc(), TRANSPARENT
);
1341 void wxDC::DoDrawRotatedText(const wxString
& text
,
1342 wxCoord x
, wxCoord y
,
1345 WXMICROWIN_CHECK_HDC
1347 // we test that we have some font because otherwise we should still use the
1348 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1349 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1350 // font for drawing rotated fonts unfortunately)
1351 if ( (angle
== 0.0) && m_font
.Ok() )
1353 DoDrawText(text
, x
, y
);
1355 #ifndef __WXMICROWIN__
1358 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1359 // because it's not TrueType and so can't have non zero
1360 // orientation/escapement under Win9x
1361 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1362 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1364 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1366 wxLogLastError(wxT("GetObject(hfont)"));
1369 // GDI wants the angle in tenth of degree
1370 long angle10
= (long)(angle
* 10);
1371 lf
.lfEscapement
= angle10
;
1372 lf
. lfOrientation
= angle10
;
1374 hfont
= ::CreateFontIndirect(&lf
);
1377 wxLogLastError(wxT("CreateFont"));
1381 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1383 DrawAnyText(text
, x
, y
);
1385 (void)::SelectObject(GetHdc(), hfontOld
);
1386 (void)::DeleteObject(hfont
);
1389 // call the bounding box by adding all four vertices of the rectangle
1390 // containing the text to it (simpler and probably not slower than
1391 // determining which of them is really topmost/leftmost/...)
1393 GetTextExtent(text
, &w
, &h
);
1395 double rad
= DegToRad(angle
);
1397 // "upper left" and "upper right"
1398 CalcBoundingBox(x
, y
);
1399 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1401 // "bottom left" and "bottom right"
1402 x
+= (wxCoord
)(h
*sin(rad
));
1403 y
+= (wxCoord
)(h
*cos(rad
));
1404 CalcBoundingBox(x
, y
);
1405 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1410 // ---------------------------------------------------------------------------
1412 // ---------------------------------------------------------------------------
1416 void wxDC::DoSelectPalette(bool realize
)
1418 WXMICROWIN_CHECK_HDC
1420 // Set the old object temporarily, in case the assignment deletes an object
1421 // that's not yet selected out.
1424 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1428 if ( m_palette
.Ok() )
1430 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1431 GetHpaletteOf(m_palette
),
1434 m_oldPalette
= (WXHPALETTE
) oldPal
;
1437 ::RealizePalette(GetHdc());
1441 void wxDC::SetPalette(const wxPalette
& palette
)
1445 m_palette
= palette
;
1446 DoSelectPalette(true);
1450 void wxDC::InitializePalette()
1452 if ( wxDisplayDepth() <= 8 )
1454 // look for any window or parent that has a custom palette. If any has
1455 // one then we need to use it in drawing operations
1456 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1458 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1459 if ( m_hasCustomPalette
)
1461 m_palette
= win
->GetPalette();
1463 // turn on MSW translation for this palette
1469 #endif // wxUSE_PALETTE
1471 // SetFont/Pen/Brush() really ask to be implemented as a single template
1472 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1474 void wxDC::SetFont(const wxFont
& font
)
1476 WXMICROWIN_CHECK_HDC
1478 if ( font
== m_font
)
1483 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1484 if ( hfont
== HGDI_ERROR
)
1486 wxLogLastError(_T("SelectObject(font)"));
1491 m_oldFont
= (WXHPEN
)hfont
;
1496 else // invalid font, reset the current font
1500 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1502 wxLogLastError(_T("SelectObject(old font)"));
1508 m_font
= wxNullFont
;
1512 void wxDC::SetPen(const wxPen
& pen
)
1514 WXMICROWIN_CHECK_HDC
1521 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1522 if ( hpen
== HGDI_ERROR
)
1524 wxLogLastError(_T("SelectObject(pen)"));
1529 m_oldPen
= (WXHPEN
)hpen
;
1534 else // invalid pen, reset the current pen
1538 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1540 wxLogLastError(_T("SelectObject(old pen)"));
1550 void wxDC::SetBrush(const wxBrush
& brush
)
1552 WXMICROWIN_CHECK_HDC
1554 if ( brush
== m_brush
)
1559 // we must make sure the brush is aligned with the logical coordinates
1560 // before selecting it
1561 wxBitmap
*stipple
= brush
.GetStipple();
1562 if ( stipple
&& stipple
->Ok() )
1564 if ( !::SetBrushOrgEx
1567 m_deviceOriginX
% stipple
->GetWidth(),
1568 m_deviceOriginY
% stipple
->GetHeight(),
1569 NULL
// [out] previous brush origin
1572 wxLogLastError(_T("SetBrushOrgEx()"));
1576 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1577 if ( hbrush
== HGDI_ERROR
)
1579 wxLogLastError(_T("SelectObject(brush)"));
1584 m_oldBrush
= (WXHPEN
)hbrush
;
1589 else // invalid brush, reset the current brush
1593 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1595 wxLogLastError(_T("SelectObject(old brush)"));
1601 m_brush
= wxNullBrush
;
1605 void wxDC::SetBackground(const wxBrush
& brush
)
1607 WXMICROWIN_CHECK_HDC
1609 m_backgroundBrush
= brush
;
1611 if ( m_backgroundBrush
.Ok() )
1613 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1617 void wxDC::SetBackgroundMode(int mode
)
1619 WXMICROWIN_CHECK_HDC
1621 m_backgroundMode
= mode
;
1623 // SetBackgroundColour now only refers to text background
1624 // and m_backgroundMode is used there
1627 void wxDC::SetLogicalFunction(int function
)
1629 WXMICROWIN_CHECK_HDC
1631 m_logicalFunction
= function
;
1636 void wxDC::SetRop(WXHDC dc
)
1638 if ( !dc
|| m_logicalFunction
< 0 )
1643 switch (m_logicalFunction
)
1645 case wxCLEAR
: rop
= R2_BLACK
; break;
1646 case wxXOR
: rop
= R2_XORPEN
; break;
1647 case wxINVERT
: rop
= R2_NOT
; break;
1648 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1649 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1650 case wxCOPY
: rop
= R2_COPYPEN
; break;
1651 case wxAND
: rop
= R2_MASKPEN
; break;
1652 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1653 case wxNO_OP
: rop
= R2_NOP
; break;
1654 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1655 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1656 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1657 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1658 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1659 case wxOR
: rop
= R2_MERGEPEN
; break;
1660 case wxSET
: rop
= R2_WHITE
; break;
1663 wxFAIL_MSG( wxT("unsupported logical function") );
1667 SetROP2(GetHdc(), rop
);
1670 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1672 // We might be previewing, so return true to let it continue.
1680 void wxDC::StartPage()
1684 void wxDC::EndPage()
1688 // ---------------------------------------------------------------------------
1690 // ---------------------------------------------------------------------------
1692 wxCoord
wxDC::GetCharHeight() const
1694 WXMICROWIN_CHECK_HDC_RET(0)
1696 TEXTMETRIC lpTextMetric
;
1698 GetTextMetrics(GetHdc(), &lpTextMetric
);
1700 return lpTextMetric
.tmHeight
;
1703 wxCoord
wxDC::GetCharWidth() const
1705 WXMICROWIN_CHECK_HDC_RET(0)
1707 TEXTMETRIC lpTextMetric
;
1709 GetTextMetrics(GetHdc(), &lpTextMetric
);
1711 return lpTextMetric
.tmAveCharWidth
;
1714 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1715 wxCoord
*descent
, wxCoord
*externalLeading
,
1718 #ifdef __WXMICROWIN__
1723 if (descent
) *descent
= 0;
1724 if (externalLeading
) *externalLeading
= 0;
1727 #endif // __WXMICROWIN__
1732 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1734 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1736 else // don't change the font
1742 const size_t len
= string
.length();
1743 if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) )
1745 wxLogLastError(_T("GetTextExtentPoint32()"));
1748 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1749 // the result computed by GetTextExtentPoint32() may be too small as it
1750 // accounts for under/overhang of the first/last character while we want
1751 // just the bounding rect for this string so adjust the width as needed
1752 // (using API not available in 2002 SDKs of WinCE)
1756 const wxChar chFirst
= *string
.begin();
1757 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1759 if ( width
.abcA
< 0 )
1760 sizeRect
.cx
-= width
.abcA
;
1764 const wxChar chLast
= *string
.rbegin();
1765 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1767 //else: we already have the width of the last character
1769 if ( width
.abcC
< 0 )
1770 sizeRect
.cx
-= width
.abcC
;
1772 //else: GetCharABCWidths() failed, not a TrueType font?
1774 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1777 ::GetTextMetrics(GetHdc(), &tm
);
1784 *descent
= tm
.tmDescent
;
1785 if (externalLeading
)
1786 *externalLeading
= tm
.tmExternalLeading
;
1790 ::SelectObject(GetHdc(), hfontOld
);
1795 // Each element of the array will be the width of the string up to and
1796 // including the coresoponding character in text.
1798 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1800 static int maxLenText
= -1;
1801 static int maxWidth
= -1;
1804 int stlen
= text
.length();
1806 if (maxLenText
== -1)
1808 // Win9x and WinNT+ have different limits
1809 int version
= wxGetOsVersion();
1810 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1811 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1815 widths
.Add(0, stlen
); // fill the array with zeros
1819 if (!::GetTextExtentExPoint(GetHdc(),
1820 text
.c_str(), // string to check
1821 wxMin(stlen
, maxLenText
),
1823 &fit
, // [out] count of chars
1825 &widths
[0], // array to fill
1829 wxLogLastError(wxT("GetTextExtentExPoint"));
1839 void wxDC::SetMapMode(int mode
)
1841 WXMICROWIN_CHECK_HDC
1843 m_mappingMode
= mode
;
1845 if ( mode
== wxMM_TEXT
)
1848 m_logicalScaleY
= 1.0;
1850 else // need to do some calculations
1852 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1853 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1854 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1855 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1857 if ( (mm_width
== 0) || (mm_height
== 0) )
1859 // we can't calculate mm2pixels[XY] then!
1863 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1864 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1869 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1870 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1874 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1875 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1879 m_logicalScaleX
= mm2pixelsX
;
1880 m_logicalScaleY
= mm2pixelsY
;
1884 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1885 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1889 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1893 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1894 // cases we could do with MM_TEXT and in the remaining 0.9% with
1895 // MM_ISOTROPIC (TODO!)
1897 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1899 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1900 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1902 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1903 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1905 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1906 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1910 void wxDC::SetUserScale(double x
, double y
)
1912 WXMICROWIN_CHECK_HDC
1914 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1920 this->SetMapMode(m_mappingMode
);
1923 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1924 bool WXUNUSED_IN_WINCE(yBottomUp
))
1926 WXMICROWIN_CHECK_HDC
1929 int signX
= xLeftRight
? 1 : -1,
1930 signY
= yBottomUp
? -1 : 1;
1932 if ( signX
!= m_signX
|| signY
!= m_signY
)
1937 SetMapMode(m_mappingMode
);
1942 void wxDC::SetSystemScale(double x
, double y
)
1944 WXMICROWIN_CHECK_HDC
1946 if ( x
== m_scaleX
&& y
== m_scaleY
)
1953 SetMapMode(m_mappingMode
);
1957 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1959 WXMICROWIN_CHECK_HDC
1961 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1964 m_logicalOriginX
= x
;
1965 m_logicalOriginY
= y
;
1968 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1972 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1974 WXMICROWIN_CHECK_HDC
1976 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1979 m_deviceOriginX
= x
;
1980 m_deviceOriginY
= y
;
1982 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1985 // ---------------------------------------------------------------------------
1986 // coordinates transformations
1987 // ---------------------------------------------------------------------------
1989 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1991 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1994 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1996 // axis orientation is not taken into account for conversion of a distance
1997 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
2000 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
2002 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
2005 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
2007 // axis orientation is not taken into account for conversion of a distance
2008 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
2011 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
2013 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
2016 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
2018 // axis orientation is not taken into account for conversion of a distance
2019 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
2022 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
2024 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
2027 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
2029 // axis orientation is not taken into account for conversion of a distance
2030 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
2033 // ---------------------------------------------------------------------------
2035 // ---------------------------------------------------------------------------
2037 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
2038 wxCoord width
, wxCoord height
,
2039 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
2040 int rop
, bool useMask
,
2041 wxCoord xsrcMask
, wxCoord ysrcMask
)
2043 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2045 WXMICROWIN_CHECK_HDC_RET(false)
2047 // if either the source or destination has alpha channel, we must use
2048 // AlphaBlt() as other function don't handle it correctly
2049 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2050 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2051 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2053 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2054 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2058 wxMask
*mask
= NULL
;
2061 mask
= bmpSrc
.GetMask();
2063 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2065 // don't give assert here because this would break existing
2066 // programs - just silently ignore useMask parameter
2071 if (xsrcMask
== -1 && ysrcMask
== -1)
2073 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2076 COLORREF old_textground
= ::GetTextColor(GetHdc());
2077 COLORREF old_background
= ::GetBkColor(GetHdc());
2078 if (m_textForegroundColour
.Ok())
2080 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2082 if (m_textBackgroundColour
.Ok())
2084 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2090 case wxXOR
: dwRop
= SRCINVERT
; break;
2091 case wxINVERT
: dwRop
= DSTINVERT
; break;
2092 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2093 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2094 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2095 case wxSET
: dwRop
= WHITENESS
; break;
2096 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2097 case wxAND
: dwRop
= SRCAND
; break;
2098 case wxOR
: dwRop
= SRCPAINT
; break;
2099 case wxEQUIV
: dwRop
= 0x00990066; break;
2100 case wxNAND
: dwRop
= 0x007700E6; break;
2101 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2102 case wxCOPY
: dwRop
= SRCCOPY
; break;
2103 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2104 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2105 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2107 wxFAIL_MSG( wxT("unsupported logical function") );
2111 bool success
= false;
2116 // we want the part of the image corresponding to the mask to be
2117 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2118 // meaning of fg and bg is inverted which corresponds to wxWin notion
2119 // of the mask which is also contrary to the Windows one)
2121 // On some systems, MaskBlt succeeds yet is much much slower
2122 // than the wxWidgets fall-back implementation. So we need
2123 // to be able to switch this on and off at runtime.
2124 #if wxUSE_SYSTEM_OPTIONS
2125 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2131 xdest
, ydest
, width
, height
,
2134 (HBITMAP
)mask
->GetMaskBitmap(),
2136 MAKEROP4(dwRop
, DSTCOPY
)
2143 // Blit bitmap with mask
2146 HBITMAP buffer_bmap
;
2148 #if wxUSE_DC_CACHEING
2149 // create a temp buffer bitmap and DCs to access it and the mask
2150 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2151 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2153 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2154 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2156 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2159 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2160 #else // !wxUSE_DC_CACHEING
2161 // create a temp buffer bitmap and DCs to access it and the mask
2162 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2163 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2164 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2165 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2166 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2167 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2169 // copy dest to buffer
2170 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2171 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2173 wxLogLastError(wxT("BitBlt"));
2176 // copy src to buffer using selected raster op
2177 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2178 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2180 wxLogLastError(wxT("BitBlt"));
2183 // set masked area in buffer to BLACK (pixel value 0)
2184 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2185 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2186 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2187 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2189 wxLogLastError(wxT("BitBlt"));
2192 // set unmasked area in dest to BLACK
2193 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2194 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2195 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2196 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2198 wxLogLastError(wxT("BitBlt"));
2200 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2201 ::SetTextColor(GetHdc(), prevCol
);
2203 // OR buffer to dest
2204 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2205 (int)width
, (int)height
,
2206 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2209 wxLogLastError(wxT("BitBlt"));
2212 // tidy up temporary DCs and bitmap
2213 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2214 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2216 #if !wxUSE_DC_CACHEING
2218 ::DeleteDC(dc_mask
);
2219 ::DeleteDC(dc_buffer
);
2220 ::DeleteObject(buffer_bmap
);
2225 else // no mask, just BitBlt() it
2227 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2228 // use StretchBlt() if available and finally fall back to BitBlt()
2230 // FIXME: use appropriate WinCE functions
2232 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2233 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2238 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2240 &ds
) == sizeof(ds
) )
2242 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2244 // Figure out what co-ordinate system we're supposed to specify
2246 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2250 ysrc
= hDIB
- (ysrc
+ height
);
2253 if ( ::StretchDIBits(GetHdc(),
2259 (LPBITMAPINFO
)&ds
.dsBmih
,
2262 ) == (int)GDI_ERROR
)
2264 // On Win9x this API fails most (all?) of the time, so
2265 // logging it becomes quite distracting. Since it falls
2266 // back to the code below this is not really serious, so
2268 //wxLogLastError(wxT("StretchDIBits"));
2277 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2282 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2288 xdest
, ydest
, width
, height
,
2290 xsrc
, ysrc
, width
, height
,
2294 wxLogLastError(_T("StretchBlt"));
2308 (int)width
, (int)height
,
2314 wxLogLastError(_T("BitBlt"));
2323 ::SetTextColor(GetHdc(), old_textground
);
2324 ::SetBkColor(GetHdc(), old_background
);
2329 void wxDC::GetDeviceSize(int *width
, int *height
) const
2331 WXMICROWIN_CHECK_HDC
2334 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2336 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2339 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2341 WXMICROWIN_CHECK_HDC
2343 // if we implement it in terms of DoGetSize() instead of directly using the
2344 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2345 // will also work for wxWindowDC and wxClientDC even though their size is
2346 // not the same as the total size of the screen
2347 int wPixels
, hPixels
;
2348 DoGetSize(&wPixels
, &hPixels
);
2352 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2354 wxCHECK_RET( wTotal
, _T("0 width device?") );
2356 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2361 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2363 wxCHECK_RET( hTotal
, _T("0 height device?") );
2365 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2369 wxSize
wxDC::GetPPI() const
2371 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2373 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2374 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2376 return wxSize(x
, y
);
2379 // For use by wxWidgets only, unless custom units are required.
2380 void wxDC::SetLogicalScale(double x
, double y
)
2382 WXMICROWIN_CHECK_HDC
2384 m_logicalScaleX
= x
;
2385 m_logicalScaleY
= y
;
2388 // ----------------------------------------------------------------------------
2390 // ----------------------------------------------------------------------------
2392 #if wxUSE_DC_CACHEING
2395 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2396 * improve it in due course, either using arrays, or simply storing pointers to one
2397 * entry for the bitmap, and two for the DCs. -- JACS
2400 wxList
wxDC::sm_bitmapCache
;
2401 wxList
wxDC::sm_dcCache
;
2403 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2412 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2421 wxDCCacheEntry::~wxDCCacheEntry()
2424 ::DeleteObject((HBITMAP
) m_bitmap
);
2426 ::DeleteDC((HDC
) m_dc
);
2429 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2431 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2432 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2435 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2437 if (entry
->m_depth
== depth
)
2439 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2441 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2442 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2443 if ( !entry
->m_bitmap
)
2445 wxLogLastError(wxT("CreateCompatibleBitmap"));
2447 entry
->m_width
= w
; entry
->m_height
= h
;
2453 node
= node
->GetNext();
2455 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2458 wxLogLastError(wxT("CreateCompatibleBitmap"));
2460 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2461 AddToBitmapCache(entry
);
2465 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2467 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2468 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2471 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2473 // Don't return the same one as we already have
2474 if (!notThis
|| (notThis
!= entry
))
2476 if (entry
->m_depth
== depth
)
2482 node
= node
->GetNext();
2484 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2487 wxLogLastError(wxT("CreateCompatibleDC"));
2489 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2490 AddToDCCache(entry
);
2494 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2496 sm_bitmapCache
.Append(entry
);
2499 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2501 sm_dcCache
.Append(entry
);
2504 void wxDC::ClearCache()
2506 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2507 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2510 // Clean up cache at app exit
2511 class wxDCModule
: public wxModule
2514 virtual bool OnInit() { return true; }
2515 virtual void OnExit() { wxDC::ClearCache(); }
2518 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2521 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2523 #endif // wxUSE_DC_CACHEING
2525 // ----------------------------------------------------------------------------
2526 // alpha channel support
2527 // ----------------------------------------------------------------------------
2529 static bool AlphaBlt(HDC hdcDst
,
2530 int x
, int y
, int width
, int height
,
2531 int srcX
, int srcY
, HDC hdcSrc
,
2532 const wxBitmap
& bmp
)
2534 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2535 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2537 // do we have AlphaBlend() and company in the headers?
2538 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2539 // yes, now try to see if we have it during run-time
2540 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2541 HDC
,int,int,int,int,
2544 static AlphaBlend_t pfnAlphaBlend
= wxMSIMG32_SYMBOL(AlphaBlend
);
2545 if ( pfnAlphaBlend
)
2548 bf
.BlendOp
= AC_SRC_OVER
;
2550 bf
.SourceConstantAlpha
= 0xff;
2551 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2553 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2554 hdcSrc
, srcX
, srcY
, width
, height
,
2557 // skip wxAlphaBlend() call below
2561 wxLogLastError(_T("AlphaBlend"));
2564 wxUnusedVar(hdcSrc
);
2565 #endif // defined(AC_SRC_OVER)
2567 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2569 #ifdef wxHAVE_RAW_BITMAP
2570 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2573 #else // !wxHAVE_RAW_BITMAP
2574 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2575 // alpha but at least something will be shown like this)
2578 #endif // wxHAVE_RAW_BITMAP
2582 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2583 #ifdef wxHAVE_RAW_BITMAP
2586 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2588 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2590 // get the destination DC pixels
2591 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2593 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2595 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2597 wxLogLastError(_T("BitBlt"));
2600 // combine them with the source bitmap using alpha
2601 wxAlphaPixelData
dataDst(bmpDst
),
2602 dataSrc((wxBitmap
&)bmpSrc
);
2604 wxCHECK_RET( dataDst
&& dataSrc
,
2605 _T("failed to get raw data in wxAlphaBlend") );
2607 wxAlphaPixelData::Iterator
pDst(dataDst
),
2610 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2612 for ( int y
= 0; y
< h
; y
++ )
2614 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2615 pSrcRowStart
= pSrc
;
2617 for ( int x
= 0; x
< w
; x
++ )
2619 // note that source bitmap uses premultiplied alpha (as required by
2620 // the real AlphaBlend)
2621 const unsigned beta
= 255 - pSrc
.Alpha();
2623 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2624 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2625 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2631 pDst
= pDstRowStart
;
2632 pSrc
= pSrcRowStart
;
2633 pDst
.OffsetY(dataDst
, 1);
2634 pSrc
.OffsetY(dataSrc
, 1);
2637 // and finally blit them back to the destination DC
2638 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2640 wxLogLastError(_T("BitBlt"));
2644 #endif // #ifdef wxHAVE_RAW_BITMAP
2646 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2647 const wxColour
& initialColour
,
2648 const wxColour
& destColour
,
2649 wxDirection nDirection
)
2651 // use native function if we have compile-time support it and can load it
2652 // during run-time (linking to it statically would make the program
2653 // unusable on earlier Windows versions)
2654 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2656 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2657 static GradientFill_t pfnGradientFill
= wxMSIMG32_SYMBOL(GradientFill
);
2659 if ( pfnGradientFill
)
2661 GRADIENT_RECT grect
;
2662 grect
.UpperLeft
= 0;
2663 grect
.LowerRight
= 1;
2665 // invert colours direction if not filling from left-to-right or
2667 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2669 // one vertex for upper left and one for upper-right
2670 TRIVERTEX vertices
[2];
2672 vertices
[0].x
= rect
.GetLeft();
2673 vertices
[0].y
= rect
.GetTop();
2674 vertices
[1].x
= rect
.GetRight();
2675 vertices
[1].y
= rect
.GetBottom();
2677 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2678 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2679 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2680 vertices
[firstVertex
].Alpha
= 0;
2681 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2682 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2683 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2684 vertices
[1 - firstVertex
].Alpha
= 0;
2686 if ( (*pfnGradientFill
)
2693 nDirection
== wxWEST
|| nDirection
== wxEAST
2694 ? GRADIENT_FILL_RECT_H
2695 : GRADIENT_FILL_RECT_V
2698 // skip call of the base class version below
2702 wxLogLastError(_T("GradientFill"));
2704 #endif // wxUSE_DYNLIB_CLASS
2706 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);