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/dynload.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
)
486 // TODO: this should restore the previous clipping region,
487 // so that OnPaint processing works correctly, and the update
488 // clipping region doesn't get destroyed after the first
489 // DestroyClippingRegion.
490 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
491 ::SelectClipRgn(GetHdc(), rgn
);
495 wxDCBase::DestroyClippingRegion();
498 // ---------------------------------------------------------------------------
499 // query capabilities
500 // ---------------------------------------------------------------------------
502 bool wxDC::CanDrawBitmap() const
507 bool wxDC::CanGetTextExtent() const
509 #ifdef __WXMICROWIN__
510 // TODO Extend MicroWindows' GetDeviceCaps function
513 // What sort of display is it?
514 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
516 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
520 int wxDC::GetDepth() const
522 WXMICROWIN_CHECK_HDC_RET(16)
524 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
527 // ---------------------------------------------------------------------------
529 // ---------------------------------------------------------------------------
538 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
542 // No, I think we should simply ignore this if printing on e.g.
544 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
545 if (!m_selectedBitmap
.Ok())
548 rect
.left
= 0; rect
.top
= 0;
549 rect
.right
= m_selectedBitmap
.GetWidth();
550 rect
.bottom
= m_selectedBitmap
.GetHeight();
554 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
557 DWORD colour
= ::GetBkColor(GetHdc());
558 HBRUSH brush
= ::CreateSolidBrush(colour
);
559 ::FillRect(GetHdc(), &rect
, brush
);
560 ::DeleteObject(brush
);
563 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
564 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
566 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
568 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
569 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
570 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
571 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
575 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
576 wxCoord
WXUNUSED_IN_WINCE(y
),
577 const wxColour
& WXUNUSED_IN_WINCE(col
),
578 int WXUNUSED_IN_WINCE(style
))
583 WXMICROWIN_CHECK_HDC_RET(false)
585 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
587 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
588 : FLOODFILLBORDER
) ) ;
591 // quoting from the MSDN docs:
593 // Following are some of the reasons this function might fail:
595 // * The filling could not be completed.
596 // * The specified point has the boundary color specified by the
597 // crColor parameter (if FLOODFILLBORDER was requested).
598 // * The specified point does not have the color specified by
599 // crColor (if FLOODFILLSURFACE was requested)
600 // * The point is outside the clipping region that is, it is not
601 // visible on the device.
603 wxLogLastError(wxT("ExtFloodFill"));
606 CalcBoundingBox(x
, y
);
612 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
614 WXMICROWIN_CHECK_HDC_RET(false)
616 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
618 // get the color of the pixel
619 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
621 wxRGBToColour(*col
, pixelcolor
);
626 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
630 wxCoord x1
= x
-VIEWPORT_EXTENT
;
631 wxCoord y1
= y
-VIEWPORT_EXTENT
;
632 wxCoord x2
= x
+VIEWPORT_EXTENT
;
633 wxCoord y2
= y
+VIEWPORT_EXTENT
;
635 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
636 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
638 CalcBoundingBox(x1
, y1
);
639 CalcBoundingBox(x2
, y2
);
642 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
646 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
648 CalcBoundingBox(x1
, y1
);
649 CalcBoundingBox(x2
, y2
);
652 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
653 // and ending at (x2, y2)
654 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
655 wxCoord x2
, wxCoord y2
,
656 wxCoord xc
, wxCoord yc
)
659 // Slower emulation since WinCE doesn't support Pie and Arc
660 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
661 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
662 if( y1
>yc
) sa
= -sa
; // below center
663 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
664 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
669 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
673 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
674 wxCoord r
= (wxCoord
)radius
;
676 // treat the special case of full circle separately
677 if ( x1
== x2
&& y1
== y2
)
679 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
683 wxCoord xx1
= XLOG2DEV(x1
);
684 wxCoord yy1
= YLOG2DEV(y1
);
685 wxCoord xx2
= XLOG2DEV(x2
);
686 wxCoord yy2
= YLOG2DEV(y2
);
687 wxCoord xxc
= XLOG2DEV(xc
);
688 wxCoord yyc
= YLOG2DEV(yc
);
689 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
691 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
692 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
693 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
694 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
696 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
698 // Have to add 1 to bottom-right corner of rectangle
699 // to make semi-circles look right (crooked line otherwise).
700 // Unfortunately this is not a reliable method, depends
701 // on the size of shape.
702 // TODO: figure out why this happens!
703 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
707 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
710 CalcBoundingBox(xc
- r
, yc
- r
);
711 CalcBoundingBox(xc
+ r
, yc
+ r
);
715 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
716 wxCoord width
, wxCoord height
)
720 wxCoord x2
= x1
+ width
,
723 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
731 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
733 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
735 #else // Symantec-MicroWin
737 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
738 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
739 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
740 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
741 ::SetROP2(GetHdc(), R2_COPYPEN
);
742 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
743 MoveToEx(GetHdc(), x1
, y1
, NULL
);
744 LineTo(GetHdc(), x2
, y2
);
745 MoveToEx(GetHdc(), x2
, y1
, NULL
);
746 LineTo(GetHdc(), x1
, y2
);
747 ::SelectObject(GetHdc(), hPenOld
);
748 ::SelectObject(GetHdc(), hBrushOld
);
749 ::DeleteObject(blackPen
);
750 #endif // Win32/Symantec-MicroWin
752 CalcBoundingBox(x1
, y1
);
753 CalcBoundingBox(x2
, y2
);
756 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
760 COLORREF color
= 0x00ffffff;
763 color
= m_pen
.GetColour().GetPixel();
766 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
768 CalcBoundingBox(x
, y
);
771 void wxDC::DoDrawPolygon(int n
,
775 int WXUNUSED_IN_WINCE(fillStyle
))
779 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
781 // Do things less efficiently if we have offsets
782 if (xoffset
!= 0 || yoffset
!= 0)
784 POINT
*cpoints
= new POINT
[n
];
786 for (i
= 0; i
< n
; i
++)
788 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
789 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
791 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
794 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
796 (void)Polygon(GetHdc(), cpoints
, n
);
798 SetPolyFillMode(GetHdc(),prev
);
805 for (i
= 0; i
< n
; i
++)
806 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
809 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
811 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
813 SetPolyFillMode(GetHdc(),prev
);
819 wxDC::DoDrawPolyPolygon(int n
,
827 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
831 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
833 for (i
= cnt
= 0; i
< n
; i
++)
836 // Do things less efficiently if we have offsets
837 if (xoffset
!= 0 || yoffset
!= 0)
839 POINT
*cpoints
= new POINT
[cnt
];
840 for (i
= 0; i
< cnt
; i
++)
842 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
843 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
845 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
848 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
850 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
852 SetPolyFillMode(GetHdc(),prev
);
858 for (i
= 0; i
< cnt
; i
++)
859 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
862 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
864 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
866 SetPolyFillMode(GetHdc(),prev
);
873 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
877 // Do things less efficiently if we have offsets
878 if (xoffset
!= 0 || yoffset
!= 0)
880 POINT
*cpoints
= new POINT
[n
];
882 for (i
= 0; i
< n
; i
++)
884 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
885 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
887 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
889 (void)Polyline(GetHdc(), cpoints
, n
);
895 for (i
= 0; i
< n
; i
++)
896 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
898 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
902 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
906 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
908 wxCoord x2
= x
+ width
;
909 wxCoord y2
= y
+ height
;
911 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
914 rect
.left
= XLOG2DEV(x
);
915 rect
.top
= YLOG2DEV(y
);
916 rect
.right
= XLOG2DEV(x2
);
917 rect
.bottom
= YLOG2DEV(y2
);
918 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
922 // Windows draws the filled rectangles without outline (i.e. drawn with a
923 // transparent pen) one pixel smaller in both directions and we want them
924 // to have the same size regardless of which pen is used - adjust
926 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
927 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
929 // Apparently not needed for WinCE (see e.g. Life! demo)
936 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
940 CalcBoundingBox(x
, y
);
941 CalcBoundingBox(x2
, y2
);
944 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
948 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
950 // Now, a negative radius value is interpreted to mean
951 // 'the proportion of the smallest X or Y dimension'
955 double smallest
= (width
< height
) ? width
: height
;
956 radius
= (- radius
* smallest
);
959 wxCoord x2
= (x
+width
);
960 wxCoord y2
= (y
+height
);
962 // Windows draws the filled rectangles without outline (i.e. drawn with a
963 // transparent pen) one pixel smaller in both directions and we want them
964 // to have the same size regardless of which pen is used - adjust
965 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
971 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
972 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
974 CalcBoundingBox(x
, y
);
975 CalcBoundingBox(x2
, y2
);
978 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
982 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
984 wxCoord x2
= (x
+width
);
985 wxCoord y2
= (y
+height
);
987 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
989 CalcBoundingBox(x
, y
);
990 CalcBoundingBox(x2
, y2
);
994 void wxDC::DoDrawSpline(wxList
*points
)
997 // WinCE does not support ::PolyBezier so use generic version
998 wxDCBase::DoDrawSpline(points
);
1000 // quadratic b-spline to cubic bezier spline conversion
1002 // quadratic spline with control points P0,P1,P2
1003 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1005 // bezier spline with control points B0,B1,B2,B3
1006 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1008 // control points of bezier spline calculated from b-spline
1010 // B1 = (2*P1 + P0)/3
1011 // B2 = (2*P1 + P2)/3
1014 WXMICROWIN_CHECK_HDC
1016 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1018 const size_t n_points
= points
->GetCount();
1019 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1021 const size_t n_bezier_points
= n_points
* 3 + 1;
1022 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1023 size_t bezier_pos
= 0;
1024 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1026 wxList::compatibility_iterator node
= points
->GetFirst();
1027 wxPoint
*p
= (wxPoint
*)node
->GetData();
1028 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1029 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1031 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1034 node
= node
->GetNext();
1035 p
= (wxPoint
*)node
->GetData();
1039 cx1
= ( x1
+ x2
) / 2;
1040 cy1
= ( y1
+ y2
) / 2;
1041 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1042 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1044 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1048 while ((node
= node
->GetNext()) != NULL
)
1050 while ((node
= node
->GetNext()))
1051 #endif // !wxUSE_STL
1053 p
= (wxPoint
*)node
->GetData();
1058 cx4
= (x1
+ x2
) / 2;
1059 cy4
= (y1
+ y2
) / 2;
1060 // B0 is B3 of previous segment
1062 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1063 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1066 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1067 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1070 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1071 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1077 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1079 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1080 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1082 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1085 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1092 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1093 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1096 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1099 WXMICROWIN_CHECK_HDC
1101 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1106 int rx1
= XLOG2DEV(x
+w
/2);
1107 int ry1
= YLOG2DEV(y
+h
/2);
1114 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1115 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1116 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1117 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1119 // draw pie with NULL_PEN first and then outline otherwise a line is
1120 // drawn from the start and end points to the centre
1121 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1124 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1125 rx1
, ry1
, rx2
, ry2
);
1129 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1130 rx1
, ry1
-1, rx2
, ry2
-1);
1133 ::SelectObject(GetHdc(), hpenOld
);
1135 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1136 rx1
, ry1
, rx2
, ry2
);
1138 CalcBoundingBox(x
, y
);
1139 CalcBoundingBox(x2
, y2
);
1143 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1145 WXMICROWIN_CHECK_HDC
1147 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1150 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1152 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1155 CalcBoundingBox(x
, y
);
1156 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1159 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1161 WXMICROWIN_CHECK_HDC
1163 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1165 int width
= bmp
.GetWidth(),
1166 height
= bmp
.GetHeight();
1168 HBITMAP hbmpMask
= 0;
1171 HPALETTE oldPal
= 0;
1172 #endif // wxUSE_PALETTE
1174 if ( bmp
.HasAlpha() )
1177 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1179 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1185 wxMask
*mask
= bmp
.GetMask();
1187 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1191 // don't give assert here because this would break existing
1192 // programs - just silently ignore useMask parameter
1199 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1201 // On some systems, MaskBlt succeeds yet is much much slower
1202 // than the wxWidgets fall-back implementation. So we need
1203 // to be able to switch this on and off at runtime.
1205 #if wxUSE_SYSTEM_OPTIONS
1206 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1210 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1211 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1213 wxPalette
*pal
= bmp
.GetPalette();
1214 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1216 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1217 ::RealizePalette(hdcMem
);
1219 #endif // wxUSE_PALETTE
1221 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1224 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1228 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1229 #endif // wxUSE_PALETTE
1231 ::SelectObject(hdcMem
, hOldBitmap
);
1238 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1241 memDC
.SelectObject(bmp
);
1243 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1245 memDC
.SelectObject(wxNullBitmap
);
1248 else // no mask, just use BitBlt()
1251 HDC memdc
= ::CreateCompatibleDC( cdc
);
1252 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1254 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1256 COLORREF old_textground
= ::GetTextColor(GetHdc());
1257 COLORREF old_background
= ::GetBkColor(GetHdc());
1258 if (m_textForegroundColour
.Ok())
1260 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1262 if (m_textBackgroundColour
.Ok())
1264 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1268 wxPalette
*pal
= bmp
.GetPalette();
1269 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1271 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1272 ::RealizePalette(memdc
);
1274 #endif // wxUSE_PALETTE
1276 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1277 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1281 ::SelectPalette(memdc
, oldPal
, FALSE
);
1282 #endif // wxUSE_PALETTE
1284 ::SelectObject( memdc
, hOldBitmap
);
1285 ::DeleteDC( memdc
);
1287 ::SetTextColor(GetHdc(), old_textground
);
1288 ::SetBkColor(GetHdc(), old_background
);
1292 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1294 WXMICROWIN_CHECK_HDC
1296 DrawAnyText(text
, x
, y
);
1298 // update the bounding box
1299 CalcBoundingBox(x
, y
);
1302 GetTextExtent(text
, &w
, &h
);
1303 CalcBoundingBox(x
+ w
, y
+ h
);
1306 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1308 WXMICROWIN_CHECK_HDC
1310 // prepare for drawing the text
1311 if ( m_textForegroundColour
.Ok() )
1312 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1314 DWORD old_background
= 0;
1315 if ( m_textBackgroundColour
.Ok() )
1317 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1320 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1324 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1325 text
.c_str(), text
.length(), NULL
) == 0 )
1327 wxLogLastError(wxT("TextOut"));
1330 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1331 text
.c_str(), text
.length()) == 0 )
1333 wxLogLastError(wxT("TextOut"));
1337 // restore the old parameters (text foreground colour may be left because
1338 // it never is set to anything else, but background should remain
1339 // transparent even if we just drew an opaque string)
1340 if ( m_textBackgroundColour
.Ok() )
1341 (void)SetBkColor(GetHdc(), old_background
);
1343 SetBkMode(GetHdc(), TRANSPARENT
);
1346 void wxDC::DoDrawRotatedText(const wxString
& text
,
1347 wxCoord x
, wxCoord y
,
1350 WXMICROWIN_CHECK_HDC
1352 // we test that we have some font because otherwise we should still use the
1353 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1354 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1355 // font for drawing rotated fonts unfortunately)
1356 if ( (angle
== 0.0) && m_font
.Ok() )
1358 DoDrawText(text
, x
, y
);
1360 #ifndef __WXMICROWIN__
1363 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1364 // because it's not TrueType and so can't have non zero
1365 // orientation/escapement under Win9x
1366 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1367 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1369 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1371 wxLogLastError(wxT("GetObject(hfont)"));
1374 // GDI wants the angle in tenth of degree
1375 long angle10
= (long)(angle
* 10);
1376 lf
.lfEscapement
= angle10
;
1377 lf
. lfOrientation
= angle10
;
1379 hfont
= ::CreateFontIndirect(&lf
);
1382 wxLogLastError(wxT("CreateFont"));
1386 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1388 DrawAnyText(text
, x
, y
);
1390 (void)::SelectObject(GetHdc(), hfontOld
);
1391 (void)::DeleteObject(hfont
);
1394 // call the bounding box by adding all four vertices of the rectangle
1395 // containing the text to it (simpler and probably not slower than
1396 // determining which of them is really topmost/leftmost/...)
1398 GetTextExtent(text
, &w
, &h
);
1400 double rad
= DegToRad(angle
);
1402 // "upper left" and "upper right"
1403 CalcBoundingBox(x
, y
);
1404 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1406 // "bottom left" and "bottom right"
1407 x
+= (wxCoord
)(h
*sin(rad
));
1408 y
+= (wxCoord
)(h
*cos(rad
));
1409 CalcBoundingBox(x
, y
);
1410 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1415 // ---------------------------------------------------------------------------
1417 // ---------------------------------------------------------------------------
1421 void wxDC::DoSelectPalette(bool realize
)
1423 WXMICROWIN_CHECK_HDC
1425 // Set the old object temporarily, in case the assignment deletes an object
1426 // that's not yet selected out.
1429 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1433 if ( m_palette
.Ok() )
1435 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1436 GetHpaletteOf(m_palette
),
1439 m_oldPalette
= (WXHPALETTE
) oldPal
;
1442 ::RealizePalette(GetHdc());
1446 void wxDC::SetPalette(const wxPalette
& palette
)
1450 m_palette
= palette
;
1451 DoSelectPalette(true);
1455 void wxDC::InitializePalette()
1457 if ( wxDisplayDepth() <= 8 )
1459 // look for any window or parent that has a custom palette. If any has
1460 // one then we need to use it in drawing operations
1461 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1463 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1464 if ( m_hasCustomPalette
)
1466 m_palette
= win
->GetPalette();
1468 // turn on MSW translation for this palette
1474 #endif // wxUSE_PALETTE
1476 // SetFont/Pen/Brush() really ask to be implemented as a single template
1477 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1479 void wxDC::SetFont(const wxFont
& font
)
1481 WXMICROWIN_CHECK_HDC
1483 if ( font
== m_font
)
1488 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1489 if ( hfont
== HGDI_ERROR
)
1491 wxLogLastError(_T("SelectObject(font)"));
1496 m_oldFont
= (WXHPEN
)hfont
;
1501 else // invalid font, reset the current font
1505 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1507 wxLogLastError(_T("SelectObject(old font)"));
1513 m_font
= wxNullFont
;
1517 void wxDC::SetPen(const wxPen
& pen
)
1519 WXMICROWIN_CHECK_HDC
1526 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1527 if ( hpen
== HGDI_ERROR
)
1529 wxLogLastError(_T("SelectObject(pen)"));
1534 m_oldPen
= (WXHPEN
)hpen
;
1539 else // invalid pen, reset the current pen
1543 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1545 wxLogLastError(_T("SelectObject(old pen)"));
1555 void wxDC::SetBrush(const wxBrush
& brush
)
1557 WXMICROWIN_CHECK_HDC
1559 if ( brush
== m_brush
)
1564 // we must make sure the brush is aligned with the logical coordinates
1565 // before selecting it
1566 wxBitmap
*stipple
= brush
.GetStipple();
1567 if ( stipple
&& stipple
->Ok() )
1569 if ( !::SetBrushOrgEx
1572 m_deviceOriginX
% stipple
->GetWidth(),
1573 m_deviceOriginY
% stipple
->GetHeight(),
1574 NULL
// [out] previous brush origin
1577 wxLogLastError(_T("SetBrushOrgEx()"));
1581 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1582 if ( hbrush
== HGDI_ERROR
)
1584 wxLogLastError(_T("SelectObject(brush)"));
1589 m_oldBrush
= (WXHPEN
)hbrush
;
1594 else // invalid brush, reset the current brush
1598 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1600 wxLogLastError(_T("SelectObject(old brush)"));
1606 m_brush
= wxNullBrush
;
1610 void wxDC::SetBackground(const wxBrush
& brush
)
1612 WXMICROWIN_CHECK_HDC
1614 m_backgroundBrush
= brush
;
1616 if ( m_backgroundBrush
.Ok() )
1618 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1622 void wxDC::SetBackgroundMode(int mode
)
1624 WXMICROWIN_CHECK_HDC
1626 m_backgroundMode
= mode
;
1628 // SetBackgroundColour now only refers to text background
1629 // and m_backgroundMode is used there
1632 void wxDC::SetLogicalFunction(int function
)
1634 WXMICROWIN_CHECK_HDC
1636 m_logicalFunction
= function
;
1641 void wxDC::SetRop(WXHDC dc
)
1643 if ( !dc
|| m_logicalFunction
< 0 )
1648 switch (m_logicalFunction
)
1650 case wxCLEAR
: rop
= R2_BLACK
; break;
1651 case wxXOR
: rop
= R2_XORPEN
; break;
1652 case wxINVERT
: rop
= R2_NOT
; break;
1653 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1654 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1655 case wxCOPY
: rop
= R2_COPYPEN
; break;
1656 case wxAND
: rop
= R2_MASKPEN
; break;
1657 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1658 case wxNO_OP
: rop
= R2_NOP
; break;
1659 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1660 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1661 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1662 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1663 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1664 case wxOR
: rop
= R2_MERGEPEN
; break;
1665 case wxSET
: rop
= R2_WHITE
; break;
1668 wxFAIL_MSG( wxT("unsupported logical function") );
1672 SetROP2(GetHdc(), rop
);
1675 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1677 // We might be previewing, so return true to let it continue.
1685 void wxDC::StartPage()
1689 void wxDC::EndPage()
1693 // ---------------------------------------------------------------------------
1695 // ---------------------------------------------------------------------------
1697 wxCoord
wxDC::GetCharHeight() const
1699 WXMICROWIN_CHECK_HDC_RET(0)
1701 TEXTMETRIC lpTextMetric
;
1703 GetTextMetrics(GetHdc(), &lpTextMetric
);
1705 return lpTextMetric
.tmHeight
;
1708 wxCoord
wxDC::GetCharWidth() const
1710 WXMICROWIN_CHECK_HDC_RET(0)
1712 TEXTMETRIC lpTextMetric
;
1714 GetTextMetrics(GetHdc(), &lpTextMetric
);
1716 return lpTextMetric
.tmAveCharWidth
;
1719 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1720 wxCoord
*descent
, wxCoord
*externalLeading
,
1723 #ifdef __WXMICROWIN__
1728 if (descent
) *descent
= 0;
1729 if (externalLeading
) *externalLeading
= 0;
1732 #endif // __WXMICROWIN__
1737 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1739 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1741 else // don't change the font
1749 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1750 GetTextMetrics(GetHdc(), &tm
);
1757 *descent
= tm
.tmDescent
;
1758 if (externalLeading
)
1759 *externalLeading
= tm
.tmExternalLeading
;
1763 ::SelectObject(GetHdc(), hfontOld
);
1768 // Each element of the array will be the width of the string up to and
1769 // including the coresoponding character in text.
1771 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1773 static int maxLenText
= -1;
1774 static int maxWidth
= -1;
1777 int stlen
= text
.length();
1779 if (maxLenText
== -1)
1781 // Win9x and WinNT+ have different limits
1782 int version
= wxGetOsVersion();
1783 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1784 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1788 widths
.Add(0, stlen
); // fill the array with zeros
1792 if (!::GetTextExtentExPoint(GetHdc(),
1793 text
.c_str(), // string to check
1794 wxMin(stlen
, maxLenText
),
1796 &fit
, // [out] count of chars
1798 &widths
[0], // array to fill
1802 wxLogLastError(wxT("GetTextExtentExPoint"));
1812 void wxDC::SetMapMode(int mode
)
1814 WXMICROWIN_CHECK_HDC
1816 m_mappingMode
= mode
;
1818 if ( mode
== wxMM_TEXT
)
1821 m_logicalScaleY
= 1.0;
1823 else // need to do some calculations
1825 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1826 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1827 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1828 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1830 if ( (mm_width
== 0) || (mm_height
== 0) )
1832 // we can't calculate mm2pixels[XY] then!
1836 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1837 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1842 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1843 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1847 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1848 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1852 m_logicalScaleX
= mm2pixelsX
;
1853 m_logicalScaleY
= mm2pixelsY
;
1857 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1858 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1862 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1866 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1867 // cases we could do with MM_TEXT and in the remaining 0.9% with
1868 // MM_ISOTROPIC (TODO!)
1870 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1872 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1873 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1875 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1876 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1878 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1879 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1883 void wxDC::SetUserScale(double x
, double y
)
1885 WXMICROWIN_CHECK_HDC
1887 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1893 this->SetMapMode(m_mappingMode
);
1896 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1897 bool WXUNUSED_IN_WINCE(yBottomUp
))
1899 WXMICROWIN_CHECK_HDC
1902 int signX
= xLeftRight
? 1 : -1,
1903 signY
= yBottomUp
? -1 : 1;
1905 if ( signX
!= m_signX
|| signY
!= m_signY
)
1910 SetMapMode(m_mappingMode
);
1915 void wxDC::SetSystemScale(double x
, double y
)
1917 WXMICROWIN_CHECK_HDC
1919 if ( x
== m_scaleX
&& y
== m_scaleY
)
1926 SetMapMode(m_mappingMode
);
1930 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1932 WXMICROWIN_CHECK_HDC
1934 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1937 m_logicalOriginX
= x
;
1938 m_logicalOriginY
= y
;
1941 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1945 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1947 WXMICROWIN_CHECK_HDC
1949 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1952 m_deviceOriginX
= x
;
1953 m_deviceOriginY
= y
;
1955 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1958 // ---------------------------------------------------------------------------
1959 // coordinates transformations
1960 // ---------------------------------------------------------------------------
1962 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1964 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1967 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1969 // axis orientation is not taken into account for conversion of a distance
1970 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1973 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1975 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1978 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1980 // axis orientation is not taken into account for conversion of a distance
1981 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1984 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1986 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1989 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1991 // axis orientation is not taken into account for conversion of a distance
1992 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1995 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1997 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
2000 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
2002 // axis orientation is not taken into account for conversion of a distance
2003 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
2006 // ---------------------------------------------------------------------------
2008 // ---------------------------------------------------------------------------
2010 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
2011 wxCoord width
, wxCoord height
,
2012 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
2013 int rop
, bool useMask
,
2014 wxCoord xsrcMask
, wxCoord ysrcMask
)
2016 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2018 WXMICROWIN_CHECK_HDC_RET(false)
2020 // if either the source or destination has alpha channel, we must use
2021 // AlphaBlt() as other function don't handle it correctly
2022 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2023 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2024 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2026 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2027 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2031 wxMask
*mask
= NULL
;
2034 mask
= bmpSrc
.GetMask();
2036 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2038 // don't give assert here because this would break existing
2039 // programs - just silently ignore useMask parameter
2044 if (xsrcMask
== -1 && ysrcMask
== -1)
2046 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2049 COLORREF old_textground
= ::GetTextColor(GetHdc());
2050 COLORREF old_background
= ::GetBkColor(GetHdc());
2051 if (m_textForegroundColour
.Ok())
2053 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2055 if (m_textBackgroundColour
.Ok())
2057 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2063 case wxXOR
: dwRop
= SRCINVERT
; break;
2064 case wxINVERT
: dwRop
= DSTINVERT
; break;
2065 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2066 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2067 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2068 case wxSET
: dwRop
= WHITENESS
; break;
2069 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2070 case wxAND
: dwRop
= SRCAND
; break;
2071 case wxOR
: dwRop
= SRCPAINT
; break;
2072 case wxEQUIV
: dwRop
= 0x00990066; break;
2073 case wxNAND
: dwRop
= 0x007700E6; break;
2074 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2075 case wxCOPY
: dwRop
= SRCCOPY
; break;
2076 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2077 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2078 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2080 wxFAIL_MSG( wxT("unsupported logical function") );
2084 bool success
= false;
2089 // we want the part of the image corresponding to the mask to be
2090 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2091 // meaning of fg and bg is inverted which corresponds to wxWin notion
2092 // of the mask which is also contrary to the Windows one)
2094 // On some systems, MaskBlt succeeds yet is much much slower
2095 // than the wxWidgets fall-back implementation. So we need
2096 // to be able to switch this on and off at runtime.
2097 #if wxUSE_SYSTEM_OPTIONS
2098 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2104 xdest
, ydest
, width
, height
,
2107 (HBITMAP
)mask
->GetMaskBitmap(),
2109 MAKEROP4(dwRop
, DSTCOPY
)
2116 // Blit bitmap with mask
2119 HBITMAP buffer_bmap
;
2121 #if wxUSE_DC_CACHEING
2122 // create a temp buffer bitmap and DCs to access it and the mask
2123 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2124 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2126 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2127 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2129 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2132 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2133 #else // !wxUSE_DC_CACHEING
2134 // create a temp buffer bitmap and DCs to access it and the mask
2135 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2136 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2137 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2138 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2139 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2140 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2142 // copy dest to buffer
2143 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2144 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2146 wxLogLastError(wxT("BitBlt"));
2149 // copy src to buffer using selected raster op
2150 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2151 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2153 wxLogLastError(wxT("BitBlt"));
2156 // set masked area in buffer to BLACK (pixel value 0)
2157 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2158 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2159 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2160 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2162 wxLogLastError(wxT("BitBlt"));
2165 // set unmasked area in dest to BLACK
2166 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2167 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2168 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2169 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2171 wxLogLastError(wxT("BitBlt"));
2173 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2174 ::SetTextColor(GetHdc(), prevCol
);
2176 // OR buffer to dest
2177 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2178 (int)width
, (int)height
,
2179 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2182 wxLogLastError(wxT("BitBlt"));
2185 // tidy up temporary DCs and bitmap
2186 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2187 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2189 #if !wxUSE_DC_CACHEING
2191 ::DeleteDC(dc_mask
);
2192 ::DeleteDC(dc_buffer
);
2193 ::DeleteObject(buffer_bmap
);
2198 else // no mask, just BitBlt() it
2200 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2201 // use StretchBlt() if available and finally fall back to BitBlt()
2203 // FIXME: use appropriate WinCE functions
2205 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2206 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2211 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2213 &ds
) == sizeof(ds
) )
2215 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2217 // Figure out what co-ordinate system we're supposed to specify
2219 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2223 ysrc
= hDIB
- (ysrc
+ height
);
2226 if ( ::StretchDIBits(GetHdc(),
2232 (LPBITMAPINFO
)&ds
.dsBmih
,
2235 ) == (int)GDI_ERROR
)
2237 // On Win9x this API fails most (all?) of the time, so
2238 // logging it becomes quite distracting. Since it falls
2239 // back to the code below this is not really serious, so
2241 //wxLogLastError(wxT("StretchDIBits"));
2250 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2255 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2261 xdest
, ydest
, width
, height
,
2263 xsrc
, ysrc
, width
, height
,
2267 wxLogLastError(_T("StretchBlt"));
2281 (int)width
, (int)height
,
2287 wxLogLastError(_T("BitBlt"));
2296 ::SetTextColor(GetHdc(), old_textground
);
2297 ::SetBkColor(GetHdc(), old_background
);
2302 void wxDC::GetDeviceSize(int *width
, int *height
) const
2304 WXMICROWIN_CHECK_HDC
2307 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2309 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2312 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2314 WXMICROWIN_CHECK_HDC
2316 // if we implement it in terms of DoGetSize() instead of directly using the
2317 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2318 // will also work for wxWindowDC and wxClientDC even though their size is
2319 // not the same as the total size of the screen
2320 int wPixels
, hPixels
;
2321 DoGetSize(&wPixels
, &hPixels
);
2325 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2327 wxCHECK_RET( wTotal
, _T("0 width device?") );
2329 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2334 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2336 wxCHECK_RET( hTotal
, _T("0 height device?") );
2338 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2342 wxSize
wxDC::GetPPI() const
2344 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2346 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2347 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2349 return wxSize(x
, y
);
2352 // For use by wxWidgets only, unless custom units are required.
2353 void wxDC::SetLogicalScale(double x
, double y
)
2355 WXMICROWIN_CHECK_HDC
2357 m_logicalScaleX
= x
;
2358 m_logicalScaleY
= y
;
2361 // ----------------------------------------------------------------------------
2363 // ----------------------------------------------------------------------------
2365 #if wxUSE_DC_CACHEING
2368 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2369 * improve it in due course, either using arrays, or simply storing pointers to one
2370 * entry for the bitmap, and two for the DCs. -- JACS
2373 wxList
wxDC::sm_bitmapCache
;
2374 wxList
wxDC::sm_dcCache
;
2376 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2385 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2394 wxDCCacheEntry::~wxDCCacheEntry()
2397 ::DeleteObject((HBITMAP
) m_bitmap
);
2399 ::DeleteDC((HDC
) m_dc
);
2402 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2404 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2405 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2408 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2410 if (entry
->m_depth
== depth
)
2412 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2414 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2415 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2416 if ( !entry
->m_bitmap
)
2418 wxLogLastError(wxT("CreateCompatibleBitmap"));
2420 entry
->m_width
= w
; entry
->m_height
= h
;
2426 node
= node
->GetNext();
2428 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2431 wxLogLastError(wxT("CreateCompatibleBitmap"));
2433 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2434 AddToBitmapCache(entry
);
2438 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2440 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2441 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2444 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2446 // Don't return the same one as we already have
2447 if (!notThis
|| (notThis
!= entry
))
2449 if (entry
->m_depth
== depth
)
2455 node
= node
->GetNext();
2457 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2460 wxLogLastError(wxT("CreateCompatibleDC"));
2462 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2463 AddToDCCache(entry
);
2467 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2469 sm_bitmapCache
.Append(entry
);
2472 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2474 sm_dcCache
.Append(entry
);
2477 void wxDC::ClearCache()
2479 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2480 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2483 // Clean up cache at app exit
2484 class wxDCModule
: public wxModule
2487 virtual bool OnInit() { return true; }
2488 virtual void OnExit() { wxDC::ClearCache(); }
2491 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2494 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2496 #endif // wxUSE_DC_CACHEING
2498 // ----------------------------------------------------------------------------
2499 // alpha channel support
2500 // ----------------------------------------------------------------------------
2502 static bool AlphaBlt(HDC hdcDst
,
2503 int x
, int y
, int width
, int height
,
2504 int srcX
, int srcY
, HDC hdcSrc
,
2505 const wxBitmap
& bmp
)
2507 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2508 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2510 // do we have AlphaBlend() and company in the headers?
2511 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2512 // yes, now try to see if we have it during run-time
2513 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2514 HDC
,int,int,int,int,
2517 static AlphaBlend_t pfnAlphaBlend
= wxMSIMG32_SYMBOL(AlphaBlend
);
2518 if ( pfnAlphaBlend
)
2521 bf
.BlendOp
= AC_SRC_OVER
;
2523 bf
.SourceConstantAlpha
= 0xff;
2524 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2526 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2527 hdcSrc
, srcX
, srcY
, width
, height
,
2530 // skip wxAlphaBlend() call below
2534 wxLogLastError(_T("AlphaBlend"));
2537 wxUnusedVar(hdcSrc
);
2538 #endif // defined(AC_SRC_OVER)
2540 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2542 #ifdef wxHAVE_RAW_BITMAP
2543 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2546 #else // !wxHAVE_RAW_BITMAP
2547 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2548 // alpha but at least something will be shown like this)
2551 #endif // wxHAVE_RAW_BITMAP
2555 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2556 #ifdef wxHAVE_RAW_BITMAP
2559 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2561 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2563 // get the destination DC pixels
2564 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2566 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2568 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2570 wxLogLastError(_T("BitBlt"));
2573 // combine them with the source bitmap using alpha
2574 wxAlphaPixelData
dataDst(bmpDst
),
2575 dataSrc((wxBitmap
&)bmpSrc
);
2577 wxCHECK_RET( dataDst
&& dataSrc
,
2578 _T("failed to get raw data in wxAlphaBlend") );
2580 wxAlphaPixelData::Iterator
pDst(dataDst
),
2583 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2585 for ( int y
= 0; y
< h
; y
++ )
2587 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2588 pSrcRowStart
= pSrc
;
2590 for ( int x
= 0; x
< w
; x
++ )
2592 // note that source bitmap uses premultiplied alpha (as required by
2593 // the real AlphaBlend)
2594 const unsigned beta
= 255 - pSrc
.Alpha();
2596 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2597 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2598 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2604 pDst
= pDstRowStart
;
2605 pSrc
= pSrcRowStart
;
2606 pDst
.OffsetY(dataDst
, 1);
2607 pSrc
.OffsetY(dataSrc
, 1);
2610 // and finally blit them back to the destination DC
2611 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2613 wxLogLastError(_T("BitBlt"));
2617 #endif // #ifdef wxHAVE_RAW_BITMAP
2619 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2620 const wxColour
& initialColour
,
2621 const wxColour
& destColour
,
2622 wxDirection nDirection
)
2624 // use native function if we have compile-time support it and can load it
2625 // during run-time (linking to it statically would make the program
2626 // unusable on earlier Windows versions)
2627 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2629 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2630 static GradientFill_t pfnGradientFill
= wxMSIMG32_SYMBOL(GradientFill
);
2632 if ( pfnGradientFill
)
2634 GRADIENT_RECT grect
;
2635 grect
.UpperLeft
= 0;
2636 grect
.LowerRight
= 1;
2638 // invert colours direction if not filling from left-to-right or
2640 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2642 // one vertex for upper left and one for upper-right
2643 TRIVERTEX vertices
[2];
2645 vertices
[0].x
= rect
.GetLeft();
2646 vertices
[0].y
= rect
.GetTop();
2647 vertices
[1].x
= rect
.GetRight();
2648 vertices
[1].y
= rect
.GetBottom();
2650 vertices
[firstVertex
].Red
= initialColour
.Red() << 8;
2651 vertices
[firstVertex
].Green
= initialColour
.Green() << 8;
2652 vertices
[firstVertex
].Blue
= initialColour
.Blue() << 8;
2653 vertices
[firstVertex
].Alpha
= 0;
2654 vertices
[1 - firstVertex
].Red
= destColour
.Red() << 8;
2655 vertices
[1 - firstVertex
].Green
= destColour
.Green() << 8;
2656 vertices
[1 - firstVertex
].Blue
= destColour
.Blue() << 8;
2657 vertices
[1 - firstVertex
].Alpha
= 0;
2659 if (nDirection
== wxWEST
||
2660 nDirection
== wxEAST
)
2661 if ( (*pfnGradientFill
)
2668 nDirection
== wxWEST
|| nDirection
== wxEAST
2669 ? GRADIENT_FILL_RECT_H
2670 : GRADIENT_FILL_RECT_V
2673 // skip call of the base class version below
2677 wxLogLastError(_T("GradientFill"));
2679 #endif // wxUSE_DYNLIB_CLASS
2681 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);