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
)
729 wxCoord x2
= x1
+ width
,
732 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
740 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
742 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
744 #else // Symantec-MicroWin
746 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
747 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
748 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
749 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
750 ::SetROP2(GetHdc(), R2_COPYPEN
);
751 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
752 MoveToEx(GetHdc(), x1
, y1
, NULL
);
753 LineTo(GetHdc(), x2
, y2
);
754 MoveToEx(GetHdc(), x2
, y1
, NULL
);
755 LineTo(GetHdc(), x1
, y2
);
756 ::SelectObject(GetHdc(), hPenOld
);
757 ::SelectObject(GetHdc(), hBrushOld
);
758 ::DeleteObject(blackPen
);
759 #endif // Win32/Symantec-MicroWin
761 CalcBoundingBox(x1
, y1
);
762 CalcBoundingBox(x2
, y2
);
765 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
769 COLORREF color
= 0x00ffffff;
772 color
= m_pen
.GetColour().GetPixel();
775 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
777 CalcBoundingBox(x
, y
);
780 void wxDC::DoDrawPolygon(int n
,
784 int WXUNUSED_IN_WINCE(fillStyle
))
788 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
790 // Do things less efficiently if we have offsets
791 if (xoffset
!= 0 || yoffset
!= 0)
793 POINT
*cpoints
= new POINT
[n
];
795 for (i
= 0; i
< n
; i
++)
797 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
798 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
800 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
803 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
805 (void)Polygon(GetHdc(), cpoints
, n
);
807 SetPolyFillMode(GetHdc(),prev
);
814 for (i
= 0; i
< n
; i
++)
815 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
818 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
820 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
822 SetPolyFillMode(GetHdc(),prev
);
828 wxDC::DoDrawPolyPolygon(int n
,
836 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
840 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
842 for (i
= cnt
= 0; i
< n
; i
++)
845 // Do things less efficiently if we have offsets
846 if (xoffset
!= 0 || yoffset
!= 0)
848 POINT
*cpoints
= new POINT
[cnt
];
849 for (i
= 0; i
< cnt
; i
++)
851 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
852 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
854 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
857 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
859 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
861 SetPolyFillMode(GetHdc(),prev
);
867 for (i
= 0; i
< cnt
; i
++)
868 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
871 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
873 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
875 SetPolyFillMode(GetHdc(),prev
);
882 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
886 // Do things less efficiently if we have offsets
887 if (xoffset
!= 0 || yoffset
!= 0)
889 POINT
*cpoints
= new POINT
[n
];
891 for (i
= 0; i
< n
; i
++)
893 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
894 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
896 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
898 (void)Polyline(GetHdc(), cpoints
, n
);
904 for (i
= 0; i
< n
; i
++)
905 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
907 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
911 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
915 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
917 wxCoord x2
= x
+ width
;
918 wxCoord y2
= y
+ height
;
920 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
923 rect
.left
= XLOG2DEV(x
);
924 rect
.top
= YLOG2DEV(y
);
925 rect
.right
= XLOG2DEV(x2
);
926 rect
.bottom
= YLOG2DEV(y2
);
927 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
931 // Windows draws the filled rectangles without outline (i.e. drawn with a
932 // transparent pen) one pixel smaller in both directions and we want them
933 // to have the same size regardless of which pen is used - adjust
935 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
936 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
938 // Apparently not needed for WinCE (see e.g. Life! demo)
945 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
949 CalcBoundingBox(x
, y
);
950 CalcBoundingBox(x2
, y2
);
953 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
957 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
959 // Now, a negative radius value is interpreted to mean
960 // 'the proportion of the smallest X or Y dimension'
964 double smallest
= (width
< height
) ? width
: height
;
965 radius
= (- radius
* smallest
);
968 wxCoord x2
= (x
+width
);
969 wxCoord y2
= (y
+height
);
971 // Windows draws the filled rectangles without outline (i.e. drawn with a
972 // transparent pen) one pixel smaller in both directions and we want them
973 // to have the same size regardless of which pen is used - adjust
974 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
980 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
981 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
983 CalcBoundingBox(x
, y
);
984 CalcBoundingBox(x2
, y2
);
987 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
991 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
993 wxCoord x2
= (x
+width
);
994 wxCoord y2
= (y
+height
);
996 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
998 CalcBoundingBox(x
, y
);
999 CalcBoundingBox(x2
, y2
);
1003 void wxDC::DoDrawSpline(wxList
*points
)
1006 // WinCE does not support ::PolyBezier so use generic version
1007 wxDCBase::DoDrawSpline(points
);
1009 // quadratic b-spline to cubic bezier spline conversion
1011 // quadratic spline with control points P0,P1,P2
1012 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1014 // bezier spline with control points B0,B1,B2,B3
1015 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1017 // control points of bezier spline calculated from b-spline
1019 // B1 = (2*P1 + P0)/3
1020 // B2 = (2*P1 + P2)/3
1023 WXMICROWIN_CHECK_HDC
1025 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1027 const size_t n_points
= points
->GetCount();
1028 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1030 const size_t n_bezier_points
= n_points
* 3 + 1;
1031 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1032 size_t bezier_pos
= 0;
1033 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1035 wxList::compatibility_iterator node
= points
->GetFirst();
1036 wxPoint
*p
= (wxPoint
*)node
->GetData();
1037 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1038 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1040 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1043 node
= node
->GetNext();
1044 p
= (wxPoint
*)node
->GetData();
1048 cx1
= ( x1
+ x2
) / 2;
1049 cy1
= ( y1
+ y2
) / 2;
1050 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1051 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1053 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1057 while ((node
= node
->GetNext()) != NULL
)
1059 while ((node
= node
->GetNext()))
1060 #endif // !wxUSE_STL
1062 p
= (wxPoint
*)node
->GetData();
1067 cx4
= (x1
+ x2
) / 2;
1068 cy4
= (y1
+ y2
) / 2;
1069 // B0 is B3 of previous segment
1071 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1072 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1075 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1076 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1079 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1080 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1086 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1088 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1089 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1091 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1094 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1101 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1102 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1105 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1108 WXMICROWIN_CHECK_HDC
1110 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1115 int rx1
= XLOG2DEV(x
+w
/2);
1116 int ry1
= YLOG2DEV(y
+h
/2);
1123 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1124 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1125 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1126 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1128 // draw pie with NULL_PEN first and then outline otherwise a line is
1129 // drawn from the start and end points to the centre
1130 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1133 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1134 rx1
, ry1
, rx2
, ry2
);
1138 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1139 rx1
, ry1
-1, rx2
, ry2
-1);
1142 ::SelectObject(GetHdc(), hpenOld
);
1144 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1145 rx1
, ry1
, rx2
, ry2
);
1147 CalcBoundingBox(x
, y
);
1148 CalcBoundingBox(x2
, y2
);
1152 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1154 WXMICROWIN_CHECK_HDC
1156 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1159 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1161 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1164 CalcBoundingBox(x
, y
);
1165 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1168 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1170 WXMICROWIN_CHECK_HDC
1172 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1174 int width
= bmp
.GetWidth(),
1175 height
= bmp
.GetHeight();
1177 HBITMAP hbmpMask
= 0;
1180 HPALETTE oldPal
= 0;
1181 #endif // wxUSE_PALETTE
1183 if ( bmp
.HasAlpha() )
1186 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1188 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1194 wxMask
*mask
= bmp
.GetMask();
1196 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1200 // don't give assert here because this would break existing
1201 // programs - just silently ignore useMask parameter
1208 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1210 // On some systems, MaskBlt succeeds yet is much much slower
1211 // than the wxWidgets fall-back implementation. So we need
1212 // to be able to switch this on and off at runtime.
1214 #if wxUSE_SYSTEM_OPTIONS
1215 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1219 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1220 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1222 wxPalette
*pal
= bmp
.GetPalette();
1223 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1225 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1226 ::RealizePalette(hdcMem
);
1228 #endif // wxUSE_PALETTE
1230 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1233 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1237 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1238 #endif // wxUSE_PALETTE
1240 ::SelectObject(hdcMem
, hOldBitmap
);
1247 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1250 memDC
.SelectObject(bmp
);
1252 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1254 memDC
.SelectObject(wxNullBitmap
);
1257 else // no mask, just use BitBlt()
1260 HDC memdc
= ::CreateCompatibleDC( cdc
);
1261 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1263 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1265 COLORREF old_textground
= ::GetTextColor(GetHdc());
1266 COLORREF old_background
= ::GetBkColor(GetHdc());
1267 if (m_textForegroundColour
.Ok())
1269 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1271 if (m_textBackgroundColour
.Ok())
1273 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1277 wxPalette
*pal
= bmp
.GetPalette();
1278 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1280 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1281 ::RealizePalette(memdc
);
1283 #endif // wxUSE_PALETTE
1285 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1286 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1290 ::SelectPalette(memdc
, oldPal
, FALSE
);
1291 #endif // wxUSE_PALETTE
1293 ::SelectObject( memdc
, hOldBitmap
);
1294 ::DeleteDC( memdc
);
1296 ::SetTextColor(GetHdc(), old_textground
);
1297 ::SetBkColor(GetHdc(), old_background
);
1301 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1303 WXMICROWIN_CHECK_HDC
1305 DrawAnyText(text
, x
, y
);
1307 // update the bounding box
1308 CalcBoundingBox(x
, y
);
1311 GetTextExtent(text
, &w
, &h
);
1312 CalcBoundingBox(x
+ w
, y
+ h
);
1315 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1317 WXMICROWIN_CHECK_HDC
1319 // prepare for drawing the text
1320 if ( m_textForegroundColour
.Ok() )
1321 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1323 DWORD old_background
= 0;
1324 if ( m_textBackgroundColour
.Ok() )
1326 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1329 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1333 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1334 text
.c_str(), text
.length(), NULL
) == 0 )
1336 wxLogLastError(wxT("TextOut"));
1339 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1340 text
.c_str(), text
.length()) == 0 )
1342 wxLogLastError(wxT("TextOut"));
1346 // restore the old parameters (text foreground colour may be left because
1347 // it never is set to anything else, but background should remain
1348 // transparent even if we just drew an opaque string)
1349 if ( m_textBackgroundColour
.Ok() )
1350 (void)SetBkColor(GetHdc(), old_background
);
1352 SetBkMode(GetHdc(), TRANSPARENT
);
1355 void wxDC::DoDrawRotatedText(const wxString
& text
,
1356 wxCoord x
, wxCoord y
,
1359 WXMICROWIN_CHECK_HDC
1361 // we test that we have some font because otherwise we should still use the
1362 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1363 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1364 // font for drawing rotated fonts unfortunately)
1365 if ( (angle
== 0.0) && m_font
.Ok() )
1367 DoDrawText(text
, x
, y
);
1369 #ifndef __WXMICROWIN__
1372 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1373 // because it's not TrueType and so can't have non zero
1374 // orientation/escapement under Win9x
1375 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1376 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1378 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1380 wxLogLastError(wxT("GetObject(hfont)"));
1383 // GDI wants the angle in tenth of degree
1384 long angle10
= (long)(angle
* 10);
1385 lf
.lfEscapement
= angle10
;
1386 lf
. lfOrientation
= angle10
;
1388 hfont
= ::CreateFontIndirect(&lf
);
1391 wxLogLastError(wxT("CreateFont"));
1395 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1397 DrawAnyText(text
, x
, y
);
1399 (void)::SelectObject(GetHdc(), hfontOld
);
1400 (void)::DeleteObject(hfont
);
1403 // call the bounding box by adding all four vertices of the rectangle
1404 // containing the text to it (simpler and probably not slower than
1405 // determining which of them is really topmost/leftmost/...)
1407 GetTextExtent(text
, &w
, &h
);
1409 double rad
= DegToRad(angle
);
1411 // "upper left" and "upper right"
1412 CalcBoundingBox(x
, y
);
1413 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1415 // "bottom left" and "bottom right"
1416 x
+= (wxCoord
)(h
*sin(rad
));
1417 y
+= (wxCoord
)(h
*cos(rad
));
1418 CalcBoundingBox(x
, y
);
1419 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1424 // ---------------------------------------------------------------------------
1426 // ---------------------------------------------------------------------------
1430 void wxDC::DoSelectPalette(bool realize
)
1432 WXMICROWIN_CHECK_HDC
1434 // Set the old object temporarily, in case the assignment deletes an object
1435 // that's not yet selected out.
1438 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1442 if ( m_palette
.Ok() )
1444 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1445 GetHpaletteOf(m_palette
),
1448 m_oldPalette
= (WXHPALETTE
) oldPal
;
1451 ::RealizePalette(GetHdc());
1455 void wxDC::SetPalette(const wxPalette
& palette
)
1459 m_palette
= palette
;
1460 DoSelectPalette(true);
1464 void wxDC::InitializePalette()
1466 if ( wxDisplayDepth() <= 8 )
1468 // look for any window or parent that has a custom palette. If any has
1469 // one then we need to use it in drawing operations
1470 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1472 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1473 if ( m_hasCustomPalette
)
1475 m_palette
= win
->GetPalette();
1477 // turn on MSW translation for this palette
1483 #endif // wxUSE_PALETTE
1485 // SetFont/Pen/Brush() really ask to be implemented as a single template
1486 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1488 void wxDC::SetFont(const wxFont
& font
)
1490 WXMICROWIN_CHECK_HDC
1492 if ( font
== m_font
)
1497 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1498 if ( hfont
== HGDI_ERROR
)
1500 wxLogLastError(_T("SelectObject(font)"));
1505 m_oldFont
= (WXHPEN
)hfont
;
1510 else // invalid font, reset the current font
1514 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1516 wxLogLastError(_T("SelectObject(old font)"));
1522 m_font
= wxNullFont
;
1526 void wxDC::SetPen(const wxPen
& pen
)
1528 WXMICROWIN_CHECK_HDC
1535 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1536 if ( hpen
== HGDI_ERROR
)
1538 wxLogLastError(_T("SelectObject(pen)"));
1543 m_oldPen
= (WXHPEN
)hpen
;
1548 else // invalid pen, reset the current pen
1552 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1554 wxLogLastError(_T("SelectObject(old pen)"));
1564 void wxDC::SetBrush(const wxBrush
& brush
)
1566 WXMICROWIN_CHECK_HDC
1568 if ( brush
== m_brush
)
1573 // we must make sure the brush is aligned with the logical coordinates
1574 // before selecting it
1575 wxBitmap
*stipple
= brush
.GetStipple();
1576 if ( stipple
&& stipple
->Ok() )
1578 if ( !::SetBrushOrgEx
1581 m_deviceOriginX
% stipple
->GetWidth(),
1582 m_deviceOriginY
% stipple
->GetHeight(),
1583 NULL
// [out] previous brush origin
1586 wxLogLastError(_T("SetBrushOrgEx()"));
1590 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1591 if ( hbrush
== HGDI_ERROR
)
1593 wxLogLastError(_T("SelectObject(brush)"));
1598 m_oldBrush
= (WXHPEN
)hbrush
;
1603 else // invalid brush, reset the current brush
1607 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1609 wxLogLastError(_T("SelectObject(old brush)"));
1615 m_brush
= wxNullBrush
;
1619 void wxDC::SetBackground(const wxBrush
& brush
)
1621 WXMICROWIN_CHECK_HDC
1623 m_backgroundBrush
= brush
;
1625 if ( m_backgroundBrush
.Ok() )
1627 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1631 void wxDC::SetBackgroundMode(int mode
)
1633 WXMICROWIN_CHECK_HDC
1635 m_backgroundMode
= mode
;
1637 // SetBackgroundColour now only refers to text background
1638 // and m_backgroundMode is used there
1641 void wxDC::SetLogicalFunction(int function
)
1643 WXMICROWIN_CHECK_HDC
1645 m_logicalFunction
= function
;
1650 void wxDC::SetRop(WXHDC dc
)
1652 if ( !dc
|| m_logicalFunction
< 0 )
1657 switch (m_logicalFunction
)
1659 case wxCLEAR
: rop
= R2_BLACK
; break;
1660 case wxXOR
: rop
= R2_XORPEN
; break;
1661 case wxINVERT
: rop
= R2_NOT
; break;
1662 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1663 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1664 case wxCOPY
: rop
= R2_COPYPEN
; break;
1665 case wxAND
: rop
= R2_MASKPEN
; break;
1666 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1667 case wxNO_OP
: rop
= R2_NOP
; break;
1668 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1669 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1670 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1671 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1672 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1673 case wxOR
: rop
= R2_MERGEPEN
; break;
1674 case wxSET
: rop
= R2_WHITE
; break;
1677 wxFAIL_MSG( wxT("unsupported logical function") );
1681 SetROP2(GetHdc(), rop
);
1684 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1686 // We might be previewing, so return true to let it continue.
1694 void wxDC::StartPage()
1698 void wxDC::EndPage()
1702 // ---------------------------------------------------------------------------
1704 // ---------------------------------------------------------------------------
1706 wxCoord
wxDC::GetCharHeight() const
1708 WXMICROWIN_CHECK_HDC_RET(0)
1710 TEXTMETRIC lpTextMetric
;
1712 GetTextMetrics(GetHdc(), &lpTextMetric
);
1714 return lpTextMetric
.tmHeight
;
1717 wxCoord
wxDC::GetCharWidth() const
1719 WXMICROWIN_CHECK_HDC_RET(0)
1721 TEXTMETRIC lpTextMetric
;
1723 GetTextMetrics(GetHdc(), &lpTextMetric
);
1725 return lpTextMetric
.tmAveCharWidth
;
1728 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1729 wxCoord
*descent
, wxCoord
*externalLeading
,
1732 #ifdef __WXMICROWIN__
1737 if (descent
) *descent
= 0;
1738 if (externalLeading
) *externalLeading
= 0;
1741 #endif // __WXMICROWIN__
1746 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1748 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1750 else // don't change the font
1756 const size_t len
= string
.length();
1757 if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) )
1759 wxLogLastError(_T("GetTextExtentPoint32()"));
1762 // the result computed by GetTextExtentPoint32() may be too small as it
1763 // accounts for under/overhang of the first/last character while we want
1764 // just the bounding rect for this string so adjust the width as needed
1768 const wxChar chFirst
= *string
.begin();
1769 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1771 if ( width
.abcA
< 0 )
1772 sizeRect
.cx
-= width
.abcA
;
1776 const wxChar chLast
= *string
.rbegin();
1777 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1779 //else: we already have the width of the last character
1781 if ( width
.abcC
< 0 )
1782 sizeRect
.cx
-= width
.abcC
;
1784 //else: GetCharABCWidths() failed, not a TrueType font?
1788 ::GetTextMetrics(GetHdc(), &tm
);
1795 *descent
= tm
.tmDescent
;
1796 if (externalLeading
)
1797 *externalLeading
= tm
.tmExternalLeading
;
1801 ::SelectObject(GetHdc(), hfontOld
);
1806 // Each element of the array will be the width of the string up to and
1807 // including the coresoponding character in text.
1809 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1811 static int maxLenText
= -1;
1812 static int maxWidth
= -1;
1815 int stlen
= text
.length();
1817 if (maxLenText
== -1)
1819 // Win9x and WinNT+ have different limits
1820 int version
= wxGetOsVersion();
1821 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1822 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1826 widths
.Add(0, stlen
); // fill the array with zeros
1830 if (!::GetTextExtentExPoint(GetHdc(),
1831 text
.c_str(), // string to check
1832 wxMin(stlen
, maxLenText
),
1834 &fit
, // [out] count of chars
1836 &widths
[0], // array to fill
1840 wxLogLastError(wxT("GetTextExtentExPoint"));
1850 void wxDC::SetMapMode(int mode
)
1852 WXMICROWIN_CHECK_HDC
1854 m_mappingMode
= mode
;
1856 if ( mode
== wxMM_TEXT
)
1859 m_logicalScaleY
= 1.0;
1861 else // need to do some calculations
1863 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1864 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1865 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1866 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1868 if ( (mm_width
== 0) || (mm_height
== 0) )
1870 // we can't calculate mm2pixels[XY] then!
1874 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1875 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1880 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1881 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1885 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1886 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1890 m_logicalScaleX
= mm2pixelsX
;
1891 m_logicalScaleY
= mm2pixelsY
;
1895 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1896 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1900 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1904 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1905 // cases we could do with MM_TEXT and in the remaining 0.9% with
1906 // MM_ISOTROPIC (TODO!)
1908 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1910 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1911 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1913 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1914 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1916 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1917 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1921 void wxDC::SetUserScale(double x
, double y
)
1923 WXMICROWIN_CHECK_HDC
1925 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1931 this->SetMapMode(m_mappingMode
);
1934 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1935 bool WXUNUSED_IN_WINCE(yBottomUp
))
1937 WXMICROWIN_CHECK_HDC
1940 int signX
= xLeftRight
? 1 : -1,
1941 signY
= yBottomUp
? -1 : 1;
1943 if ( signX
!= m_signX
|| signY
!= m_signY
)
1948 SetMapMode(m_mappingMode
);
1953 void wxDC::SetSystemScale(double x
, double y
)
1955 WXMICROWIN_CHECK_HDC
1957 if ( x
== m_scaleX
&& y
== m_scaleY
)
1964 SetMapMode(m_mappingMode
);
1968 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1970 WXMICROWIN_CHECK_HDC
1972 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1975 m_logicalOriginX
= x
;
1976 m_logicalOriginY
= y
;
1979 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1983 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1985 WXMICROWIN_CHECK_HDC
1987 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1990 m_deviceOriginX
= x
;
1991 m_deviceOriginY
= y
;
1993 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1996 // ---------------------------------------------------------------------------
1997 // coordinates transformations
1998 // ---------------------------------------------------------------------------
2000 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
2002 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
2005 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
2007 // axis orientation is not taken into account for conversion of a distance
2008 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
2011 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
2013 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
2016 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
2018 // axis orientation is not taken into account for conversion of a distance
2019 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
2022 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
2024 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
2027 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
2029 // axis orientation is not taken into account for conversion of a distance
2030 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
2033 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
2035 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
2038 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
2040 // axis orientation is not taken into account for conversion of a distance
2041 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
2044 // ---------------------------------------------------------------------------
2046 // ---------------------------------------------------------------------------
2048 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
2049 wxCoord width
, wxCoord height
,
2050 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
2051 int rop
, bool useMask
,
2052 wxCoord xsrcMask
, wxCoord ysrcMask
)
2054 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2056 WXMICROWIN_CHECK_HDC_RET(false)
2058 // if either the source or destination has alpha channel, we must use
2059 // AlphaBlt() as other function don't handle it correctly
2060 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2061 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2062 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2064 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2065 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2069 wxMask
*mask
= NULL
;
2072 mask
= bmpSrc
.GetMask();
2074 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2076 // don't give assert here because this would break existing
2077 // programs - just silently ignore useMask parameter
2082 if (xsrcMask
== -1 && ysrcMask
== -1)
2084 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2087 COLORREF old_textground
= ::GetTextColor(GetHdc());
2088 COLORREF old_background
= ::GetBkColor(GetHdc());
2089 if (m_textForegroundColour
.Ok())
2091 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2093 if (m_textBackgroundColour
.Ok())
2095 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2101 case wxXOR
: dwRop
= SRCINVERT
; break;
2102 case wxINVERT
: dwRop
= DSTINVERT
; break;
2103 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2104 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2105 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2106 case wxSET
: dwRop
= WHITENESS
; break;
2107 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2108 case wxAND
: dwRop
= SRCAND
; break;
2109 case wxOR
: dwRop
= SRCPAINT
; break;
2110 case wxEQUIV
: dwRop
= 0x00990066; break;
2111 case wxNAND
: dwRop
= 0x007700E6; break;
2112 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2113 case wxCOPY
: dwRop
= SRCCOPY
; break;
2114 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2115 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2116 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2118 wxFAIL_MSG( wxT("unsupported logical function") );
2122 bool success
= false;
2127 // we want the part of the image corresponding to the mask to be
2128 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2129 // meaning of fg and bg is inverted which corresponds to wxWin notion
2130 // of the mask which is also contrary to the Windows one)
2132 // On some systems, MaskBlt succeeds yet is much much slower
2133 // than the wxWidgets fall-back implementation. So we need
2134 // to be able to switch this on and off at runtime.
2135 #if wxUSE_SYSTEM_OPTIONS
2136 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2142 xdest
, ydest
, width
, height
,
2145 (HBITMAP
)mask
->GetMaskBitmap(),
2147 MAKEROP4(dwRop
, DSTCOPY
)
2154 // Blit bitmap with mask
2157 HBITMAP buffer_bmap
;
2159 #if wxUSE_DC_CACHEING
2160 // create a temp buffer bitmap and DCs to access it and the mask
2161 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2162 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2164 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2165 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2167 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2170 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2171 #else // !wxUSE_DC_CACHEING
2172 // create a temp buffer bitmap and DCs to access it and the mask
2173 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2174 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2175 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2176 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2177 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2178 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2180 // copy dest to buffer
2181 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2182 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2184 wxLogLastError(wxT("BitBlt"));
2187 // copy src to buffer using selected raster op
2188 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2189 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2191 wxLogLastError(wxT("BitBlt"));
2194 // set masked area in buffer to BLACK (pixel value 0)
2195 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2196 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2197 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2198 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2200 wxLogLastError(wxT("BitBlt"));
2203 // set unmasked area in dest to BLACK
2204 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2205 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2206 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2207 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2209 wxLogLastError(wxT("BitBlt"));
2211 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2212 ::SetTextColor(GetHdc(), prevCol
);
2214 // OR buffer to dest
2215 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2216 (int)width
, (int)height
,
2217 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2220 wxLogLastError(wxT("BitBlt"));
2223 // tidy up temporary DCs and bitmap
2224 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2225 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2227 #if !wxUSE_DC_CACHEING
2229 ::DeleteDC(dc_mask
);
2230 ::DeleteDC(dc_buffer
);
2231 ::DeleteObject(buffer_bmap
);
2236 else // no mask, just BitBlt() it
2238 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2239 // use StretchBlt() if available and finally fall back to BitBlt()
2241 // FIXME: use appropriate WinCE functions
2243 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2244 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2249 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2251 &ds
) == sizeof(ds
) )
2253 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2255 // Figure out what co-ordinate system we're supposed to specify
2257 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2261 ysrc
= hDIB
- (ysrc
+ height
);
2264 if ( ::StretchDIBits(GetHdc(),
2270 (LPBITMAPINFO
)&ds
.dsBmih
,
2273 ) == (int)GDI_ERROR
)
2275 // On Win9x this API fails most (all?) of the time, so
2276 // logging it becomes quite distracting. Since it falls
2277 // back to the code below this is not really serious, so
2279 //wxLogLastError(wxT("StretchDIBits"));
2288 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2293 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2299 xdest
, ydest
, width
, height
,
2301 xsrc
, ysrc
, width
, height
,
2305 wxLogLastError(_T("StretchBlt"));
2319 (int)width
, (int)height
,
2325 wxLogLastError(_T("BitBlt"));
2334 ::SetTextColor(GetHdc(), old_textground
);
2335 ::SetBkColor(GetHdc(), old_background
);
2340 void wxDC::GetDeviceSize(int *width
, int *height
) const
2342 WXMICROWIN_CHECK_HDC
2345 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2347 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2350 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2352 WXMICROWIN_CHECK_HDC
2354 // if we implement it in terms of DoGetSize() instead of directly using the
2355 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2356 // will also work for wxWindowDC and wxClientDC even though their size is
2357 // not the same as the total size of the screen
2358 int wPixels
, hPixels
;
2359 DoGetSize(&wPixels
, &hPixels
);
2363 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2365 wxCHECK_RET( wTotal
, _T("0 width device?") );
2367 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2372 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2374 wxCHECK_RET( hTotal
, _T("0 height device?") );
2376 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2380 wxSize
wxDC::GetPPI() const
2382 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2384 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2385 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2387 return wxSize(x
, y
);
2390 // For use by wxWidgets only, unless custom units are required.
2391 void wxDC::SetLogicalScale(double x
, double y
)
2393 WXMICROWIN_CHECK_HDC
2395 m_logicalScaleX
= x
;
2396 m_logicalScaleY
= y
;
2399 // ----------------------------------------------------------------------------
2401 // ----------------------------------------------------------------------------
2403 #if wxUSE_DC_CACHEING
2406 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2407 * improve it in due course, either using arrays, or simply storing pointers to one
2408 * entry for the bitmap, and two for the DCs. -- JACS
2411 wxList
wxDC::sm_bitmapCache
;
2412 wxList
wxDC::sm_dcCache
;
2414 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2423 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2432 wxDCCacheEntry::~wxDCCacheEntry()
2435 ::DeleteObject((HBITMAP
) m_bitmap
);
2437 ::DeleteDC((HDC
) m_dc
);
2440 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2442 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2443 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2446 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2448 if (entry
->m_depth
== depth
)
2450 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2452 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2453 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2454 if ( !entry
->m_bitmap
)
2456 wxLogLastError(wxT("CreateCompatibleBitmap"));
2458 entry
->m_width
= w
; entry
->m_height
= h
;
2464 node
= node
->GetNext();
2466 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2469 wxLogLastError(wxT("CreateCompatibleBitmap"));
2471 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2472 AddToBitmapCache(entry
);
2476 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2478 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2479 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2482 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2484 // Don't return the same one as we already have
2485 if (!notThis
|| (notThis
!= entry
))
2487 if (entry
->m_depth
== depth
)
2493 node
= node
->GetNext();
2495 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2498 wxLogLastError(wxT("CreateCompatibleDC"));
2500 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2501 AddToDCCache(entry
);
2505 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2507 sm_bitmapCache
.Append(entry
);
2510 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2512 sm_dcCache
.Append(entry
);
2515 void wxDC::ClearCache()
2517 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2518 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2521 // Clean up cache at app exit
2522 class wxDCModule
: public wxModule
2525 virtual bool OnInit() { return true; }
2526 virtual void OnExit() { wxDC::ClearCache(); }
2529 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2532 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2534 #endif // wxUSE_DC_CACHEING
2536 // ----------------------------------------------------------------------------
2537 // alpha channel support
2538 // ----------------------------------------------------------------------------
2540 static bool AlphaBlt(HDC hdcDst
,
2541 int x
, int y
, int width
, int height
,
2542 int srcX
, int srcY
, HDC hdcSrc
,
2543 const wxBitmap
& bmp
)
2545 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2546 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2548 // do we have AlphaBlend() and company in the headers?
2549 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2550 // yes, now try to see if we have it during run-time
2551 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2552 HDC
,int,int,int,int,
2555 static AlphaBlend_t pfnAlphaBlend
= wxMSIMG32_SYMBOL(AlphaBlend
);
2556 if ( pfnAlphaBlend
)
2559 bf
.BlendOp
= AC_SRC_OVER
;
2561 bf
.SourceConstantAlpha
= 0xff;
2562 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2564 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2565 hdcSrc
, srcX
, srcY
, width
, height
,
2568 // skip wxAlphaBlend() call below
2572 wxLogLastError(_T("AlphaBlend"));
2575 wxUnusedVar(hdcSrc
);
2576 #endif // defined(AC_SRC_OVER)
2578 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2580 #ifdef wxHAVE_RAW_BITMAP
2581 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2584 #else // !wxHAVE_RAW_BITMAP
2585 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2586 // alpha but at least something will be shown like this)
2589 #endif // wxHAVE_RAW_BITMAP
2593 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2594 #ifdef wxHAVE_RAW_BITMAP
2597 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2599 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2601 // get the destination DC pixels
2602 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2604 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2606 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2608 wxLogLastError(_T("BitBlt"));
2611 // combine them with the source bitmap using alpha
2612 wxAlphaPixelData
dataDst(bmpDst
),
2613 dataSrc((wxBitmap
&)bmpSrc
);
2615 wxCHECK_RET( dataDst
&& dataSrc
,
2616 _T("failed to get raw data in wxAlphaBlend") );
2618 wxAlphaPixelData::Iterator
pDst(dataDst
),
2621 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2623 for ( int y
= 0; y
< h
; y
++ )
2625 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2626 pSrcRowStart
= pSrc
;
2628 for ( int x
= 0; x
< w
; x
++ )
2630 // note that source bitmap uses premultiplied alpha (as required by
2631 // the real AlphaBlend)
2632 const unsigned beta
= 255 - pSrc
.Alpha();
2634 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2635 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2636 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2642 pDst
= pDstRowStart
;
2643 pSrc
= pSrcRowStart
;
2644 pDst
.OffsetY(dataDst
, 1);
2645 pSrc
.OffsetY(dataSrc
, 1);
2648 // and finally blit them back to the destination DC
2649 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2651 wxLogLastError(_T("BitBlt"));
2655 #endif // #ifdef wxHAVE_RAW_BITMAP
2657 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2658 const wxColour
& initialColour
,
2659 const wxColour
& destColour
,
2660 wxDirection nDirection
)
2662 // use native function if we have compile-time support it and can load it
2663 // during run-time (linking to it statically would make the program
2664 // unusable on earlier Windows versions)
2665 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2667 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2668 static GradientFill_t pfnGradientFill
= wxMSIMG32_SYMBOL(GradientFill
);
2670 if ( pfnGradientFill
)
2672 GRADIENT_RECT grect
;
2673 grect
.UpperLeft
= 0;
2674 grect
.LowerRight
= 1;
2676 // invert colours direction if not filling from left-to-right or
2678 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2680 // one vertex for upper left and one for upper-right
2681 TRIVERTEX vertices
[2];
2683 vertices
[0].x
= rect
.GetLeft();
2684 vertices
[0].y
= rect
.GetTop();
2685 vertices
[1].x
= rect
.GetRight();
2686 vertices
[1].y
= rect
.GetBottom();
2688 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2689 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2690 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2691 vertices
[firstVertex
].Alpha
= 0;
2692 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2693 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2694 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2695 vertices
[1 - firstVertex
].Alpha
= 0;
2697 if ( (*pfnGradientFill
)
2704 nDirection
== wxWEST
|| nDirection
== wxEAST
2705 ? GRADIENT_FILL_RECT_H
2706 : GRADIENT_FILL_RECT_V
2709 // skip call of the base class version below
2713 wxLogLastError(_T("GradientFill"));
2715 #endif // wxUSE_DYNLIB_CLASS
2717 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);