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
134 // our (limited) AlphaBlend() replacement
136 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmp
);
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 // instead of duplicating the same code which sets and then restores text
144 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
145 // encapsulate this in a small helper class
147 // wxColourChanger: changes the text colours in the ctor if required and
148 // restores them in the dtor
149 class wxColourChanger
152 wxColourChanger(wxDC
& dc
);
158 COLORREF m_colFgOld
, m_colBgOld
;
162 DECLARE_NO_COPY_CLASS(wxColourChanger
)
165 // this class saves the old stretch blit mode during its life time
166 class StretchBltModeChanger
169 StretchBltModeChanger(HDC hdc
,
170 int WXUNUSED_IN_WINCE(mode
))
174 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
176 wxLogLastError(_T("SetStretchBltMode"));
180 ~StretchBltModeChanger()
183 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
184 wxLogLastError(_T("SetStretchBltMode"));
193 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
196 // ===========================================================================
198 // ===========================================================================
200 // ----------------------------------------------------------------------------
202 // ----------------------------------------------------------------------------
204 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
206 const wxBrush
& brush
= dc
.GetBrush();
207 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
209 HDC hdc
= GetHdcOf(dc
);
210 m_colFgOld
= ::GetTextColor(hdc
);
211 m_colBgOld
= ::GetBkColor(hdc
);
213 // note that Windows convention is opposite to wxWidgets one, this is
214 // why text colour becomes the background one and vice versa
215 const wxColour
& colFg
= dc
.GetTextForeground();
218 ::SetBkColor(hdc
, colFg
.GetPixel());
221 const wxColour
& colBg
= dc
.GetTextBackground();
224 ::SetTextColor(hdc
, colBg
.GetPixel());
228 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
231 // flag which telsl us to undo changes in the dtor
236 // nothing done, nothing to undo
241 wxColourChanger::~wxColourChanger()
245 // restore the colours we changed
246 HDC hdc
= GetHdcOf(m_dc
);
248 ::SetBkMode(hdc
, TRANSPARENT
);
249 ::SetTextColor(hdc
, m_colFgOld
);
250 ::SetBkColor(hdc
, m_colBgOld
);
254 // ---------------------------------------------------------------------------
256 // ---------------------------------------------------------------------------
258 // Default constructor
269 #endif // wxUSE_PALETTE
279 SelectOldObjects(m_hDC
);
281 // if we own the HDC, we delete it, otherwise we just release it
285 ::DeleteDC(GetHdc());
287 else // we don't own our HDC
291 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
295 // Must have been a wxScreenDC
296 ::ReleaseDC((HWND
) NULL
, GetHdc());
302 // This will select current objects out of the DC,
303 // which is what you have to do before deleting the
305 void wxDC::SelectOldObjects(WXHDC dc
)
311 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
313 if (m_selectedBitmap
.Ok())
315 m_selectedBitmap
.SetSelectedInto(NULL
);
322 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
327 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
332 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
339 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
342 #endif // wxUSE_PALETTE
345 m_brush
= wxNullBrush
;
348 m_palette
= wxNullPalette
;
349 #endif // wxUSE_PALETTE
351 m_backgroundBrush
= wxNullBrush
;
352 m_selectedBitmap
= wxNullBitmap
;
355 // ---------------------------------------------------------------------------
357 // ---------------------------------------------------------------------------
359 void wxDC::UpdateClipBox()
364 ::GetClipBox(GetHdc(), &rect
);
366 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
367 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
368 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
369 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
373 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
375 // check if we should try to retrieve the clipping region possibly not set
376 // by our SetClippingRegion() but preset by Windows:this can only happen
377 // when we're associated with an existing HDC usign SetHDC(), see there
378 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
380 wxDC
*self
= wxConstCast(this, wxDC
);
381 self
->UpdateClipBox();
383 if ( !m_clipX1
&& !m_clipX2
)
384 self
->m_clipping
= false;
387 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
390 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
391 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
393 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
397 // note that we combine the new clipping region with the existing one: this
398 // is compatible with what the other ports do and is the documented
399 // behaviour now (starting with 2.3.3)
400 #if defined(__WXWINCE__)
402 if ( !::GetClipBox(GetHdc(), &rectClip
) )
405 // GetClipBox returns logical coordinates, so transform to device
406 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
407 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
408 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
409 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
411 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
412 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
413 rectClip
.right
, rectClip
.bottom
);
415 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
417 ::SelectClipRgn(GetHdc(), hrgnDest
);
420 ::DeleteObject(hrgnClipOld
);
421 ::DeleteObject(hrgnDest
);
423 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
425 wxLogLastError(_T("ExtSelectClipRgn"));
429 #endif // WinCE/!WinCE
436 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
438 // the region coords are always the device ones, so do the translation
441 // FIXME: possible +/-1 error here, to check!
442 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
444 LogicalToDeviceX(x
+ w
),
445 LogicalToDeviceY(y
+ h
));
448 wxLogLastError(_T("CreateRectRgn"));
452 SetClippingHrgn((WXHRGN
)hrgn
);
454 ::DeleteObject(hrgn
);
458 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
460 SetClippingHrgn(region
.GetHRGN());
463 void wxDC::DestroyClippingRegion()
467 if (m_clipping
&& m_hDC
)
469 // TODO: this should restore the previous clipping region,
470 // so that OnPaint processing works correctly, and the update
471 // clipping region doesn't get destroyed after the first
472 // DestroyClippingRegion.
473 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
474 ::SelectClipRgn(GetHdc(), rgn
);
478 wxDCBase::DestroyClippingRegion();
481 // ---------------------------------------------------------------------------
482 // query capabilities
483 // ---------------------------------------------------------------------------
485 bool wxDC::CanDrawBitmap() const
490 bool wxDC::CanGetTextExtent() const
492 #ifdef __WXMICROWIN__
493 // TODO Extend MicroWindows' GetDeviceCaps function
496 // What sort of display is it?
497 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
499 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
503 int wxDC::GetDepth() const
505 WXMICROWIN_CHECK_HDC_RET(16)
507 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
510 // ---------------------------------------------------------------------------
512 // ---------------------------------------------------------------------------
521 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
525 // No, I think we should simply ignore this if printing on e.g.
527 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
528 if (!m_selectedBitmap
.Ok())
531 rect
.left
= 0; rect
.top
= 0;
532 rect
.right
= m_selectedBitmap
.GetWidth();
533 rect
.bottom
= m_selectedBitmap
.GetHeight();
537 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
540 DWORD colour
= ::GetBkColor(GetHdc());
541 HBRUSH brush
= ::CreateSolidBrush(colour
);
542 ::FillRect(GetHdc(), &rect
, brush
);
543 ::DeleteObject(brush
);
546 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
547 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
549 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
551 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
552 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
553 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
554 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
558 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
559 wxCoord
WXUNUSED_IN_WINCE(y
),
560 const wxColour
& WXUNUSED_IN_WINCE(col
),
561 int WXUNUSED_IN_WINCE(style
))
566 WXMICROWIN_CHECK_HDC_RET(false)
568 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
570 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
571 : FLOODFILLBORDER
) ) ;
574 // quoting from the MSDN docs:
576 // Following are some of the reasons this function might fail:
578 // * The filling could not be completed.
579 // * The specified point has the boundary color specified by the
580 // crColor parameter (if FLOODFILLBORDER was requested).
581 // * The specified point does not have the color specified by
582 // crColor (if FLOODFILLSURFACE was requested)
583 // * The point is outside the clipping region that is, it is not
584 // visible on the device.
586 wxLogLastError(wxT("ExtFloodFill"));
589 CalcBoundingBox(x
, y
);
595 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
597 WXMICROWIN_CHECK_HDC_RET(false)
599 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
601 // get the color of the pixel
602 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
604 wxRGBToColour(*col
, pixelcolor
);
609 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
613 wxCoord x1
= x
-VIEWPORT_EXTENT
;
614 wxCoord y1
= y
-VIEWPORT_EXTENT
;
615 wxCoord x2
= x
+VIEWPORT_EXTENT
;
616 wxCoord y2
= y
+VIEWPORT_EXTENT
;
618 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
619 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
621 CalcBoundingBox(x1
, y1
);
622 CalcBoundingBox(x2
, y2
);
625 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
629 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
631 CalcBoundingBox(x1
, y1
);
632 CalcBoundingBox(x2
, y2
);
635 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
636 // and ending at (x2, y2)
637 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
638 wxCoord x2
, wxCoord y2
,
639 wxCoord xc
, wxCoord yc
)
642 // Slower emulation since WinCE doesn't support Pie and Arc
643 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
644 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
645 if( y1
>yc
) sa
= -sa
; // below center
646 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
647 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
652 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
656 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
657 wxCoord r
= (wxCoord
)radius
;
659 // treat the special case of full circle separately
660 if ( x1
== x2
&& y1
== y2
)
662 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
666 wxCoord xx1
= XLOG2DEV(x1
);
667 wxCoord yy1
= YLOG2DEV(y1
);
668 wxCoord xx2
= XLOG2DEV(x2
);
669 wxCoord yy2
= YLOG2DEV(y2
);
670 wxCoord xxc
= XLOG2DEV(xc
);
671 wxCoord yyc
= YLOG2DEV(yc
);
672 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
674 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
675 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
676 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
677 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
679 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
681 // Have to add 1 to bottom-right corner of rectangle
682 // to make semi-circles look right (crooked line otherwise).
683 // Unfortunately this is not a reliable method, depends
684 // on the size of shape.
685 // TODO: figure out why this happens!
686 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
690 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
693 CalcBoundingBox(xc
- r
, yc
- r
);
694 CalcBoundingBox(xc
+ r
, yc
+ r
);
698 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
699 wxCoord width
, wxCoord height
)
703 wxCoord x2
= x1
+ width
,
706 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
714 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
716 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
718 #else // Symantec-MicroWin
720 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
721 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
722 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
723 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
724 ::SetROP2(GetHdc(), R2_COPYPEN
);
725 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
726 MoveToEx(GetHdc(), x1
, y1
, NULL
);
727 LineTo(GetHdc(), x2
, y2
);
728 MoveToEx(GetHdc(), x2
, y1
, NULL
);
729 LineTo(GetHdc(), x1
, y2
);
730 ::SelectObject(GetHdc(), hPenOld
);
731 ::SelectObject(GetHdc(), hBrushOld
);
732 ::DeleteObject(blackPen
);
733 #endif // Win32/Symantec-MicroWin
735 CalcBoundingBox(x1
, y1
);
736 CalcBoundingBox(x2
, y2
);
739 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
743 COLORREF color
= 0x00ffffff;
746 color
= m_pen
.GetColour().GetPixel();
749 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
751 CalcBoundingBox(x
, y
);
754 void wxDC::DoDrawPolygon(int n
,
758 int WXUNUSED_IN_WINCE(fillStyle
))
762 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
764 // Do things less efficiently if we have offsets
765 if (xoffset
!= 0 || yoffset
!= 0)
767 POINT
*cpoints
= new POINT
[n
];
769 for (i
= 0; i
< n
; i
++)
771 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
772 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
774 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
777 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
779 (void)Polygon(GetHdc(), cpoints
, n
);
781 SetPolyFillMode(GetHdc(),prev
);
788 for (i
= 0; i
< n
; i
++)
789 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
792 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
794 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
796 SetPolyFillMode(GetHdc(),prev
);
802 wxDC::DoDrawPolyPolygon(int n
,
810 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
814 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
816 for (i
= cnt
= 0; i
< n
; i
++)
819 // Do things less efficiently if we have offsets
820 if (xoffset
!= 0 || yoffset
!= 0)
822 POINT
*cpoints
= new POINT
[cnt
];
823 for (i
= 0; i
< cnt
; i
++)
825 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
826 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
828 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
831 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
833 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
835 SetPolyFillMode(GetHdc(),prev
);
841 for (i
= 0; i
< cnt
; i
++)
842 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
845 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
847 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
849 SetPolyFillMode(GetHdc(),prev
);
856 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
860 // Do things less efficiently if we have offsets
861 if (xoffset
!= 0 || yoffset
!= 0)
863 POINT
*cpoints
= new POINT
[n
];
865 for (i
= 0; i
< n
; i
++)
867 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
868 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
870 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
872 (void)Polyline(GetHdc(), cpoints
, n
);
878 for (i
= 0; i
< n
; i
++)
879 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
881 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
885 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
889 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
891 wxCoord x2
= x
+ width
;
892 wxCoord y2
= y
+ height
;
894 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
897 rect
.left
= XLOG2DEV(x
);
898 rect
.top
= YLOG2DEV(y
);
899 rect
.right
= XLOG2DEV(x2
);
900 rect
.bottom
= YLOG2DEV(y2
);
901 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
905 // Windows draws the filled rectangles without outline (i.e. drawn with a
906 // transparent pen) one pixel smaller in both directions and we want them
907 // to have the same size regardless of which pen is used - adjust
909 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
910 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
912 // Apparently not needed for WinCE (see e.g. Life! demo)
919 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
923 CalcBoundingBox(x
, y
);
924 CalcBoundingBox(x2
, y2
);
927 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
931 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
933 // Now, a negative radius value is interpreted to mean
934 // 'the proportion of the smallest X or Y dimension'
938 double smallest
= (width
< height
) ? width
: height
;
939 radius
= (- radius
* smallest
);
942 wxCoord x2
= (x
+width
);
943 wxCoord y2
= (y
+height
);
945 // Windows draws the filled rectangles without outline (i.e. drawn with a
946 // transparent pen) one pixel smaller in both directions and we want them
947 // to have the same size regardless of which pen is used - adjust
948 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
954 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
955 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
957 CalcBoundingBox(x
, y
);
958 CalcBoundingBox(x2
, y2
);
961 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
965 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
967 wxCoord x2
= (x
+width
);
968 wxCoord y2
= (y
+height
);
970 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
972 CalcBoundingBox(x
, y
);
973 CalcBoundingBox(x2
, y2
);
977 void wxDC::DoDrawSpline(wxList
*points
)
980 // WinCE does not support ::PolyBezier so use generic version
981 wxDCBase::DoDrawSpline(points
);
983 // quadratic b-spline to cubic bezier spline conversion
985 // quadratic spline with control points P0,P1,P2
986 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
988 // bezier spline with control points B0,B1,B2,B3
989 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
991 // control points of bezier spline calculated from b-spline
993 // B1 = (2*P1 + P0)/3
994 // B2 = (2*P1 + P2)/3
999 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1001 const size_t n_points
= points
->GetCount();
1002 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1004 const size_t n_bezier_points
= n_points
* 3 + 1;
1005 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1006 size_t bezier_pos
= 0;
1007 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1009 wxList::compatibility_iterator node
= points
->GetFirst();
1010 wxPoint
*p
= (wxPoint
*)node
->GetData();
1011 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1012 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1014 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1017 node
= node
->GetNext();
1018 p
= (wxPoint
*)node
->GetData();
1022 cx1
= ( x1
+ x2
) / 2;
1023 cy1
= ( y1
+ y2
) / 2;
1024 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1025 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1027 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1031 while ((node
= node
->GetNext()) != NULL
)
1033 while ((node
= node
->GetNext()))
1034 #endif // !wxUSE_STL
1036 p
= (wxPoint
*)node
->GetData();
1041 cx4
= (x1
+ x2
) / 2;
1042 cy4
= (y1
+ y2
) / 2;
1043 // B0 is B3 of previous segment
1045 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1046 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1049 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1050 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1053 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1054 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1060 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1062 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1063 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1065 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1068 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1075 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1076 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1079 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1082 WXMICROWIN_CHECK_HDC
1084 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1089 int rx1
= XLOG2DEV(x
+w
/2);
1090 int ry1
= YLOG2DEV(y
+h
/2);
1097 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1098 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1099 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1100 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1102 // draw pie with NULL_PEN first and then outline otherwise a line is
1103 // drawn from the start and end points to the centre
1104 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1107 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1108 rx1
, ry1
, rx2
, ry2
);
1112 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1113 rx1
, ry1
-1, rx2
, ry2
-1);
1116 ::SelectObject(GetHdc(), hpenOld
);
1118 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1119 rx1
, ry1
, rx2
, ry2
);
1121 CalcBoundingBox(x
, y
);
1122 CalcBoundingBox(x2
, y2
);
1126 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1128 WXMICROWIN_CHECK_HDC
1130 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1133 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1135 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1138 CalcBoundingBox(x
, y
);
1139 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1142 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1144 WXMICROWIN_CHECK_HDC
1146 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1148 int width
= bmp
.GetWidth(),
1149 height
= bmp
.GetHeight();
1151 HBITMAP hbmpMask
= 0;
1154 HPALETTE oldPal
= 0;
1155 #endif // wxUSE_PALETTE
1157 if ( bmp
.HasAlpha() )
1160 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1162 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1168 wxMask
*mask
= bmp
.GetMask();
1170 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1174 // don't give assert here because this would break existing
1175 // programs - just silently ignore useMask parameter
1182 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1184 // On some systems, MaskBlt succeeds yet is much much slower
1185 // than the wxWidgets fall-back implementation. So we need
1186 // to be able to switch this on and off at runtime.
1188 #if wxUSE_SYSTEM_OPTIONS
1189 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1193 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1194 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1196 wxPalette
*pal
= bmp
.GetPalette();
1197 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1199 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1200 ::RealizePalette(hdcMem
);
1202 #endif // wxUSE_PALETTE
1204 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1207 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1211 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1212 #endif // wxUSE_PALETTE
1214 ::SelectObject(hdcMem
, hOldBitmap
);
1221 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1224 memDC
.SelectObject(bmp
);
1226 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1228 memDC
.SelectObject(wxNullBitmap
);
1231 else // no mask, just use BitBlt()
1234 HDC memdc
= ::CreateCompatibleDC( cdc
);
1235 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1237 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1239 COLORREF old_textground
= ::GetTextColor(GetHdc());
1240 COLORREF old_background
= ::GetBkColor(GetHdc());
1241 if (m_textForegroundColour
.Ok())
1243 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1245 if (m_textBackgroundColour
.Ok())
1247 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1251 wxPalette
*pal
= bmp
.GetPalette();
1252 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1254 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1255 ::RealizePalette(memdc
);
1257 #endif // wxUSE_PALETTE
1259 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1260 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1264 ::SelectPalette(memdc
, oldPal
, FALSE
);
1265 #endif // wxUSE_PALETTE
1267 ::SelectObject( memdc
, hOldBitmap
);
1268 ::DeleteDC( memdc
);
1270 ::SetTextColor(GetHdc(), old_textground
);
1271 ::SetBkColor(GetHdc(), old_background
);
1275 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1277 WXMICROWIN_CHECK_HDC
1279 DrawAnyText(text
, x
, y
);
1281 // update the bounding box
1282 CalcBoundingBox(x
, y
);
1285 GetTextExtent(text
, &w
, &h
);
1286 CalcBoundingBox(x
+ w
, y
+ h
);
1289 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1291 WXMICROWIN_CHECK_HDC
1293 // prepare for drawing the text
1294 if ( m_textForegroundColour
.Ok() )
1295 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1297 DWORD old_background
= 0;
1298 if ( m_textBackgroundColour
.Ok() )
1300 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1303 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1307 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1308 text
.c_str(), text
.length(), NULL
) == 0 )
1310 wxLogLastError(wxT("TextOut"));
1313 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1314 text
.c_str(), text
.length()) == 0 )
1316 wxLogLastError(wxT("TextOut"));
1320 // restore the old parameters (text foreground colour may be left because
1321 // it never is set to anything else, but background should remain
1322 // transparent even if we just drew an opaque string)
1323 if ( m_textBackgroundColour
.Ok() )
1324 (void)SetBkColor(GetHdc(), old_background
);
1326 SetBkMode(GetHdc(), TRANSPARENT
);
1329 void wxDC::DoDrawRotatedText(const wxString
& text
,
1330 wxCoord x
, wxCoord y
,
1333 WXMICROWIN_CHECK_HDC
1335 // we test that we have some font because otherwise we should still use the
1336 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1337 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1338 // font for drawing rotated fonts unfortunately)
1339 if ( (angle
== 0.0) && m_font
.Ok() )
1341 DoDrawText(text
, x
, y
);
1343 #ifndef __WXMICROWIN__
1346 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1347 // because it's not TrueType and so can't have non zero
1348 // orientation/escapement under Win9x
1349 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1350 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1352 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1354 wxLogLastError(wxT("GetObject(hfont)"));
1357 // GDI wants the angle in tenth of degree
1358 long angle10
= (long)(angle
* 10);
1359 lf
.lfEscapement
= angle10
;
1360 lf
. lfOrientation
= angle10
;
1362 hfont
= ::CreateFontIndirect(&lf
);
1365 wxLogLastError(wxT("CreateFont"));
1369 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1371 DrawAnyText(text
, x
, y
);
1373 (void)::SelectObject(GetHdc(), hfontOld
);
1374 (void)::DeleteObject(hfont
);
1377 // call the bounding box by adding all four vertices of the rectangle
1378 // containing the text to it (simpler and probably not slower than
1379 // determining which of them is really topmost/leftmost/...)
1381 GetTextExtent(text
, &w
, &h
);
1383 double rad
= DegToRad(angle
);
1385 // "upper left" and "upper right"
1386 CalcBoundingBox(x
, y
);
1387 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1389 // "bottom left" and "bottom right"
1390 x
+= (wxCoord
)(h
*sin(rad
));
1391 y
+= (wxCoord
)(h
*cos(rad
));
1392 CalcBoundingBox(x
, y
);
1393 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1398 // ---------------------------------------------------------------------------
1400 // ---------------------------------------------------------------------------
1404 void wxDC::DoSelectPalette(bool realize
)
1406 WXMICROWIN_CHECK_HDC
1408 // Set the old object temporarily, in case the assignment deletes an object
1409 // that's not yet selected out.
1412 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1416 if ( m_palette
.Ok() )
1418 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1419 GetHpaletteOf(m_palette
),
1422 m_oldPalette
= (WXHPALETTE
) oldPal
;
1425 ::RealizePalette(GetHdc());
1429 void wxDC::SetPalette(const wxPalette
& palette
)
1433 m_palette
= palette
;
1434 DoSelectPalette(true);
1438 void wxDC::InitializePalette()
1440 if ( wxDisplayDepth() <= 8 )
1442 // look for any window or parent that has a custom palette. If any has
1443 // one then we need to use it in drawing operations
1444 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1446 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1447 if ( m_hasCustomPalette
)
1449 m_palette
= win
->GetPalette();
1451 // turn on MSW translation for this palette
1457 #endif // wxUSE_PALETTE
1459 // SetFont/Pen/Brush() really ask to be implemented as a single template
1460 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1462 void wxDC::SetFont(const wxFont
& font
)
1464 WXMICROWIN_CHECK_HDC
1466 if ( font
== m_font
)
1471 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1472 if ( hfont
== HGDI_ERROR
)
1474 wxLogLastError(_T("SelectObject(font)"));
1479 m_oldFont
= (WXHPEN
)hfont
;
1484 else // invalid font, reset the current font
1488 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1490 wxLogLastError(_T("SelectObject(old font)"));
1496 m_font
= wxNullFont
;
1500 void wxDC::SetPen(const wxPen
& pen
)
1502 WXMICROWIN_CHECK_HDC
1509 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1510 if ( hpen
== HGDI_ERROR
)
1512 wxLogLastError(_T("SelectObject(pen)"));
1517 m_oldPen
= (WXHPEN
)hpen
;
1522 else // invalid pen, reset the current pen
1526 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1528 wxLogLastError(_T("SelectObject(old pen)"));
1538 void wxDC::SetBrush(const wxBrush
& brush
)
1540 WXMICROWIN_CHECK_HDC
1542 if ( brush
== m_brush
)
1547 // we must make sure the brush is aligned with the logical coordinates
1548 // before selecting it
1549 wxBitmap
*stipple
= brush
.GetStipple();
1550 if ( stipple
&& stipple
->Ok() )
1552 if ( !::SetBrushOrgEx
1555 m_deviceOriginX
% stipple
->GetWidth(),
1556 m_deviceOriginY
% stipple
->GetHeight(),
1557 NULL
// [out] previous brush origin
1560 wxLogLastError(_T("SetBrushOrgEx()"));
1564 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1565 if ( hbrush
== HGDI_ERROR
)
1567 wxLogLastError(_T("SelectObject(brush)"));
1572 m_oldBrush
= (WXHPEN
)hbrush
;
1577 else // invalid brush, reset the current brush
1581 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1583 wxLogLastError(_T("SelectObject(old brush)"));
1589 m_brush
= wxNullBrush
;
1593 void wxDC::SetBackground(const wxBrush
& brush
)
1595 WXMICROWIN_CHECK_HDC
1597 m_backgroundBrush
= brush
;
1599 if ( m_backgroundBrush
.Ok() )
1601 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1605 void wxDC::SetBackgroundMode(int mode
)
1607 WXMICROWIN_CHECK_HDC
1609 m_backgroundMode
= mode
;
1611 // SetBackgroundColour now only refers to text background
1612 // and m_backgroundMode is used there
1615 void wxDC::SetLogicalFunction(int function
)
1617 WXMICROWIN_CHECK_HDC
1619 m_logicalFunction
= function
;
1624 void wxDC::SetRop(WXHDC dc
)
1626 if ( !dc
|| m_logicalFunction
< 0 )
1631 switch (m_logicalFunction
)
1633 case wxCLEAR
: rop
= R2_BLACK
; break;
1634 case wxXOR
: rop
= R2_XORPEN
; break;
1635 case wxINVERT
: rop
= R2_NOT
; break;
1636 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1637 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1638 case wxCOPY
: rop
= R2_COPYPEN
; break;
1639 case wxAND
: rop
= R2_MASKPEN
; break;
1640 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1641 case wxNO_OP
: rop
= R2_NOP
; break;
1642 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1643 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1644 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1645 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1646 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1647 case wxOR
: rop
= R2_MERGEPEN
; break;
1648 case wxSET
: rop
= R2_WHITE
; break;
1651 wxFAIL_MSG( wxT("unsupported logical function") );
1655 SetROP2(GetHdc(), rop
);
1658 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1660 // We might be previewing, so return true to let it continue.
1668 void wxDC::StartPage()
1672 void wxDC::EndPage()
1676 // ---------------------------------------------------------------------------
1678 // ---------------------------------------------------------------------------
1680 wxCoord
wxDC::GetCharHeight() const
1682 WXMICROWIN_CHECK_HDC_RET(0)
1684 TEXTMETRIC lpTextMetric
;
1686 GetTextMetrics(GetHdc(), &lpTextMetric
);
1688 return lpTextMetric
.tmHeight
;
1691 wxCoord
wxDC::GetCharWidth() const
1693 WXMICROWIN_CHECK_HDC_RET(0)
1695 TEXTMETRIC lpTextMetric
;
1697 GetTextMetrics(GetHdc(), &lpTextMetric
);
1699 return lpTextMetric
.tmAveCharWidth
;
1702 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1703 wxCoord
*descent
, wxCoord
*externalLeading
,
1706 #ifdef __WXMICROWIN__
1711 if (descent
) *descent
= 0;
1712 if (externalLeading
) *externalLeading
= 0;
1715 #endif // __WXMICROWIN__
1720 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1722 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1724 else // don't change the font
1732 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1733 GetTextMetrics(GetHdc(), &tm
);
1740 *descent
= tm
.tmDescent
;
1741 if (externalLeading
)
1742 *externalLeading
= tm
.tmExternalLeading
;
1746 ::SelectObject(GetHdc(), hfontOld
);
1751 // Each element of the array will be the width of the string up to and
1752 // including the coresoponding character in text.
1754 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1756 static int maxLenText
= -1;
1757 static int maxWidth
= -1;
1760 int stlen
= text
.length();
1762 if (maxLenText
== -1)
1764 // Win9x and WinNT+ have different limits
1765 int version
= wxGetOsVersion();
1766 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1767 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1771 widths
.Add(0, stlen
); // fill the array with zeros
1775 if (!::GetTextExtentExPoint(GetHdc(),
1776 text
.c_str(), // string to check
1777 wxMin(stlen
, maxLenText
),
1779 &fit
, // [out] count of chars
1781 &widths
[0], // array to fill
1785 wxLogLastError(wxT("GetTextExtentExPoint"));
1795 void wxDC::SetMapMode(int mode
)
1797 WXMICROWIN_CHECK_HDC
1799 m_mappingMode
= mode
;
1801 if ( mode
== wxMM_TEXT
)
1804 m_logicalScaleY
= 1.0;
1806 else // need to do some calculations
1808 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1809 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1810 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1811 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1813 if ( (mm_width
== 0) || (mm_height
== 0) )
1815 // we can't calculate mm2pixels[XY] then!
1819 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1820 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1825 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1826 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1830 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1831 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1835 m_logicalScaleX
= mm2pixelsX
;
1836 m_logicalScaleY
= mm2pixelsY
;
1840 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1841 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1845 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1849 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1850 // cases we could do with MM_TEXT and in the remaining 0.9% with
1851 // MM_ISOTROPIC (TODO!)
1853 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1855 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1856 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1858 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1859 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1861 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1862 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1866 void wxDC::SetUserScale(double x
, double y
)
1868 WXMICROWIN_CHECK_HDC
1870 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1876 this->SetMapMode(m_mappingMode
);
1879 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1880 bool WXUNUSED_IN_WINCE(yBottomUp
))
1882 WXMICROWIN_CHECK_HDC
1885 int signX
= xLeftRight
? 1 : -1,
1886 signY
= yBottomUp
? -1 : 1;
1888 if ( signX
!= m_signX
|| signY
!= m_signY
)
1893 SetMapMode(m_mappingMode
);
1898 void wxDC::SetSystemScale(double x
, double y
)
1900 WXMICROWIN_CHECK_HDC
1902 if ( x
== m_scaleX
&& y
== m_scaleY
)
1909 SetMapMode(m_mappingMode
);
1913 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1915 WXMICROWIN_CHECK_HDC
1917 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1920 m_logicalOriginX
= x
;
1921 m_logicalOriginY
= y
;
1924 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1928 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1930 WXMICROWIN_CHECK_HDC
1932 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1935 m_deviceOriginX
= x
;
1936 m_deviceOriginY
= y
;
1938 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1941 // ---------------------------------------------------------------------------
1942 // coordinates transformations
1943 // ---------------------------------------------------------------------------
1945 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1947 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1950 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1952 // axis orientation is not taken into account for conversion of a distance
1953 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1956 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1958 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1961 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1963 // axis orientation is not taken into account for conversion of a distance
1964 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1967 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1969 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1972 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1974 // axis orientation is not taken into account for conversion of a distance
1975 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1978 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1980 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1983 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1985 // axis orientation is not taken into account for conversion of a distance
1986 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1989 // ---------------------------------------------------------------------------
1991 // ---------------------------------------------------------------------------
1993 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1994 wxCoord width
, wxCoord height
,
1995 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1996 int rop
, bool useMask
,
1997 wxCoord xsrcMask
, wxCoord ysrcMask
)
1999 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2001 WXMICROWIN_CHECK_HDC_RET(false)
2003 // if either the source or destination has alpha channel, we must use
2004 // AlphaBlt() as other function don't handle it correctly
2005 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2006 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2007 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2009 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2010 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2014 wxMask
*mask
= NULL
;
2017 mask
= bmpSrc
.GetMask();
2019 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2021 // don't give assert here because this would break existing
2022 // programs - just silently ignore useMask parameter
2027 if (xsrcMask
== -1 && ysrcMask
== -1)
2029 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2032 COLORREF old_textground
= ::GetTextColor(GetHdc());
2033 COLORREF old_background
= ::GetBkColor(GetHdc());
2034 if (m_textForegroundColour
.Ok())
2036 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2038 if (m_textBackgroundColour
.Ok())
2040 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2046 case wxXOR
: dwRop
= SRCINVERT
; break;
2047 case wxINVERT
: dwRop
= DSTINVERT
; break;
2048 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2049 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2050 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2051 case wxSET
: dwRop
= WHITENESS
; break;
2052 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2053 case wxAND
: dwRop
= SRCAND
; break;
2054 case wxOR
: dwRop
= SRCPAINT
; break;
2055 case wxEQUIV
: dwRop
= 0x00990066; break;
2056 case wxNAND
: dwRop
= 0x007700E6; break;
2057 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2058 case wxCOPY
: dwRop
= SRCCOPY
; break;
2059 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2060 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2061 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2063 wxFAIL_MSG( wxT("unsupported logical function") );
2067 bool success
= false;
2072 // we want the part of the image corresponding to the mask to be
2073 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2074 // meaning of fg and bg is inverted which corresponds to wxWin notion
2075 // of the mask which is also contrary to the Windows one)
2077 // On some systems, MaskBlt succeeds yet is much much slower
2078 // than the wxWidgets fall-back implementation. So we need
2079 // to be able to switch this on and off at runtime.
2080 #if wxUSE_SYSTEM_OPTIONS
2081 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2087 xdest
, ydest
, width
, height
,
2090 (HBITMAP
)mask
->GetMaskBitmap(),
2092 MAKEROP4(dwRop
, DSTCOPY
)
2099 // Blit bitmap with mask
2102 HBITMAP buffer_bmap
;
2104 #if wxUSE_DC_CACHEING
2105 // create a temp buffer bitmap and DCs to access it and the mask
2106 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2107 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2109 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2110 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2112 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2115 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2116 #else // !wxUSE_DC_CACHEING
2117 // create a temp buffer bitmap and DCs to access it and the mask
2118 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2119 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2120 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2121 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2122 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2123 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2125 // copy dest to buffer
2126 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2127 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2129 wxLogLastError(wxT("BitBlt"));
2132 // copy src to buffer using selected raster op
2133 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2134 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2136 wxLogLastError(wxT("BitBlt"));
2139 // set masked area in buffer to BLACK (pixel value 0)
2140 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2141 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2142 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2143 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2145 wxLogLastError(wxT("BitBlt"));
2148 // set unmasked area in dest to BLACK
2149 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2150 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2151 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2152 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2154 wxLogLastError(wxT("BitBlt"));
2156 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2157 ::SetTextColor(GetHdc(), prevCol
);
2159 // OR buffer to dest
2160 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2161 (int)width
, (int)height
,
2162 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2165 wxLogLastError(wxT("BitBlt"));
2168 // tidy up temporary DCs and bitmap
2169 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2170 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2172 #if !wxUSE_DC_CACHEING
2174 ::DeleteDC(dc_mask
);
2175 ::DeleteDC(dc_buffer
);
2176 ::DeleteObject(buffer_bmap
);
2181 else // no mask, just BitBlt() it
2183 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2184 // use StretchBlt() if available and finally fall back to BitBlt()
2186 // FIXME: use appropriate WinCE functions
2188 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2189 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2194 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2196 &ds
) == sizeof(ds
) )
2198 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2200 // Figure out what co-ordinate system we're supposed to specify
2202 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2206 ysrc
= hDIB
- (ysrc
+ height
);
2209 if ( ::StretchDIBits(GetHdc(),
2215 (LPBITMAPINFO
)&ds
.dsBmih
,
2218 ) == (int)GDI_ERROR
)
2220 // On Win9x this API fails most (all?) of the time, so
2221 // logging it becomes quite distracting. Since it falls
2222 // back to the code below this is not really serious, so
2224 //wxLogLastError(wxT("StretchDIBits"));
2233 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2238 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2244 xdest
, ydest
, width
, height
,
2246 xsrc
, ysrc
, width
, height
,
2250 wxLogLastError(_T("StretchBlt"));
2264 (int)width
, (int)height
,
2270 wxLogLastError(_T("BitBlt"));
2279 ::SetTextColor(GetHdc(), old_textground
);
2280 ::SetBkColor(GetHdc(), old_background
);
2285 void wxDC::DoGetSize(int *w
, int *h
) const
2287 WXMICROWIN_CHECK_HDC
2289 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2290 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2293 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2295 WXMICROWIN_CHECK_HDC
2297 // if we implement it in terms of DoGetSize() instead of directly using the
2298 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2299 // will also work for wxWindowDC and wxClientDC even though their size is
2300 // not the same as the total size of the screen
2301 int wPixels
, hPixels
;
2302 DoGetSize(&wPixels
, &hPixels
);
2306 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2308 wxCHECK_RET( wTotal
, _T("0 width device?") );
2310 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2315 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2317 wxCHECK_RET( hTotal
, _T("0 height device?") );
2319 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2323 wxSize
wxDC::GetPPI() const
2325 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2327 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2328 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2330 return wxSize(x
, y
);
2333 // For use by wxWidgets only, unless custom units are required.
2334 void wxDC::SetLogicalScale(double x
, double y
)
2336 WXMICROWIN_CHECK_HDC
2338 m_logicalScaleX
= x
;
2339 m_logicalScaleY
= y
;
2342 // ----------------------------------------------------------------------------
2344 // ----------------------------------------------------------------------------
2346 #if wxUSE_DC_CACHEING
2349 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2350 * improve it in due course, either using arrays, or simply storing pointers to one
2351 * entry for the bitmap, and two for the DCs. -- JACS
2354 wxList
wxDC::sm_bitmapCache
;
2355 wxList
wxDC::sm_dcCache
;
2357 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2366 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2375 wxDCCacheEntry::~wxDCCacheEntry()
2378 ::DeleteObject((HBITMAP
) m_bitmap
);
2380 ::DeleteDC((HDC
) m_dc
);
2383 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2385 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2386 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2389 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2391 if (entry
->m_depth
== depth
)
2393 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2395 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2396 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2397 if ( !entry
->m_bitmap
)
2399 wxLogLastError(wxT("CreateCompatibleBitmap"));
2401 entry
->m_width
= w
; entry
->m_height
= h
;
2407 node
= node
->GetNext();
2409 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2412 wxLogLastError(wxT("CreateCompatibleBitmap"));
2414 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2415 AddToBitmapCache(entry
);
2419 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2421 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2422 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2425 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2427 // Don't return the same one as we already have
2428 if (!notThis
|| (notThis
!= entry
))
2430 if (entry
->m_depth
== depth
)
2436 node
= node
->GetNext();
2438 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2441 wxLogLastError(wxT("CreateCompatibleDC"));
2443 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2444 AddToDCCache(entry
);
2448 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2450 sm_bitmapCache
.Append(entry
);
2453 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2455 sm_dcCache
.Append(entry
);
2458 void wxDC::ClearCache()
2460 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2461 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2464 // Clean up cache at app exit
2465 class wxDCModule
: public wxModule
2468 virtual bool OnInit() { return true; }
2469 virtual void OnExit() { wxDC::ClearCache(); }
2472 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2475 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2477 #endif // wxUSE_DC_CACHEING
2479 // ----------------------------------------------------------------------------
2480 // alpha channel support
2481 // ----------------------------------------------------------------------------
2483 static bool AlphaBlt(HDC hdcDst
,
2484 int x
, int y
, int width
, int height
,
2485 int srcX
, int srcY
, HDC hdcSrc
,
2486 const wxBitmap
& bmp
)
2488 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2489 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2491 // do we have AlphaBlend() and company in the headers?
2492 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2493 // yes, now try to see if we have it during run-time
2494 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2495 HDC
,int,int,int,int,
2498 // bitmaps can be drawn only from GUI thread so there is no need to
2499 // protect this static variable from multiple threads
2500 static bool s_triedToLoad
= false;
2501 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2502 if ( !s_triedToLoad
)
2504 s_triedToLoad
= true;
2506 // don't give errors about the DLL being unavailable, we're
2507 // prepared to handle this
2510 wxDynamicLibrary
dll(_T("msimg32.dll"));
2511 if ( dll
.IsLoaded() )
2513 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2514 if ( pfnAlphaBlend
)
2516 // we must keep the DLL loaded if we want to be able to
2517 // call AlphaBlend() so just never unload it at all, not a
2524 if ( pfnAlphaBlend
)
2527 bf
.BlendOp
= AC_SRC_OVER
;
2529 bf
.SourceConstantAlpha
= 0xff;
2530 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2532 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2533 hdcSrc
, srcX
, srcY
, width
, height
,
2536 // skip wxAlphaBlend() call below
2540 wxLogLastError(_T("AlphaBlend"));
2543 wxUnusedVar(hdcSrc
);
2544 #endif // defined(AC_SRC_OVER)
2546 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2548 #ifdef wxHAVE_RAW_BITMAP
2549 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2552 #else // !wxHAVE_RAW_BITMAP
2553 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2554 // alpha but at least something will be shown like this)
2557 #endif // wxHAVE_RAW_BITMAP
2561 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2562 #ifdef wxHAVE_RAW_BITMAP
2565 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2567 // get the destination DC pixels
2568 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2570 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2572 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2574 wxLogLastError(_T("BitBlt"));
2577 // combine them with the source bitmap using alpha
2578 wxAlphaPixelData
dataDst(bmpDst
),
2579 dataSrc((wxBitmap
&)bmpSrc
);
2581 wxCHECK_RET( dataDst
&& dataSrc
,
2582 _T("failed to get raw data in wxAlphaBlend") );
2584 wxAlphaPixelData::Iterator
pDst(dataDst
),
2587 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2589 for ( int y
= 0; y
< h
; y
++ )
2591 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2592 pSrcRowStart
= pSrc
;
2594 for ( int x
= 0; x
< w
; x
++ )
2596 // note that source bitmap uses premultiplied alpha (as required by
2597 // the real AlphaBlend)
2598 const unsigned beta
= 255 - pSrc
.Alpha();
2600 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2601 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2602 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2608 pDst
= pDstRowStart
;
2609 pSrc
= pSrcRowStart
;
2610 pDst
.OffsetY(dataDst
, 1);
2611 pSrc
.OffsetY(dataSrc
, 1);
2614 // and finally blit them back to the destination DC
2615 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2617 wxLogLastError(_T("BitBlt"));
2621 #endif // #ifdef wxHAVE_RAW_BITMAP