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 // ===========================================================================
201 // ===========================================================================
203 // ----------------------------------------------------------------------------
205 // ----------------------------------------------------------------------------
207 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
209 const wxBrush
& brush
= dc
.GetBrush();
210 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
212 HDC hdc
= GetHdcOf(dc
);
213 m_colFgOld
= ::GetTextColor(hdc
);
214 m_colBgOld
= ::GetBkColor(hdc
);
216 // note that Windows convention is opposite to wxWidgets one, this is
217 // why text colour becomes the background one and vice versa
218 const wxColour
& colFg
= dc
.GetTextForeground();
221 ::SetBkColor(hdc
, colFg
.GetPixel());
224 const wxColour
& colBg
= dc
.GetTextBackground();
227 ::SetTextColor(hdc
, colBg
.GetPixel());
231 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
234 // flag which telsl us to undo changes in the dtor
239 // nothing done, nothing to undo
244 wxColourChanger::~wxColourChanger()
248 // restore the colours we changed
249 HDC hdc
= GetHdcOf(m_dc
);
251 ::SetBkMode(hdc
, TRANSPARENT
);
252 ::SetTextColor(hdc
, m_colFgOld
);
253 ::SetBkColor(hdc
, m_colBgOld
);
257 // ---------------------------------------------------------------------------
259 // ---------------------------------------------------------------------------
261 // Default constructor
272 #endif // wxUSE_PALETTE
282 SelectOldObjects(m_hDC
);
284 // if we own the HDC, we delete it, otherwise we just release it
288 ::DeleteDC(GetHdc());
290 else // we don't own our HDC
294 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
298 // Must have been a wxScreenDC
299 ::ReleaseDC((HWND
) NULL
, GetHdc());
305 // This will select current objects out of the DC,
306 // which is what you have to do before deleting the
308 void wxDC::SelectOldObjects(WXHDC dc
)
314 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
316 if (m_selectedBitmap
.Ok())
318 m_selectedBitmap
.SetSelectedInto(NULL
);
325 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
330 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
335 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
342 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
345 #endif // wxUSE_PALETTE
348 m_brush
= wxNullBrush
;
351 m_palette
= wxNullPalette
;
352 #endif // wxUSE_PALETTE
354 m_backgroundBrush
= wxNullBrush
;
355 m_selectedBitmap
= wxNullBitmap
;
358 // ---------------------------------------------------------------------------
360 // ---------------------------------------------------------------------------
362 void wxDC::UpdateClipBox()
367 ::GetClipBox(GetHdc(), &rect
);
369 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
370 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
371 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
372 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
376 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
378 // check if we should try to retrieve the clipping region possibly not set
379 // by our SetClippingRegion() but preset by Windows:this can only happen
380 // when we're associated with an existing HDC usign SetHDC(), see there
381 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
383 wxDC
*self
= wxConstCast(this, wxDC
);
384 self
->UpdateClipBox();
386 if ( !m_clipX1
&& !m_clipX2
)
387 self
->m_clipping
= false;
390 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
393 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
394 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
396 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
400 // note that we combine the new clipping region with the existing one: this
401 // is compatible with what the other ports do and is the documented
402 // behaviour now (starting with 2.3.3)
403 #if defined(__WXWINCE__)
405 if ( !::GetClipBox(GetHdc(), &rectClip
) )
408 // GetClipBox returns logical coordinates, so transform to device
409 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
410 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
411 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
412 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
414 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
415 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
416 rectClip
.right
, rectClip
.bottom
);
418 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
420 ::SelectClipRgn(GetHdc(), hrgnDest
);
423 ::DeleteObject(hrgnClipOld
);
424 ::DeleteObject(hrgnDest
);
426 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
428 wxLogLastError(_T("ExtSelectClipRgn"));
432 #endif // WinCE/!WinCE
439 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
441 // the region coords are always the device ones, so do the translation
444 // FIXME: possible +/-1 error here, to check!
445 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
447 LogicalToDeviceX(x
+ w
),
448 LogicalToDeviceY(y
+ h
));
451 wxLogLastError(_T("CreateRectRgn"));
455 SetClippingHrgn((WXHRGN
)hrgn
);
457 ::DeleteObject(hrgn
);
461 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
463 SetClippingHrgn(region
.GetHRGN());
466 void wxDC::DestroyClippingRegion()
470 if (m_clipping
&& m_hDC
)
472 // TODO: this should restore the previous clipping region,
473 // so that OnPaint processing works correctly, and the update
474 // clipping region doesn't get destroyed after the first
475 // DestroyClippingRegion.
476 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
477 ::SelectClipRgn(GetHdc(), rgn
);
481 wxDCBase::DestroyClippingRegion();
484 // ---------------------------------------------------------------------------
485 // query capabilities
486 // ---------------------------------------------------------------------------
488 bool wxDC::CanDrawBitmap() const
493 bool wxDC::CanGetTextExtent() const
495 #ifdef __WXMICROWIN__
496 // TODO Extend MicroWindows' GetDeviceCaps function
499 // What sort of display is it?
500 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
502 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
506 int wxDC::GetDepth() const
508 WXMICROWIN_CHECK_HDC_RET(16)
510 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
513 // ---------------------------------------------------------------------------
515 // ---------------------------------------------------------------------------
524 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
528 // No, I think we should simply ignore this if printing on e.g.
530 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
531 if (!m_selectedBitmap
.Ok())
534 rect
.left
= 0; rect
.top
= 0;
535 rect
.right
= m_selectedBitmap
.GetWidth();
536 rect
.bottom
= m_selectedBitmap
.GetHeight();
540 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
543 DWORD colour
= ::GetBkColor(GetHdc());
544 HBRUSH brush
= ::CreateSolidBrush(colour
);
545 ::FillRect(GetHdc(), &rect
, brush
);
546 ::DeleteObject(brush
);
549 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
550 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
552 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
554 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
555 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
556 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
557 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
561 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
562 wxCoord
WXUNUSED_IN_WINCE(y
),
563 const wxColour
& WXUNUSED_IN_WINCE(col
),
564 int WXUNUSED_IN_WINCE(style
))
569 WXMICROWIN_CHECK_HDC_RET(false)
571 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
573 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
574 : FLOODFILLBORDER
) ) ;
577 // quoting from the MSDN docs:
579 // Following are some of the reasons this function might fail:
581 // * The filling could not be completed.
582 // * The specified point has the boundary color specified by the
583 // crColor parameter (if FLOODFILLBORDER was requested).
584 // * The specified point does not have the color specified by
585 // crColor (if FLOODFILLSURFACE was requested)
586 // * The point is outside the clipping region that is, it is not
587 // visible on the device.
589 wxLogLastError(wxT("ExtFloodFill"));
592 CalcBoundingBox(x
, y
);
598 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
600 WXMICROWIN_CHECK_HDC_RET(false)
602 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
604 // get the color of the pixel
605 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
607 wxRGBToColour(*col
, pixelcolor
);
612 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
616 wxCoord x1
= x
-VIEWPORT_EXTENT
;
617 wxCoord y1
= y
-VIEWPORT_EXTENT
;
618 wxCoord x2
= x
+VIEWPORT_EXTENT
;
619 wxCoord y2
= y
+VIEWPORT_EXTENT
;
621 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
622 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
624 CalcBoundingBox(x1
, y1
);
625 CalcBoundingBox(x2
, y2
);
628 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
632 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
634 CalcBoundingBox(x1
, y1
);
635 CalcBoundingBox(x2
, y2
);
638 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
639 // and ending at (x2, y2)
640 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
641 wxCoord x2
, wxCoord y2
,
642 wxCoord xc
, wxCoord yc
)
645 // Slower emulation since WinCE doesn't support Pie and Arc
646 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
647 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
648 if( y1
>yc
) sa
= -sa
; // below center
649 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
650 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
655 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
659 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
660 wxCoord r
= (wxCoord
)radius
;
662 // treat the special case of full circle separately
663 if ( x1
== x2
&& y1
== y2
)
665 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
669 wxCoord xx1
= XLOG2DEV(x1
);
670 wxCoord yy1
= YLOG2DEV(y1
);
671 wxCoord xx2
= XLOG2DEV(x2
);
672 wxCoord yy2
= YLOG2DEV(y2
);
673 wxCoord xxc
= XLOG2DEV(xc
);
674 wxCoord yyc
= YLOG2DEV(yc
);
675 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
677 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
678 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
679 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
680 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
682 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
684 // Have to add 1 to bottom-right corner of rectangle
685 // to make semi-circles look right (crooked line otherwise).
686 // Unfortunately this is not a reliable method, depends
687 // on the size of shape.
688 // TODO: figure out why this happens!
689 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
693 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
696 CalcBoundingBox(xc
- r
, yc
- r
);
697 CalcBoundingBox(xc
+ r
, yc
+ r
);
701 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
702 wxCoord width
, wxCoord height
)
706 wxCoord x2
= x1
+ width
,
709 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
717 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
719 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
721 #else // Symantec-MicroWin
723 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
724 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
725 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
726 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
727 ::SetROP2(GetHdc(), R2_COPYPEN
);
728 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
729 MoveToEx(GetHdc(), x1
, y1
, NULL
);
730 LineTo(GetHdc(), x2
, y2
);
731 MoveToEx(GetHdc(), x2
, y1
, NULL
);
732 LineTo(GetHdc(), x1
, y2
);
733 ::SelectObject(GetHdc(), hPenOld
);
734 ::SelectObject(GetHdc(), hBrushOld
);
735 ::DeleteObject(blackPen
);
736 #endif // Win32/Symantec-MicroWin
738 CalcBoundingBox(x1
, y1
);
739 CalcBoundingBox(x2
, y2
);
742 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
746 COLORREF color
= 0x00ffffff;
749 color
= m_pen
.GetColour().GetPixel();
752 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
754 CalcBoundingBox(x
, y
);
757 void wxDC::DoDrawPolygon(int n
,
761 int WXUNUSED_IN_WINCE(fillStyle
))
765 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
767 // Do things less efficiently if we have offsets
768 if (xoffset
!= 0 || yoffset
!= 0)
770 POINT
*cpoints
= new POINT
[n
];
772 for (i
= 0; i
< n
; i
++)
774 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
775 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
777 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
780 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
782 (void)Polygon(GetHdc(), cpoints
, n
);
784 SetPolyFillMode(GetHdc(),prev
);
791 for (i
= 0; i
< n
; i
++)
792 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
795 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
797 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
799 SetPolyFillMode(GetHdc(),prev
);
805 wxDC::DoDrawPolyPolygon(int n
,
813 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
817 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
819 for (i
= cnt
= 0; i
< n
; i
++)
822 // Do things less efficiently if we have offsets
823 if (xoffset
!= 0 || yoffset
!= 0)
825 POINT
*cpoints
= new POINT
[cnt
];
826 for (i
= 0; i
< cnt
; i
++)
828 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
829 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
831 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
834 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
836 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
838 SetPolyFillMode(GetHdc(),prev
);
844 for (i
= 0; i
< cnt
; i
++)
845 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
848 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
850 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
852 SetPolyFillMode(GetHdc(),prev
);
859 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
863 // Do things less efficiently if we have offsets
864 if (xoffset
!= 0 || yoffset
!= 0)
866 POINT
*cpoints
= new POINT
[n
];
868 for (i
= 0; i
< n
; i
++)
870 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
871 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
873 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
875 (void)Polyline(GetHdc(), cpoints
, n
);
881 for (i
= 0; i
< n
; i
++)
882 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
884 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
888 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
892 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
894 wxCoord x2
= x
+ width
;
895 wxCoord y2
= y
+ height
;
897 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
900 rect
.left
= XLOG2DEV(x
);
901 rect
.top
= YLOG2DEV(y
);
902 rect
.right
= XLOG2DEV(x2
);
903 rect
.bottom
= YLOG2DEV(y2
);
904 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
908 // Windows draws the filled rectangles without outline (i.e. drawn with a
909 // transparent pen) one pixel smaller in both directions and we want them
910 // to have the same size regardless of which pen is used - adjust
912 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
913 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
915 // Apparently not needed for WinCE (see e.g. Life! demo)
922 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
926 CalcBoundingBox(x
, y
);
927 CalcBoundingBox(x2
, y2
);
930 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
934 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
936 // Now, a negative radius value is interpreted to mean
937 // 'the proportion of the smallest X or Y dimension'
941 double smallest
= (width
< height
) ? width
: height
;
942 radius
= (- radius
* smallest
);
945 wxCoord x2
= (x
+width
);
946 wxCoord y2
= (y
+height
);
948 // Windows draws the filled rectangles without outline (i.e. drawn with a
949 // transparent pen) one pixel smaller in both directions and we want them
950 // to have the same size regardless of which pen is used - adjust
951 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
957 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
958 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
960 CalcBoundingBox(x
, y
);
961 CalcBoundingBox(x2
, y2
);
964 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
968 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
970 wxCoord x2
= (x
+width
);
971 wxCoord y2
= (y
+height
);
973 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
975 CalcBoundingBox(x
, y
);
976 CalcBoundingBox(x2
, y2
);
980 void wxDC::DoDrawSpline(wxList
*points
)
983 // WinCE does not support ::PolyBezier so use generic version
984 wxDCBase::DoDrawSpline(points
);
986 // quadratic b-spline to cubic bezier spline conversion
988 // quadratic spline with control points P0,P1,P2
989 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
991 // bezier spline with control points B0,B1,B2,B3
992 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
994 // control points of bezier spline calculated from b-spline
996 // B1 = (2*P1 + P0)/3
997 // B2 = (2*P1 + P2)/3
1000 WXMICROWIN_CHECK_HDC
1002 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1004 const size_t n_points
= points
->GetCount();
1005 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1007 const size_t n_bezier_points
= n_points
* 3 + 1;
1008 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1009 size_t bezier_pos
= 0;
1010 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1012 wxList::compatibility_iterator node
= points
->GetFirst();
1013 wxPoint
*p
= (wxPoint
*)node
->GetData();
1014 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1015 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1017 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1020 node
= node
->GetNext();
1021 p
= (wxPoint
*)node
->GetData();
1025 cx1
= ( x1
+ x2
) / 2;
1026 cy1
= ( y1
+ y2
) / 2;
1027 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1028 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1030 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1034 while ((node
= node
->GetNext()) != NULL
)
1036 while ((node
= node
->GetNext()))
1037 #endif // !wxUSE_STL
1039 p
= (wxPoint
*)node
->GetData();
1044 cx4
= (x1
+ x2
) / 2;
1045 cy4
= (y1
+ y2
) / 2;
1046 // B0 is B3 of previous segment
1048 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1049 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1052 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1053 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1056 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1057 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1063 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1065 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1066 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1068 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1071 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1078 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1079 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1082 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1085 WXMICROWIN_CHECK_HDC
1087 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1092 int rx1
= XLOG2DEV(x
+w
/2);
1093 int ry1
= YLOG2DEV(y
+h
/2);
1100 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1101 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1102 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1103 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1105 // draw pie with NULL_PEN first and then outline otherwise a line is
1106 // drawn from the start and end points to the centre
1107 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1110 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1111 rx1
, ry1
, rx2
, ry2
);
1115 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1116 rx1
, ry1
-1, rx2
, ry2
-1);
1119 ::SelectObject(GetHdc(), hpenOld
);
1121 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1122 rx1
, ry1
, rx2
, ry2
);
1124 CalcBoundingBox(x
, y
);
1125 CalcBoundingBox(x2
, y2
);
1129 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1131 WXMICROWIN_CHECK_HDC
1133 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1136 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1138 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1141 CalcBoundingBox(x
, y
);
1142 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1145 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1147 WXMICROWIN_CHECK_HDC
1149 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1151 int width
= bmp
.GetWidth(),
1152 height
= bmp
.GetHeight();
1154 HBITMAP hbmpMask
= 0;
1157 HPALETTE oldPal
= 0;
1158 #endif // wxUSE_PALETTE
1160 if ( bmp
.HasAlpha() )
1163 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1165 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1171 wxMask
*mask
= bmp
.GetMask();
1173 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1177 // don't give assert here because this would break existing
1178 // programs - just silently ignore useMask parameter
1185 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1187 // On some systems, MaskBlt succeeds yet is much much slower
1188 // than the wxWidgets fall-back implementation. So we need
1189 // to be able to switch this on and off at runtime.
1191 #if wxUSE_SYSTEM_OPTIONS
1192 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1196 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1197 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1199 wxPalette
*pal
= bmp
.GetPalette();
1200 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1202 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1203 ::RealizePalette(hdcMem
);
1205 #endif // wxUSE_PALETTE
1207 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1210 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1214 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1215 #endif // wxUSE_PALETTE
1217 ::SelectObject(hdcMem
, hOldBitmap
);
1224 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1227 memDC
.SelectObject(bmp
);
1229 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1231 memDC
.SelectObject(wxNullBitmap
);
1234 else // no mask, just use BitBlt()
1237 HDC memdc
= ::CreateCompatibleDC( cdc
);
1238 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1240 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1242 COLORREF old_textground
= ::GetTextColor(GetHdc());
1243 COLORREF old_background
= ::GetBkColor(GetHdc());
1244 if (m_textForegroundColour
.Ok())
1246 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1248 if (m_textBackgroundColour
.Ok())
1250 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1254 wxPalette
*pal
= bmp
.GetPalette();
1255 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1257 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1258 ::RealizePalette(memdc
);
1260 #endif // wxUSE_PALETTE
1262 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1263 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1267 ::SelectPalette(memdc
, oldPal
, FALSE
);
1268 #endif // wxUSE_PALETTE
1270 ::SelectObject( memdc
, hOldBitmap
);
1271 ::DeleteDC( memdc
);
1273 ::SetTextColor(GetHdc(), old_textground
);
1274 ::SetBkColor(GetHdc(), old_background
);
1278 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1280 WXMICROWIN_CHECK_HDC
1282 DrawAnyText(text
, x
, y
);
1284 // update the bounding box
1285 CalcBoundingBox(x
, y
);
1288 GetTextExtent(text
, &w
, &h
);
1289 CalcBoundingBox(x
+ w
, y
+ h
);
1292 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1294 WXMICROWIN_CHECK_HDC
1296 // prepare for drawing the text
1297 if ( m_textForegroundColour
.Ok() )
1298 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1300 DWORD old_background
= 0;
1301 if ( m_textBackgroundColour
.Ok() )
1303 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1306 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1310 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1311 text
.c_str(), text
.length(), NULL
) == 0 )
1313 wxLogLastError(wxT("TextOut"));
1316 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1317 text
.c_str(), text
.length()) == 0 )
1319 wxLogLastError(wxT("TextOut"));
1323 // restore the old parameters (text foreground colour may be left because
1324 // it never is set to anything else, but background should remain
1325 // transparent even if we just drew an opaque string)
1326 if ( m_textBackgroundColour
.Ok() )
1327 (void)SetBkColor(GetHdc(), old_background
);
1329 SetBkMode(GetHdc(), TRANSPARENT
);
1332 void wxDC::DoDrawRotatedText(const wxString
& text
,
1333 wxCoord x
, wxCoord y
,
1336 WXMICROWIN_CHECK_HDC
1338 // we test that we have some font because otherwise we should still use the
1339 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1340 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1341 // font for drawing rotated fonts unfortunately)
1342 if ( (angle
== 0.0) && m_font
.Ok() )
1344 DoDrawText(text
, x
, y
);
1346 #ifndef __WXMICROWIN__
1349 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1350 // because it's not TrueType and so can't have non zero
1351 // orientation/escapement under Win9x
1352 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1353 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1355 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1357 wxLogLastError(wxT("GetObject(hfont)"));
1360 // GDI wants the angle in tenth of degree
1361 long angle10
= (long)(angle
* 10);
1362 lf
.lfEscapement
= angle10
;
1363 lf
. lfOrientation
= angle10
;
1365 hfont
= ::CreateFontIndirect(&lf
);
1368 wxLogLastError(wxT("CreateFont"));
1372 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1374 DrawAnyText(text
, x
, y
);
1376 (void)::SelectObject(GetHdc(), hfontOld
);
1377 (void)::DeleteObject(hfont
);
1380 // call the bounding box by adding all four vertices of the rectangle
1381 // containing the text to it (simpler and probably not slower than
1382 // determining which of them is really topmost/leftmost/...)
1384 GetTextExtent(text
, &w
, &h
);
1386 double rad
= DegToRad(angle
);
1388 // "upper left" and "upper right"
1389 CalcBoundingBox(x
, y
);
1390 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1392 // "bottom left" and "bottom right"
1393 x
+= (wxCoord
)(h
*sin(rad
));
1394 y
+= (wxCoord
)(h
*cos(rad
));
1395 CalcBoundingBox(x
, y
);
1396 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1401 // ---------------------------------------------------------------------------
1403 // ---------------------------------------------------------------------------
1407 void wxDC::DoSelectPalette(bool realize
)
1409 WXMICROWIN_CHECK_HDC
1411 // Set the old object temporarily, in case the assignment deletes an object
1412 // that's not yet selected out.
1415 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1419 if ( m_palette
.Ok() )
1421 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1422 GetHpaletteOf(m_palette
),
1425 m_oldPalette
= (WXHPALETTE
) oldPal
;
1428 ::RealizePalette(GetHdc());
1432 void wxDC::SetPalette(const wxPalette
& palette
)
1436 m_palette
= palette
;
1437 DoSelectPalette(true);
1441 void wxDC::InitializePalette()
1443 if ( wxDisplayDepth() <= 8 )
1445 // look for any window or parent that has a custom palette. If any has
1446 // one then we need to use it in drawing operations
1447 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1449 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1450 if ( m_hasCustomPalette
)
1452 m_palette
= win
->GetPalette();
1454 // turn on MSW translation for this palette
1460 #endif // wxUSE_PALETTE
1462 // SetFont/Pen/Brush() really ask to be implemented as a single template
1463 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1465 void wxDC::SetFont(const wxFont
& font
)
1467 WXMICROWIN_CHECK_HDC
1469 if ( font
== m_font
)
1474 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1475 if ( hfont
== HGDI_ERROR
)
1477 wxLogLastError(_T("SelectObject(font)"));
1482 m_oldFont
= (WXHPEN
)hfont
;
1487 else // invalid font, reset the current font
1491 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1493 wxLogLastError(_T("SelectObject(old font)"));
1499 m_font
= wxNullFont
;
1503 void wxDC::SetPen(const wxPen
& pen
)
1505 WXMICROWIN_CHECK_HDC
1512 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1513 if ( hpen
== HGDI_ERROR
)
1515 wxLogLastError(_T("SelectObject(pen)"));
1520 m_oldPen
= (WXHPEN
)hpen
;
1525 else // invalid pen, reset the current pen
1529 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1531 wxLogLastError(_T("SelectObject(old pen)"));
1541 void wxDC::SetBrush(const wxBrush
& brush
)
1543 WXMICROWIN_CHECK_HDC
1545 if ( brush
== m_brush
)
1550 // we must make sure the brush is aligned with the logical coordinates
1551 // before selecting it
1552 wxBitmap
*stipple
= brush
.GetStipple();
1553 if ( stipple
&& stipple
->Ok() )
1555 if ( !::SetBrushOrgEx
1558 m_deviceOriginX
% stipple
->GetWidth(),
1559 m_deviceOriginY
% stipple
->GetHeight(),
1560 NULL
// [out] previous brush origin
1563 wxLogLastError(_T("SetBrushOrgEx()"));
1567 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1568 if ( hbrush
== HGDI_ERROR
)
1570 wxLogLastError(_T("SelectObject(brush)"));
1575 m_oldBrush
= (WXHPEN
)hbrush
;
1580 else // invalid brush, reset the current brush
1584 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1586 wxLogLastError(_T("SelectObject(old brush)"));
1592 m_brush
= wxNullBrush
;
1596 void wxDC::SetBackground(const wxBrush
& brush
)
1598 WXMICROWIN_CHECK_HDC
1600 m_backgroundBrush
= brush
;
1602 if ( m_backgroundBrush
.Ok() )
1604 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1608 void wxDC::SetBackgroundMode(int mode
)
1610 WXMICROWIN_CHECK_HDC
1612 m_backgroundMode
= mode
;
1614 // SetBackgroundColour now only refers to text background
1615 // and m_backgroundMode is used there
1618 void wxDC::SetLogicalFunction(int function
)
1620 WXMICROWIN_CHECK_HDC
1622 m_logicalFunction
= function
;
1627 void wxDC::SetRop(WXHDC dc
)
1629 if ( !dc
|| m_logicalFunction
< 0 )
1634 switch (m_logicalFunction
)
1636 case wxCLEAR
: rop
= R2_BLACK
; break;
1637 case wxXOR
: rop
= R2_XORPEN
; break;
1638 case wxINVERT
: rop
= R2_NOT
; break;
1639 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1640 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1641 case wxCOPY
: rop
= R2_COPYPEN
; break;
1642 case wxAND
: rop
= R2_MASKPEN
; break;
1643 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1644 case wxNO_OP
: rop
= R2_NOP
; break;
1645 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1646 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1647 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1648 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1649 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1650 case wxOR
: rop
= R2_MERGEPEN
; break;
1651 case wxSET
: rop
= R2_WHITE
; break;
1654 wxFAIL_MSG( wxT("unsupported logical function") );
1658 SetROP2(GetHdc(), rop
);
1661 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1663 // We might be previewing, so return true to let it continue.
1671 void wxDC::StartPage()
1675 void wxDC::EndPage()
1679 // ---------------------------------------------------------------------------
1681 // ---------------------------------------------------------------------------
1683 wxCoord
wxDC::GetCharHeight() const
1685 WXMICROWIN_CHECK_HDC_RET(0)
1687 TEXTMETRIC lpTextMetric
;
1689 GetTextMetrics(GetHdc(), &lpTextMetric
);
1691 return lpTextMetric
.tmHeight
;
1694 wxCoord
wxDC::GetCharWidth() const
1696 WXMICROWIN_CHECK_HDC_RET(0)
1698 TEXTMETRIC lpTextMetric
;
1700 GetTextMetrics(GetHdc(), &lpTextMetric
);
1702 return lpTextMetric
.tmAveCharWidth
;
1705 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1706 wxCoord
*descent
, wxCoord
*externalLeading
,
1709 #ifdef __WXMICROWIN__
1714 if (descent
) *descent
= 0;
1715 if (externalLeading
) *externalLeading
= 0;
1718 #endif // __WXMICROWIN__
1723 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1725 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1727 else // don't change the font
1735 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1736 GetTextMetrics(GetHdc(), &tm
);
1743 *descent
= tm
.tmDescent
;
1744 if (externalLeading
)
1745 *externalLeading
= tm
.tmExternalLeading
;
1749 ::SelectObject(GetHdc(), hfontOld
);
1754 // Each element of the array will be the width of the string up to and
1755 // including the coresoponding character in text.
1757 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1759 static int maxLenText
= -1;
1760 static int maxWidth
= -1;
1763 int stlen
= text
.length();
1765 if (maxLenText
== -1)
1767 // Win9x and WinNT+ have different limits
1768 int version
= wxGetOsVersion();
1769 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1770 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1774 widths
.Add(0, stlen
); // fill the array with zeros
1778 if (!::GetTextExtentExPoint(GetHdc(),
1779 text
.c_str(), // string to check
1780 wxMin(stlen
, maxLenText
),
1782 &fit
, // [out] count of chars
1784 &widths
[0], // array to fill
1788 wxLogLastError(wxT("GetTextExtentExPoint"));
1798 void wxDC::SetMapMode(int mode
)
1800 WXMICROWIN_CHECK_HDC
1802 m_mappingMode
= mode
;
1804 if ( mode
== wxMM_TEXT
)
1807 m_logicalScaleY
= 1.0;
1809 else // need to do some calculations
1811 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1812 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1813 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1814 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1816 if ( (mm_width
== 0) || (mm_height
== 0) )
1818 // we can't calculate mm2pixels[XY] then!
1822 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1823 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1828 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1829 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1833 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1834 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1838 m_logicalScaleX
= mm2pixelsX
;
1839 m_logicalScaleY
= mm2pixelsY
;
1843 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1844 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1848 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1852 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1853 // cases we could do with MM_TEXT and in the remaining 0.9% with
1854 // MM_ISOTROPIC (TODO!)
1856 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1858 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1859 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1861 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1862 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1864 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1865 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1869 void wxDC::SetUserScale(double x
, double y
)
1871 WXMICROWIN_CHECK_HDC
1873 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1879 this->SetMapMode(m_mappingMode
);
1882 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1883 bool WXUNUSED_IN_WINCE(yBottomUp
))
1885 WXMICROWIN_CHECK_HDC
1888 int signX
= xLeftRight
? 1 : -1,
1889 signY
= yBottomUp
? -1 : 1;
1891 if ( signX
!= m_signX
|| signY
!= m_signY
)
1896 SetMapMode(m_mappingMode
);
1901 void wxDC::SetSystemScale(double x
, double y
)
1903 WXMICROWIN_CHECK_HDC
1905 if ( x
== m_scaleX
&& y
== m_scaleY
)
1912 SetMapMode(m_mappingMode
);
1916 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1918 WXMICROWIN_CHECK_HDC
1920 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1923 m_logicalOriginX
= x
;
1924 m_logicalOriginY
= y
;
1927 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1931 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1933 WXMICROWIN_CHECK_HDC
1935 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1938 m_deviceOriginX
= x
;
1939 m_deviceOriginY
= y
;
1941 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1944 // ---------------------------------------------------------------------------
1945 // coordinates transformations
1946 // ---------------------------------------------------------------------------
1948 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1950 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1953 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1955 // axis orientation is not taken into account for conversion of a distance
1956 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1959 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1961 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1964 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1966 // axis orientation is not taken into account for conversion of a distance
1967 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1970 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1972 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1975 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1977 // axis orientation is not taken into account for conversion of a distance
1978 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1981 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1983 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1986 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1988 // axis orientation is not taken into account for conversion of a distance
1989 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1992 // ---------------------------------------------------------------------------
1994 // ---------------------------------------------------------------------------
1996 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1997 wxCoord width
, wxCoord height
,
1998 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1999 int rop
, bool useMask
,
2000 wxCoord xsrcMask
, wxCoord ysrcMask
)
2002 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2004 WXMICROWIN_CHECK_HDC_RET(false)
2006 // if either the source or destination has alpha channel, we must use
2007 // AlphaBlt() as other function don't handle it correctly
2008 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2009 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2010 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2012 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2013 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2017 wxMask
*mask
= NULL
;
2020 mask
= bmpSrc
.GetMask();
2022 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2024 // don't give assert here because this would break existing
2025 // programs - just silently ignore useMask parameter
2030 if (xsrcMask
== -1 && ysrcMask
== -1)
2032 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2035 COLORREF old_textground
= ::GetTextColor(GetHdc());
2036 COLORREF old_background
= ::GetBkColor(GetHdc());
2037 if (m_textForegroundColour
.Ok())
2039 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2041 if (m_textBackgroundColour
.Ok())
2043 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2049 case wxXOR
: dwRop
= SRCINVERT
; break;
2050 case wxINVERT
: dwRop
= DSTINVERT
; break;
2051 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2052 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2053 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2054 case wxSET
: dwRop
= WHITENESS
; break;
2055 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2056 case wxAND
: dwRop
= SRCAND
; break;
2057 case wxOR
: dwRop
= SRCPAINT
; break;
2058 case wxEQUIV
: dwRop
= 0x00990066; break;
2059 case wxNAND
: dwRop
= 0x007700E6; break;
2060 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2061 case wxCOPY
: dwRop
= SRCCOPY
; break;
2062 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2063 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2064 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2066 wxFAIL_MSG( wxT("unsupported logical function") );
2070 bool success
= false;
2075 // we want the part of the image corresponding to the mask to be
2076 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2077 // meaning of fg and bg is inverted which corresponds to wxWin notion
2078 // of the mask which is also contrary to the Windows one)
2080 // On some systems, MaskBlt succeeds yet is much much slower
2081 // than the wxWidgets fall-back implementation. So we need
2082 // to be able to switch this on and off at runtime.
2083 #if wxUSE_SYSTEM_OPTIONS
2084 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2090 xdest
, ydest
, width
, height
,
2093 (HBITMAP
)mask
->GetMaskBitmap(),
2095 MAKEROP4(dwRop
, DSTCOPY
)
2102 // Blit bitmap with mask
2105 HBITMAP buffer_bmap
;
2107 #if wxUSE_DC_CACHEING
2108 // create a temp buffer bitmap and DCs to access it and the mask
2109 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2110 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2112 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2113 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2115 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2118 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2119 #else // !wxUSE_DC_CACHEING
2120 // create a temp buffer bitmap and DCs to access it and the mask
2121 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2122 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2123 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2124 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2125 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2126 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2128 // copy dest to buffer
2129 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2130 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2132 wxLogLastError(wxT("BitBlt"));
2135 // copy src to buffer using selected raster op
2136 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2137 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2139 wxLogLastError(wxT("BitBlt"));
2142 // set masked area in buffer to BLACK (pixel value 0)
2143 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2144 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2145 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2146 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2148 wxLogLastError(wxT("BitBlt"));
2151 // set unmasked area in dest to BLACK
2152 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2153 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2154 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2155 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2157 wxLogLastError(wxT("BitBlt"));
2159 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2160 ::SetTextColor(GetHdc(), prevCol
);
2162 // OR buffer to dest
2163 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2164 (int)width
, (int)height
,
2165 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2168 wxLogLastError(wxT("BitBlt"));
2171 // tidy up temporary DCs and bitmap
2172 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2173 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2175 #if !wxUSE_DC_CACHEING
2177 ::DeleteDC(dc_mask
);
2178 ::DeleteDC(dc_buffer
);
2179 ::DeleteObject(buffer_bmap
);
2184 else // no mask, just BitBlt() it
2186 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2187 // use StretchBlt() if available and finally fall back to BitBlt()
2189 // FIXME: use appropriate WinCE functions
2191 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2192 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2197 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2199 &ds
) == sizeof(ds
) )
2201 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2203 // Figure out what co-ordinate system we're supposed to specify
2205 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2209 ysrc
= hDIB
- (ysrc
+ height
);
2212 if ( ::StretchDIBits(GetHdc(),
2218 (LPBITMAPINFO
)&ds
.dsBmih
,
2221 ) == (int)GDI_ERROR
)
2223 // On Win9x this API fails most (all?) of the time, so
2224 // logging it becomes quite distracting. Since it falls
2225 // back to the code below this is not really serious, so
2227 //wxLogLastError(wxT("StretchDIBits"));
2236 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2241 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2247 xdest
, ydest
, width
, height
,
2249 xsrc
, ysrc
, width
, height
,
2253 wxLogLastError(_T("StretchBlt"));
2267 (int)width
, (int)height
,
2273 wxLogLastError(_T("BitBlt"));
2282 ::SetTextColor(GetHdc(), old_textground
);
2283 ::SetBkColor(GetHdc(), old_background
);
2288 void wxDC::DoGetSize(int *w
, int *h
) const
2290 WXMICROWIN_CHECK_HDC
2292 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2293 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2296 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2298 WXMICROWIN_CHECK_HDC
2300 // if we implement it in terms of DoGetSize() instead of directly using the
2301 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2302 // will also work for wxWindowDC and wxClientDC even though their size is
2303 // not the same as the total size of the screen
2304 int wPixels
, hPixels
;
2305 DoGetSize(&wPixels
, &hPixels
);
2309 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2311 wxCHECK_RET( wTotal
, _T("0 width device?") );
2313 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2318 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2320 wxCHECK_RET( hTotal
, _T("0 height device?") );
2322 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2326 wxSize
wxDC::GetPPI() const
2328 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2330 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2331 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2333 return wxSize(x
, y
);
2336 // For use by wxWidgets only, unless custom units are required.
2337 void wxDC::SetLogicalScale(double x
, double y
)
2339 WXMICROWIN_CHECK_HDC
2341 m_logicalScaleX
= x
;
2342 m_logicalScaleY
= y
;
2345 // ----------------------------------------------------------------------------
2347 // ----------------------------------------------------------------------------
2349 #if wxUSE_DC_CACHEING
2352 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2353 * improve it in due course, either using arrays, or simply storing pointers to one
2354 * entry for the bitmap, and two for the DCs. -- JACS
2357 wxList
wxDC::sm_bitmapCache
;
2358 wxList
wxDC::sm_dcCache
;
2360 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2369 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2378 wxDCCacheEntry::~wxDCCacheEntry()
2381 ::DeleteObject((HBITMAP
) m_bitmap
);
2383 ::DeleteDC((HDC
) m_dc
);
2386 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2388 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2389 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2392 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2394 if (entry
->m_depth
== depth
)
2396 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2398 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2399 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2400 if ( !entry
->m_bitmap
)
2402 wxLogLastError(wxT("CreateCompatibleBitmap"));
2404 entry
->m_width
= w
; entry
->m_height
= h
;
2410 node
= node
->GetNext();
2412 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2415 wxLogLastError(wxT("CreateCompatibleBitmap"));
2417 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2418 AddToBitmapCache(entry
);
2422 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2424 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2425 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2428 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2430 // Don't return the same one as we already have
2431 if (!notThis
|| (notThis
!= entry
))
2433 if (entry
->m_depth
== depth
)
2439 node
= node
->GetNext();
2441 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2444 wxLogLastError(wxT("CreateCompatibleDC"));
2446 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2447 AddToDCCache(entry
);
2451 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2453 sm_bitmapCache
.Append(entry
);
2456 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2458 sm_dcCache
.Append(entry
);
2461 void wxDC::ClearCache()
2463 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2464 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2467 // Clean up cache at app exit
2468 class wxDCModule
: public wxModule
2471 virtual bool OnInit() { return true; }
2472 virtual void OnExit() { wxDC::ClearCache(); }
2475 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2478 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2480 #endif // wxUSE_DC_CACHEING
2482 // ----------------------------------------------------------------------------
2483 // alpha channel support
2484 // ----------------------------------------------------------------------------
2486 static bool AlphaBlt(HDC hdcDst
,
2487 int x
, int y
, int width
, int height
,
2488 int srcX
, int srcY
, HDC hdcSrc
,
2489 const wxBitmap
& bmp
)
2491 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2492 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2494 // do we have AlphaBlend() and company in the headers?
2495 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2496 // yes, now try to see if we have it during run-time
2497 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2498 HDC
,int,int,int,int,
2501 // bitmaps can be drawn only from GUI thread so there is no need to
2502 // protect this static variable from multiple threads
2503 static bool s_triedToLoad
= false;
2504 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2505 if ( !s_triedToLoad
)
2507 s_triedToLoad
= true;
2509 // don't give errors about the DLL being unavailable, we're
2510 // prepared to handle this
2513 wxDynamicLibrary
dll(_T("msimg32.dll"));
2514 if ( dll
.IsLoaded() )
2516 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2517 if ( pfnAlphaBlend
)
2519 // we must keep the DLL loaded if we want to be able to
2520 // call AlphaBlend() so just never unload it at all, not a
2527 if ( pfnAlphaBlend
)
2530 bf
.BlendOp
= AC_SRC_OVER
;
2532 bf
.SourceConstantAlpha
= 0xff;
2533 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2535 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2536 hdcSrc
, srcX
, srcY
, width
, height
,
2539 // skip wxAlphaBlend() call below
2543 wxLogLastError(_T("AlphaBlend"));
2546 wxUnusedVar(hdcSrc
);
2547 #endif // defined(AC_SRC_OVER)
2549 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2551 #ifdef wxHAVE_RAW_BITMAP
2552 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2555 #else // !wxHAVE_RAW_BITMAP
2556 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2557 // alpha but at least something will be shown like this)
2560 #endif // wxHAVE_RAW_BITMAP
2564 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2565 #ifdef wxHAVE_RAW_BITMAP
2568 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2570 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2572 // get the destination DC pixels
2573 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2575 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2577 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2579 wxLogLastError(_T("BitBlt"));
2582 // combine them with the source bitmap using alpha
2583 wxAlphaPixelData
dataDst(bmpDst
),
2584 dataSrc((wxBitmap
&)bmpSrc
);
2586 wxCHECK_RET( dataDst
&& dataSrc
,
2587 _T("failed to get raw data in wxAlphaBlend") );
2589 wxAlphaPixelData::Iterator
pDst(dataDst
),
2592 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2594 for ( int y
= 0; y
< h
; y
++ )
2596 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2597 pSrcRowStart
= pSrc
;
2599 for ( int x
= 0; x
< w
; x
++ )
2601 // note that source bitmap uses premultiplied alpha (as required by
2602 // the real AlphaBlend)
2603 const unsigned beta
= 255 - pSrc
.Alpha();
2605 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2606 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2607 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2613 pDst
= pDstRowStart
;
2614 pSrc
= pSrcRowStart
;
2615 pDst
.OffsetY(dataDst
, 1);
2616 pSrc
.OffsetY(dataSrc
, 1);
2619 // and finally blit them back to the destination DC
2620 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2622 wxLogLastError(_T("BitBlt"));
2626 #endif // #ifdef wxHAVE_RAW_BITMAP