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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
33 #include "wx/window.h"
36 #include "wx/dialog.h"
38 #include "wx/bitmap.h"
39 #include "wx/dcmemory.h"
44 #include "wx/sysopt.h"
45 #include "wx/dcprint.h"
46 #include "wx/module.h"
47 #include "wx/dynload.h"
49 #ifdef wxHAVE_RAW_BITMAP
50 #include "wx/rawbmp.h"
55 #include "wx/msw/wrapcdlg.h"
61 #define AC_SRC_ALPHA 1
64 /* Quaternary raster codes */
66 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
69 // apparently with MicroWindows it is possible that HDC is 0 so we have to
70 // check for this ourselves
72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
75 #define WXMICROWIN_CHECK_HDC
76 #define WXMICROWIN_CHECK_HDC_RET(x)
79 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 static const int MM_POINTS
= 9;
88 static const int MM_METRIC
= 10;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
107 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
108 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
109 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
111 #define XLOG2DEV(x) (x)
112 #define YLOG2DEV(y) (y)
113 #define XDEV2LOG(x) (x)
114 #define YDEV2LOG(y) (y)
117 // ---------------------------------------------------------------------------
119 // ---------------------------------------------------------------------------
121 // convert degrees to radians
122 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
124 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
126 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
127 // to pass it to this function but as we already have it at the point
128 // of call anyhow we do
130 // return true if we could draw the bitmap in one way or the other, false
132 static bool AlphaBlt(HDC hdcDst
,
133 int x
, int y
, int w
, int h
,
134 int srcX
, int srcY
, HDC hdcSrc
,
135 const wxBitmap
& bmpSrc
);
137 #ifdef wxHAVE_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement
140 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmp
);
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
147 // instead of duplicating the same code which sets and then restores text
148 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
149 // encapsulate this in a small helper class
151 // wxColourChanger: changes the text colours in the ctor if required and
152 // restores them in the dtor
153 class wxColourChanger
156 wxColourChanger(wxDC
& dc
);
162 COLORREF m_colFgOld
, m_colBgOld
;
166 DECLARE_NO_COPY_CLASS(wxColourChanger
)
169 // this class saves the old stretch blit mode during its life time
170 class StretchBltModeChanger
173 StretchBltModeChanger(HDC hdc
,
174 int WXUNUSED_IN_WINCE(mode
))
178 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
180 wxLogLastError(_T("SetStretchBltMode"));
184 ~StretchBltModeChanger()
187 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
188 wxLogLastError(_T("SetStretchBltMode"));
197 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
200 // ===========================================================================
202 // ===========================================================================
204 // ----------------------------------------------------------------------------
206 // ----------------------------------------------------------------------------
208 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
210 const wxBrush
& brush
= dc
.GetBrush();
211 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
213 HDC hdc
= GetHdcOf(dc
);
214 m_colFgOld
= ::GetTextColor(hdc
);
215 m_colBgOld
= ::GetBkColor(hdc
);
217 // note that Windows convention is opposite to wxWidgets one, this is
218 // why text colour becomes the background one and vice versa
219 const wxColour
& colFg
= dc
.GetTextForeground();
222 ::SetBkColor(hdc
, colFg
.GetPixel());
225 const wxColour
& colBg
= dc
.GetTextBackground();
228 ::SetTextColor(hdc
, colBg
.GetPixel());
232 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
235 // flag which telsl us to undo changes in the dtor
240 // nothing done, nothing to undo
245 wxColourChanger::~wxColourChanger()
249 // restore the colours we changed
250 HDC hdc
= GetHdcOf(m_dc
);
252 ::SetBkMode(hdc
, TRANSPARENT
);
253 ::SetTextColor(hdc
, m_colFgOld
);
254 ::SetBkColor(hdc
, m_colBgOld
);
258 // ---------------------------------------------------------------------------
260 // ---------------------------------------------------------------------------
262 // Default constructor
273 #endif // wxUSE_PALETTE
283 SelectOldObjects(m_hDC
);
285 // if we own the HDC, we delete it, otherwise we just release it
289 ::DeleteDC(GetHdc());
291 else // we don't own our HDC
295 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
299 // Must have been a wxScreenDC
300 ::ReleaseDC((HWND
) NULL
, GetHdc());
306 // This will select current objects out of the DC,
307 // which is what you have to do before deleting the
309 void wxDC::SelectOldObjects(WXHDC dc
)
315 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
317 if (m_selectedBitmap
.Ok())
319 m_selectedBitmap
.SetSelectedInto(NULL
);
326 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
331 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
336 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
343 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
346 #endif // wxUSE_PALETTE
349 m_brush
= wxNullBrush
;
352 m_palette
= wxNullPalette
;
353 #endif // wxUSE_PALETTE
355 m_backgroundBrush
= wxNullBrush
;
356 m_selectedBitmap
= wxNullBitmap
;
359 // ---------------------------------------------------------------------------
361 // ---------------------------------------------------------------------------
363 void wxDC::UpdateClipBox()
368 ::GetClipBox(GetHdc(), &rect
);
370 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
371 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
372 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
373 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
377 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
379 // check if we should try to retrieve the clipping region possibly not set
380 // by our SetClippingRegion() but preset by Windows:this can only happen
381 // when we're associated with an existing HDC usign SetHDC(), see there
382 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
384 wxDC
*self
= wxConstCast(this, wxDC
);
385 self
->UpdateClipBox();
387 if ( !m_clipX1
&& !m_clipX2
)
388 self
->m_clipping
= false;
391 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
394 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
395 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
397 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
401 // note that we combine the new clipping region with the existing one: this
402 // is compatible with what the other ports do and is the documented
403 // behaviour now (starting with 2.3.3)
404 #if defined(__WXWINCE__)
406 if ( !::GetClipBox(GetHdc(), &rectClip
) )
409 // GetClipBox returns logical coordinates, so transform to device
410 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
411 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
412 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
413 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
415 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
416 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
417 rectClip
.right
, rectClip
.bottom
);
419 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
421 ::SelectClipRgn(GetHdc(), hrgnDest
);
424 ::DeleteObject(hrgnClipOld
);
425 ::DeleteObject(hrgnDest
);
427 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
429 wxLogLastError(_T("ExtSelectClipRgn"));
433 #endif // WinCE/!WinCE
440 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
442 // the region coords are always the device ones, so do the translation
445 // FIXME: possible +/-1 error here, to check!
446 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
448 LogicalToDeviceX(x
+ w
),
449 LogicalToDeviceY(y
+ h
));
452 wxLogLastError(_T("CreateRectRgn"));
456 SetClippingHrgn((WXHRGN
)hrgn
);
458 ::DeleteObject(hrgn
);
462 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
464 SetClippingHrgn(region
.GetHRGN());
467 void wxDC::DestroyClippingRegion()
471 if (m_clipping
&& m_hDC
)
473 // TODO: this should restore the previous clipping region,
474 // so that OnPaint processing works correctly, and the update
475 // clipping region doesn't get destroyed after the first
476 // DestroyClippingRegion.
477 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
478 ::SelectClipRgn(GetHdc(), rgn
);
482 wxDCBase::DestroyClippingRegion();
485 // ---------------------------------------------------------------------------
486 // query capabilities
487 // ---------------------------------------------------------------------------
489 bool wxDC::CanDrawBitmap() const
494 bool wxDC::CanGetTextExtent() const
496 #ifdef __WXMICROWIN__
497 // TODO Extend MicroWindows' GetDeviceCaps function
500 // What sort of display is it?
501 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
503 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
507 int wxDC::GetDepth() const
509 WXMICROWIN_CHECK_HDC_RET(16)
511 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
514 // ---------------------------------------------------------------------------
516 // ---------------------------------------------------------------------------
525 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
529 // No, I think we should simply ignore this if printing on e.g.
531 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
532 if (!m_selectedBitmap
.Ok())
535 rect
.left
= 0; rect
.top
= 0;
536 rect
.right
= m_selectedBitmap
.GetWidth();
537 rect
.bottom
= m_selectedBitmap
.GetHeight();
541 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
544 DWORD colour
= ::GetBkColor(GetHdc());
545 HBRUSH brush
= ::CreateSolidBrush(colour
);
546 ::FillRect(GetHdc(), &rect
, brush
);
547 ::DeleteObject(brush
);
550 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
551 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
553 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
555 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
556 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
557 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
558 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
562 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
563 wxCoord
WXUNUSED_IN_WINCE(y
),
564 const wxColour
& WXUNUSED_IN_WINCE(col
),
565 int WXUNUSED_IN_WINCE(style
))
570 WXMICROWIN_CHECK_HDC_RET(false)
572 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
574 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
575 : FLOODFILLBORDER
) ) ;
578 // quoting from the MSDN docs:
580 // Following are some of the reasons this function might fail:
582 // * The filling could not be completed.
583 // * The specified point has the boundary color specified by the
584 // crColor parameter (if FLOODFILLBORDER was requested).
585 // * The specified point does not have the color specified by
586 // crColor (if FLOODFILLSURFACE was requested)
587 // * The point is outside the clipping region that is, it is not
588 // visible on the device.
590 wxLogLastError(wxT("ExtFloodFill"));
593 CalcBoundingBox(x
, y
);
599 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
601 WXMICROWIN_CHECK_HDC_RET(false)
603 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
605 // get the color of the pixel
606 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
608 wxRGBToColour(*col
, pixelcolor
);
613 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
617 wxCoord x1
= x
-VIEWPORT_EXTENT
;
618 wxCoord y1
= y
-VIEWPORT_EXTENT
;
619 wxCoord x2
= x
+VIEWPORT_EXTENT
;
620 wxCoord y2
= y
+VIEWPORT_EXTENT
;
622 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
623 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
625 CalcBoundingBox(x1
, y1
);
626 CalcBoundingBox(x2
, y2
);
629 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
633 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
635 CalcBoundingBox(x1
, y1
);
636 CalcBoundingBox(x2
, y2
);
639 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
640 // and ending at (x2, y2)
641 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
642 wxCoord x2
, wxCoord y2
,
643 wxCoord xc
, wxCoord yc
)
646 // Slower emulation since WinCE doesn't support Pie and Arc
647 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
648 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
649 if( y1
>yc
) sa
= -sa
; // below center
650 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
651 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
656 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
660 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
661 wxCoord r
= (wxCoord
)radius
;
663 // treat the special case of full circle separately
664 if ( x1
== x2
&& y1
== y2
)
666 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
670 wxCoord xx1
= XLOG2DEV(x1
);
671 wxCoord yy1
= YLOG2DEV(y1
);
672 wxCoord xx2
= XLOG2DEV(x2
);
673 wxCoord yy2
= YLOG2DEV(y2
);
674 wxCoord xxc
= XLOG2DEV(xc
);
675 wxCoord yyc
= YLOG2DEV(yc
);
676 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
678 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
679 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
680 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
681 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
683 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
685 // Have to add 1 to bottom-right corner of rectangle
686 // to make semi-circles look right (crooked line otherwise).
687 // Unfortunately this is not a reliable method, depends
688 // on the size of shape.
689 // TODO: figure out why this happens!
690 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
694 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
697 CalcBoundingBox(xc
- r
, yc
- r
);
698 CalcBoundingBox(xc
+ r
, yc
+ r
);
702 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
703 wxCoord width
, wxCoord height
)
707 wxCoord x2
= x1
+ width
,
710 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
718 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
720 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
722 #else // Symantec-MicroWin
724 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
725 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
726 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
727 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
728 ::SetROP2(GetHdc(), R2_COPYPEN
);
729 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
730 MoveToEx(GetHdc(), x1
, y1
, NULL
);
731 LineTo(GetHdc(), x2
, y2
);
732 MoveToEx(GetHdc(), x2
, y1
, NULL
);
733 LineTo(GetHdc(), x1
, y2
);
734 ::SelectObject(GetHdc(), hPenOld
);
735 ::SelectObject(GetHdc(), hBrushOld
);
736 ::DeleteObject(blackPen
);
737 #endif // Win32/Symantec-MicroWin
739 CalcBoundingBox(x1
, y1
);
740 CalcBoundingBox(x2
, y2
);
743 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
747 COLORREF color
= 0x00ffffff;
750 color
= m_pen
.GetColour().GetPixel();
753 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
755 CalcBoundingBox(x
, y
);
758 void wxDC::DoDrawPolygon(int n
,
762 int WXUNUSED_IN_WINCE(fillStyle
))
766 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
768 // Do things less efficiently if we have offsets
769 if (xoffset
!= 0 || yoffset
!= 0)
771 POINT
*cpoints
= new POINT
[n
];
773 for (i
= 0; i
< n
; i
++)
775 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
776 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
778 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
781 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
783 (void)Polygon(GetHdc(), cpoints
, n
);
785 SetPolyFillMode(GetHdc(),prev
);
792 for (i
= 0; i
< n
; i
++)
793 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
796 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
798 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
800 SetPolyFillMode(GetHdc(),prev
);
806 wxDC::DoDrawPolyPolygon(int n
,
814 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
818 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
820 for (i
= cnt
= 0; i
< n
; i
++)
823 // Do things less efficiently if we have offsets
824 if (xoffset
!= 0 || yoffset
!= 0)
826 POINT
*cpoints
= new POINT
[cnt
];
827 for (i
= 0; i
< cnt
; i
++)
829 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
830 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
832 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
835 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
837 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
839 SetPolyFillMode(GetHdc(),prev
);
845 for (i
= 0; i
< cnt
; i
++)
846 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
849 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
851 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
853 SetPolyFillMode(GetHdc(),prev
);
860 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
864 // Do things less efficiently if we have offsets
865 if (xoffset
!= 0 || yoffset
!= 0)
867 POINT
*cpoints
= new POINT
[n
];
869 for (i
= 0; i
< n
; i
++)
871 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
872 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
874 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
876 (void)Polyline(GetHdc(), cpoints
, n
);
882 for (i
= 0; i
< n
; i
++)
883 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
885 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
889 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
893 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
895 wxCoord x2
= x
+ width
;
896 wxCoord y2
= y
+ height
;
898 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
901 rect
.left
= XLOG2DEV(x
);
902 rect
.top
= YLOG2DEV(y
);
903 rect
.right
= XLOG2DEV(x2
);
904 rect
.bottom
= YLOG2DEV(y2
);
905 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
909 // Windows draws the filled rectangles without outline (i.e. drawn with a
910 // transparent pen) one pixel smaller in both directions and we want them
911 // to have the same size regardless of which pen is used - adjust
913 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
914 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
916 // Apparently not needed for WinCE (see e.g. Life! demo)
923 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
927 CalcBoundingBox(x
, y
);
928 CalcBoundingBox(x2
, y2
);
931 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
935 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
937 // Now, a negative radius value is interpreted to mean
938 // 'the proportion of the smallest X or Y dimension'
942 double smallest
= (width
< height
) ? width
: height
;
943 radius
= (- radius
* smallest
);
946 wxCoord x2
= (x
+width
);
947 wxCoord y2
= (y
+height
);
949 // Windows draws the filled rectangles without outline (i.e. drawn with a
950 // transparent pen) one pixel smaller in both directions and we want them
951 // to have the same size regardless of which pen is used - adjust
952 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
958 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
959 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
961 CalcBoundingBox(x
, y
);
962 CalcBoundingBox(x2
, y2
);
965 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
969 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
971 wxCoord x2
= (x
+width
);
972 wxCoord y2
= (y
+height
);
974 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
976 CalcBoundingBox(x
, y
);
977 CalcBoundingBox(x2
, y2
);
981 void wxDC::DoDrawSpline(wxList
*points
)
984 // WinCE does not support ::PolyBezier so use generic version
985 wxDCBase::DoDrawSpline(points
);
987 // quadratic b-spline to cubic bezier spline conversion
989 // quadratic spline with control points P0,P1,P2
990 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
992 // bezier spline with control points B0,B1,B2,B3
993 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
995 // control points of bezier spline calculated from b-spline
997 // B1 = (2*P1 + P0)/3
998 // B2 = (2*P1 + P2)/3
1001 WXMICROWIN_CHECK_HDC
1003 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1005 const size_t n_points
= points
->GetCount();
1006 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1008 const size_t n_bezier_points
= n_points
* 3 + 1;
1009 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1010 size_t bezier_pos
= 0;
1011 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1013 wxList::compatibility_iterator node
= points
->GetFirst();
1014 wxPoint
*p
= (wxPoint
*)node
->GetData();
1015 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1016 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1018 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1021 node
= node
->GetNext();
1022 p
= (wxPoint
*)node
->GetData();
1026 cx1
= ( x1
+ x2
) / 2;
1027 cy1
= ( y1
+ y2
) / 2;
1028 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1029 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1031 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1035 while ((node
= node
->GetNext()) != NULL
)
1037 while ((node
= node
->GetNext()))
1038 #endif // !wxUSE_STL
1040 p
= (wxPoint
*)node
->GetData();
1045 cx4
= (x1
+ x2
) / 2;
1046 cy4
= (y1
+ y2
) / 2;
1047 // B0 is B3 of previous segment
1049 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1050 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1053 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1054 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1057 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1058 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1064 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1066 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1067 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1069 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1072 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1079 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1080 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1083 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1086 WXMICROWIN_CHECK_HDC
1088 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1093 int rx1
= XLOG2DEV(x
+w
/2);
1094 int ry1
= YLOG2DEV(y
+h
/2);
1101 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1102 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1103 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1104 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1106 // draw pie with NULL_PEN first and then outline otherwise a line is
1107 // drawn from the start and end points to the centre
1108 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1111 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1112 rx1
, ry1
, rx2
, ry2
);
1116 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1117 rx1
, ry1
-1, rx2
, ry2
-1);
1120 ::SelectObject(GetHdc(), hpenOld
);
1122 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1123 rx1
, ry1
, rx2
, ry2
);
1125 CalcBoundingBox(x
, y
);
1126 CalcBoundingBox(x2
, y2
);
1130 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1132 WXMICROWIN_CHECK_HDC
1134 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1137 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1139 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1142 CalcBoundingBox(x
, y
);
1143 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1146 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1148 WXMICROWIN_CHECK_HDC
1150 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1152 int width
= bmp
.GetWidth(),
1153 height
= bmp
.GetHeight();
1155 HBITMAP hbmpMask
= 0;
1158 HPALETTE oldPal
= 0;
1159 #endif // wxUSE_PALETTE
1161 if ( bmp
.HasAlpha() )
1164 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1166 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1172 wxMask
*mask
= bmp
.GetMask();
1174 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1178 // don't give assert here because this would break existing
1179 // programs - just silently ignore useMask parameter
1186 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1188 // On some systems, MaskBlt succeeds yet is much much slower
1189 // than the wxWidgets fall-back implementation. So we need
1190 // to be able to switch this on and off at runtime.
1192 #if wxUSE_SYSTEM_OPTIONS
1193 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1197 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1198 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1200 wxPalette
*pal
= bmp
.GetPalette();
1201 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1203 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1204 ::RealizePalette(hdcMem
);
1206 #endif // wxUSE_PALETTE
1208 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1211 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1215 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1216 #endif // wxUSE_PALETTE
1218 ::SelectObject(hdcMem
, hOldBitmap
);
1225 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1228 memDC
.SelectObject(bmp
);
1230 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1232 memDC
.SelectObject(wxNullBitmap
);
1235 else // no mask, just use BitBlt()
1238 HDC memdc
= ::CreateCompatibleDC( cdc
);
1239 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1241 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1243 COLORREF old_textground
= ::GetTextColor(GetHdc());
1244 COLORREF old_background
= ::GetBkColor(GetHdc());
1245 if (m_textForegroundColour
.Ok())
1247 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1249 if (m_textBackgroundColour
.Ok())
1251 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1255 wxPalette
*pal
= bmp
.GetPalette();
1256 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1258 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1259 ::RealizePalette(memdc
);
1261 #endif // wxUSE_PALETTE
1263 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1264 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1268 ::SelectPalette(memdc
, oldPal
, FALSE
);
1269 #endif // wxUSE_PALETTE
1271 ::SelectObject( memdc
, hOldBitmap
);
1272 ::DeleteDC( memdc
);
1274 ::SetTextColor(GetHdc(), old_textground
);
1275 ::SetBkColor(GetHdc(), old_background
);
1279 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1281 WXMICROWIN_CHECK_HDC
1283 DrawAnyText(text
, x
, y
);
1285 // update the bounding box
1286 CalcBoundingBox(x
, y
);
1289 GetTextExtent(text
, &w
, &h
);
1290 CalcBoundingBox(x
+ w
, y
+ h
);
1293 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1295 WXMICROWIN_CHECK_HDC
1297 // prepare for drawing the text
1298 if ( m_textForegroundColour
.Ok() )
1299 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1301 DWORD old_background
= 0;
1302 if ( m_textBackgroundColour
.Ok() )
1304 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1307 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1311 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1312 text
.c_str(), text
.length(), NULL
) == 0 )
1314 wxLogLastError(wxT("TextOut"));
1317 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1318 text
.c_str(), text
.length()) == 0 )
1320 wxLogLastError(wxT("TextOut"));
1324 // restore the old parameters (text foreground colour may be left because
1325 // it never is set to anything else, but background should remain
1326 // transparent even if we just drew an opaque string)
1327 if ( m_textBackgroundColour
.Ok() )
1328 (void)SetBkColor(GetHdc(), old_background
);
1330 SetBkMode(GetHdc(), TRANSPARENT
);
1333 void wxDC::DoDrawRotatedText(const wxString
& text
,
1334 wxCoord x
, wxCoord y
,
1337 WXMICROWIN_CHECK_HDC
1339 // we test that we have some font because otherwise we should still use the
1340 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1341 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1342 // font for drawing rotated fonts unfortunately)
1343 if ( (angle
== 0.0) && m_font
.Ok() )
1345 DoDrawText(text
, x
, y
);
1347 #ifndef __WXMICROWIN__
1350 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1351 // because it's not TrueType and so can't have non zero
1352 // orientation/escapement under Win9x
1353 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1354 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1356 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1358 wxLogLastError(wxT("GetObject(hfont)"));
1361 // GDI wants the angle in tenth of degree
1362 long angle10
= (long)(angle
* 10);
1363 lf
.lfEscapement
= angle10
;
1364 lf
. lfOrientation
= angle10
;
1366 hfont
= ::CreateFontIndirect(&lf
);
1369 wxLogLastError(wxT("CreateFont"));
1373 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1375 DrawAnyText(text
, x
, y
);
1377 (void)::SelectObject(GetHdc(), hfontOld
);
1378 (void)::DeleteObject(hfont
);
1381 // call the bounding box by adding all four vertices of the rectangle
1382 // containing the text to it (simpler and probably not slower than
1383 // determining which of them is really topmost/leftmost/...)
1385 GetTextExtent(text
, &w
, &h
);
1387 double rad
= DegToRad(angle
);
1389 // "upper left" and "upper right"
1390 CalcBoundingBox(x
, y
);
1391 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1393 // "bottom left" and "bottom right"
1394 x
+= (wxCoord
)(h
*sin(rad
));
1395 y
+= (wxCoord
)(h
*cos(rad
));
1396 CalcBoundingBox(x
, y
);
1397 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1402 // ---------------------------------------------------------------------------
1404 // ---------------------------------------------------------------------------
1408 void wxDC::DoSelectPalette(bool realize
)
1410 WXMICROWIN_CHECK_HDC
1412 // Set the old object temporarily, in case the assignment deletes an object
1413 // that's not yet selected out.
1416 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1420 if ( m_palette
.Ok() )
1422 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1423 GetHpaletteOf(m_palette
),
1426 m_oldPalette
= (WXHPALETTE
) oldPal
;
1429 ::RealizePalette(GetHdc());
1433 void wxDC::SetPalette(const wxPalette
& palette
)
1437 m_palette
= palette
;
1438 DoSelectPalette(true);
1442 void wxDC::InitializePalette()
1444 if ( wxDisplayDepth() <= 8 )
1446 // look for any window or parent that has a custom palette. If any has
1447 // one then we need to use it in drawing operations
1448 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1450 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1451 if ( m_hasCustomPalette
)
1453 m_palette
= win
->GetPalette();
1455 // turn on MSW translation for this palette
1461 #endif // wxUSE_PALETTE
1463 // SetFont/Pen/Brush() really ask to be implemented as a single template
1464 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1466 void wxDC::SetFont(const wxFont
& font
)
1468 WXMICROWIN_CHECK_HDC
1470 if ( font
== m_font
)
1475 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1476 if ( hfont
== HGDI_ERROR
)
1478 wxLogLastError(_T("SelectObject(font)"));
1483 m_oldFont
= (WXHPEN
)hfont
;
1488 else // invalid font, reset the current font
1492 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1494 wxLogLastError(_T("SelectObject(old font)"));
1500 m_font
= wxNullFont
;
1504 void wxDC::SetPen(const wxPen
& pen
)
1506 WXMICROWIN_CHECK_HDC
1513 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1514 if ( hpen
== HGDI_ERROR
)
1516 wxLogLastError(_T("SelectObject(pen)"));
1521 m_oldPen
= (WXHPEN
)hpen
;
1526 else // invalid pen, reset the current pen
1530 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1532 wxLogLastError(_T("SelectObject(old pen)"));
1542 void wxDC::SetBrush(const wxBrush
& brush
)
1544 WXMICROWIN_CHECK_HDC
1546 if ( brush
== m_brush
)
1551 // we must make sure the brush is aligned with the logical coordinates
1552 // before selecting it
1553 wxBitmap
*stipple
= brush
.GetStipple();
1554 if ( stipple
&& stipple
->Ok() )
1556 if ( !::SetBrushOrgEx
1559 m_deviceOriginX
% stipple
->GetWidth(),
1560 m_deviceOriginY
% stipple
->GetHeight(),
1561 NULL
// [out] previous brush origin
1564 wxLogLastError(_T("SetBrushOrgEx()"));
1568 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1569 if ( hbrush
== HGDI_ERROR
)
1571 wxLogLastError(_T("SelectObject(brush)"));
1576 m_oldBrush
= (WXHPEN
)hbrush
;
1581 else // invalid brush, reset the current brush
1585 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1587 wxLogLastError(_T("SelectObject(old brush)"));
1593 m_brush
= wxNullBrush
;
1597 void wxDC::SetBackground(const wxBrush
& brush
)
1599 WXMICROWIN_CHECK_HDC
1601 m_backgroundBrush
= brush
;
1603 if ( m_backgroundBrush
.Ok() )
1605 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1609 void wxDC::SetBackgroundMode(int mode
)
1611 WXMICROWIN_CHECK_HDC
1613 m_backgroundMode
= mode
;
1615 // SetBackgroundColour now only refers to text background
1616 // and m_backgroundMode is used there
1619 void wxDC::SetLogicalFunction(int function
)
1621 WXMICROWIN_CHECK_HDC
1623 m_logicalFunction
= function
;
1628 void wxDC::SetRop(WXHDC dc
)
1630 if ( !dc
|| m_logicalFunction
< 0 )
1635 switch (m_logicalFunction
)
1637 case wxCLEAR
: rop
= R2_BLACK
; break;
1638 case wxXOR
: rop
= R2_XORPEN
; break;
1639 case wxINVERT
: rop
= R2_NOT
; break;
1640 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1641 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1642 case wxCOPY
: rop
= R2_COPYPEN
; break;
1643 case wxAND
: rop
= R2_MASKPEN
; break;
1644 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1645 case wxNO_OP
: rop
= R2_NOP
; break;
1646 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1647 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1648 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1649 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1650 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1651 case wxOR
: rop
= R2_MERGEPEN
; break;
1652 case wxSET
: rop
= R2_WHITE
; break;
1655 wxFAIL_MSG( wxT("unsupported logical function") );
1659 SetROP2(GetHdc(), rop
);
1662 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1664 // We might be previewing, so return true to let it continue.
1672 void wxDC::StartPage()
1676 void wxDC::EndPage()
1680 // ---------------------------------------------------------------------------
1682 // ---------------------------------------------------------------------------
1684 wxCoord
wxDC::GetCharHeight() const
1686 WXMICROWIN_CHECK_HDC_RET(0)
1688 TEXTMETRIC lpTextMetric
;
1690 GetTextMetrics(GetHdc(), &lpTextMetric
);
1692 return lpTextMetric
.tmHeight
;
1695 wxCoord
wxDC::GetCharWidth() const
1697 WXMICROWIN_CHECK_HDC_RET(0)
1699 TEXTMETRIC lpTextMetric
;
1701 GetTextMetrics(GetHdc(), &lpTextMetric
);
1703 return lpTextMetric
.tmAveCharWidth
;
1706 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1707 wxCoord
*descent
, wxCoord
*externalLeading
,
1710 #ifdef __WXMICROWIN__
1715 if (descent
) *descent
= 0;
1716 if (externalLeading
) *externalLeading
= 0;
1719 #endif // __WXMICROWIN__
1724 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1726 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1728 else // don't change the font
1736 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1737 GetTextMetrics(GetHdc(), &tm
);
1744 *descent
= tm
.tmDescent
;
1745 if (externalLeading
)
1746 *externalLeading
= tm
.tmExternalLeading
;
1750 ::SelectObject(GetHdc(), hfontOld
);
1755 // Each element of the array will be the width of the string up to and
1756 // including the coresoponding character in text.
1758 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1760 static int maxLenText
= -1;
1761 static int maxWidth
= -1;
1764 int stlen
= text
.Length();
1766 if (maxLenText
== -1)
1768 // Win9x and WinNT+ have different limits
1769 int version
= wxGetOsVersion();
1770 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1771 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1775 widths
.Add(0, stlen
); // fill the array with zeros
1779 if (!::GetTextExtentExPoint(GetHdc(),
1780 text
.c_str(), // string to check
1781 wxMin(stlen
, maxLenText
),
1783 &fit
, // [out] count of chars
1785 &widths
[0], // array to fill
1789 wxLogLastError(wxT("GetTextExtentExPoint"));
1799 void wxDC::SetMapMode(int mode
)
1801 WXMICROWIN_CHECK_HDC
1803 m_mappingMode
= mode
;
1805 if ( mode
== wxMM_TEXT
)
1808 m_logicalScaleY
= 1.0;
1810 else // need to do some calculations
1812 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1813 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1814 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1815 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1817 if ( (mm_width
== 0) || (mm_height
== 0) )
1819 // we can't calculate mm2pixels[XY] then!
1823 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1824 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1829 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1830 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1834 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1835 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1839 m_logicalScaleX
= mm2pixelsX
;
1840 m_logicalScaleY
= mm2pixelsY
;
1844 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1845 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1849 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1853 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1854 // cases we could do with MM_TEXT and in the remaining 0.9% with
1855 // MM_ISOTROPIC (TODO!)
1857 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1859 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1860 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1862 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1863 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1865 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1866 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1870 void wxDC::SetUserScale(double x
, double y
)
1872 WXMICROWIN_CHECK_HDC
1874 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1880 this->SetMapMode(m_mappingMode
);
1883 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1884 bool WXUNUSED_IN_WINCE(yBottomUp
))
1886 WXMICROWIN_CHECK_HDC
1889 int signX
= xLeftRight
? 1 : -1,
1890 signY
= yBottomUp
? -1 : 1;
1892 if ( signX
!= m_signX
|| signY
!= m_signY
)
1897 SetMapMode(m_mappingMode
);
1902 void wxDC::SetSystemScale(double x
, double y
)
1904 WXMICROWIN_CHECK_HDC
1906 if ( x
== m_scaleX
&& y
== m_scaleY
)
1913 SetMapMode(m_mappingMode
);
1917 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1919 WXMICROWIN_CHECK_HDC
1921 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1924 m_logicalOriginX
= x
;
1925 m_logicalOriginY
= y
;
1928 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1932 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1934 WXMICROWIN_CHECK_HDC
1936 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1939 m_deviceOriginX
= x
;
1940 m_deviceOriginY
= y
;
1942 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1945 // ---------------------------------------------------------------------------
1946 // coordinates transformations
1947 // ---------------------------------------------------------------------------
1949 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1951 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1954 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1956 // axis orientation is not taken into account for conversion of a distance
1957 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1960 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1962 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1965 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1967 // axis orientation is not taken into account for conversion of a distance
1968 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1971 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1973 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1976 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1978 // axis orientation is not taken into account for conversion of a distance
1979 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1982 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1984 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1987 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1989 // axis orientation is not taken into account for conversion of a distance
1990 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1993 // ---------------------------------------------------------------------------
1995 // ---------------------------------------------------------------------------
1997 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1998 wxCoord width
, wxCoord height
,
1999 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
2000 int rop
, bool useMask
,
2001 wxCoord xsrcMask
, wxCoord ysrcMask
)
2003 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2005 WXMICROWIN_CHECK_HDC_RET(false)
2007 // if either the source or destination has alpha channel, we must use
2008 // AlphaBlt() as other function don't handle it correctly
2009 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2010 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2011 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2013 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2014 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2018 wxMask
*mask
= NULL
;
2021 mask
= bmpSrc
.GetMask();
2023 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2025 // don't give assert here because this would break existing
2026 // programs - just silently ignore useMask parameter
2031 if (xsrcMask
== -1 && ysrcMask
== -1)
2033 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2036 COLORREF old_textground
= ::GetTextColor(GetHdc());
2037 COLORREF old_background
= ::GetBkColor(GetHdc());
2038 if (m_textForegroundColour
.Ok())
2040 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2042 if (m_textBackgroundColour
.Ok())
2044 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2050 case wxXOR
: dwRop
= SRCINVERT
; break;
2051 case wxINVERT
: dwRop
= DSTINVERT
; break;
2052 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2053 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2054 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2055 case wxSET
: dwRop
= WHITENESS
; break;
2056 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2057 case wxAND
: dwRop
= SRCAND
; break;
2058 case wxOR
: dwRop
= SRCPAINT
; break;
2059 case wxEQUIV
: dwRop
= 0x00990066; break;
2060 case wxNAND
: dwRop
= 0x007700E6; break;
2061 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2062 case wxCOPY
: dwRop
= SRCCOPY
; break;
2063 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2064 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2065 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2067 wxFAIL_MSG( wxT("unsupported logical function") );
2071 bool success
= false;
2076 // we want the part of the image corresponding to the mask to be
2077 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2078 // meaning of fg and bg is inverted which corresponds to wxWin notion
2079 // of the mask which is also contrary to the Windows one)
2081 // On some systems, MaskBlt succeeds yet is much much slower
2082 // than the wxWidgets fall-back implementation. So we need
2083 // to be able to switch this on and off at runtime.
2084 #if wxUSE_SYSTEM_OPTIONS
2085 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2091 xdest
, ydest
, width
, height
,
2094 (HBITMAP
)mask
->GetMaskBitmap(),
2096 MAKEROP4(dwRop
, DSTCOPY
)
2103 // Blit bitmap with mask
2106 HBITMAP buffer_bmap
;
2108 #if wxUSE_DC_CACHEING
2109 // create a temp buffer bitmap and DCs to access it and the mask
2110 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2111 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2113 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2114 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2116 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2119 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2120 #else // !wxUSE_DC_CACHEING
2121 // create a temp buffer bitmap and DCs to access it and the mask
2122 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2123 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2124 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2125 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2126 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2127 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2129 // copy dest to buffer
2130 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2131 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2133 wxLogLastError(wxT("BitBlt"));
2136 // copy src to buffer using selected raster op
2137 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2138 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2140 wxLogLastError(wxT("BitBlt"));
2143 // set masked area in buffer to BLACK (pixel value 0)
2144 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2145 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2146 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2147 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2149 wxLogLastError(wxT("BitBlt"));
2152 // set unmasked area in dest to BLACK
2153 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2154 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2155 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2156 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2158 wxLogLastError(wxT("BitBlt"));
2160 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2161 ::SetTextColor(GetHdc(), prevCol
);
2163 // OR buffer to dest
2164 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2165 (int)width
, (int)height
,
2166 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2169 wxLogLastError(wxT("BitBlt"));
2172 // tidy up temporary DCs and bitmap
2173 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2174 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2176 #if !wxUSE_DC_CACHEING
2178 ::DeleteDC(dc_mask
);
2179 ::DeleteDC(dc_buffer
);
2180 ::DeleteObject(buffer_bmap
);
2185 else // no mask, just BitBlt() it
2187 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2188 // use StretchBlt() if available and finally fall back to BitBlt()
2190 // FIXME: use appropriate WinCE functions
2192 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2193 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2198 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2200 &ds
) == sizeof(ds
) )
2202 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2204 // Figure out what co-ordinate system we're supposed to specify
2206 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2210 ysrc
= hDIB
- (ysrc
+ height
);
2213 if ( ::StretchDIBits(GetHdc(),
2219 (LPBITMAPINFO
)&ds
.dsBmih
,
2222 ) == (int)GDI_ERROR
)
2224 // On Win9x this API fails most (all?) of the time, so
2225 // logging it becomes quite distracting. Since it falls
2226 // back to the code below this is not really serious, so
2228 //wxLogLastError(wxT("StretchDIBits"));
2237 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2242 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2248 xdest
, ydest
, width
, height
,
2250 xsrc
, ysrc
, width
, height
,
2254 wxLogLastError(_T("StretchBlt"));
2268 (int)width
, (int)height
,
2274 wxLogLastError(_T("BitBlt"));
2283 ::SetTextColor(GetHdc(), old_textground
);
2284 ::SetBkColor(GetHdc(), old_background
);
2289 void wxDC::DoGetSize(int *w
, int *h
) const
2291 WXMICROWIN_CHECK_HDC
2293 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2294 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2297 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2299 WXMICROWIN_CHECK_HDC
2301 // if we implement it in terms of DoGetSize() instead of directly using the
2302 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2303 // will also work for wxWindowDC and wxClientDC even though their size is
2304 // not the same as the total size of the screen
2305 int wPixels
, hPixels
;
2306 DoGetSize(&wPixels
, &hPixels
);
2310 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2312 wxCHECK_RET( wTotal
, _T("0 width device?") );
2314 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2319 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2321 wxCHECK_RET( hTotal
, _T("0 height device?") );
2323 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2327 wxSize
wxDC::GetPPI() const
2329 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2331 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2332 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2334 return wxSize(x
, y
);
2337 // For use by wxWidgets only, unless custom units are required.
2338 void wxDC::SetLogicalScale(double x
, double y
)
2340 WXMICROWIN_CHECK_HDC
2342 m_logicalScaleX
= x
;
2343 m_logicalScaleY
= y
;
2346 // ----------------------------------------------------------------------------
2348 // ----------------------------------------------------------------------------
2350 #if wxUSE_DC_CACHEING
2353 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2354 * improve it in due course, either using arrays, or simply storing pointers to one
2355 * entry for the bitmap, and two for the DCs. -- JACS
2358 wxList
wxDC::sm_bitmapCache
;
2359 wxList
wxDC::sm_dcCache
;
2361 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2370 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2379 wxDCCacheEntry::~wxDCCacheEntry()
2382 ::DeleteObject((HBITMAP
) m_bitmap
);
2384 ::DeleteDC((HDC
) m_dc
);
2387 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2389 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2390 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2393 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2395 if (entry
->m_depth
== depth
)
2397 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2399 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2400 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2401 if ( !entry
->m_bitmap
)
2403 wxLogLastError(wxT("CreateCompatibleBitmap"));
2405 entry
->m_width
= w
; entry
->m_height
= h
;
2411 node
= node
->GetNext();
2413 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2416 wxLogLastError(wxT("CreateCompatibleBitmap"));
2418 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2419 AddToBitmapCache(entry
);
2423 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2425 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2426 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2429 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2431 // Don't return the same one as we already have
2432 if (!notThis
|| (notThis
!= entry
))
2434 if (entry
->m_depth
== depth
)
2440 node
= node
->GetNext();
2442 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2445 wxLogLastError(wxT("CreateCompatibleDC"));
2447 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2448 AddToDCCache(entry
);
2452 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2454 sm_bitmapCache
.Append(entry
);
2457 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2459 sm_dcCache
.Append(entry
);
2462 void wxDC::ClearCache()
2464 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2465 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2468 // Clean up cache at app exit
2469 class wxDCModule
: public wxModule
2472 virtual bool OnInit() { return true; }
2473 virtual void OnExit() { wxDC::ClearCache(); }
2476 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2479 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2481 #endif // wxUSE_DC_CACHEING
2483 // ----------------------------------------------------------------------------
2484 // alpha channel support
2485 // ----------------------------------------------------------------------------
2487 static bool AlphaBlt(HDC hdcDst
,
2488 int x
, int y
, int width
, int height
,
2489 int srcX
, int srcY
, HDC hdcSrc
,
2490 const wxBitmap
& bmp
)
2492 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2493 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2495 // do we have AlphaBlend() and company in the headers?
2496 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2497 // yes, now try to see if we have it during run-time
2498 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2499 HDC
,int,int,int,int,
2502 // bitmaps can be drawn only from GUI thread so there is no need to
2503 // protect this static variable from multiple threads
2504 static bool s_triedToLoad
= false;
2505 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2506 if ( !s_triedToLoad
)
2508 s_triedToLoad
= true;
2510 // don't give errors about the DLL being unavailable, we're
2511 // prepared to handle this
2514 wxDynamicLibrary
dll(_T("msimg32.dll"));
2515 if ( dll
.IsLoaded() )
2517 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2518 if ( pfnAlphaBlend
)
2520 // we must keep the DLL loaded if we want to be able to
2521 // call AlphaBlend() so just never unload it at all, not a
2528 if ( pfnAlphaBlend
)
2531 bf
.BlendOp
= AC_SRC_OVER
;
2533 bf
.SourceConstantAlpha
= 0xff;
2534 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2536 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2537 hdcSrc
, srcX
, srcY
, width
, height
,
2540 // skip wxAlphaBlend() call below
2544 wxLogLastError(_T("AlphaBlend"));
2546 #endif // defined(AC_SRC_OVER)
2548 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2550 #ifdef wxHAVE_RAW_BITMAP
2551 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2554 #else // !wxHAVE_RAW_BITMAP
2555 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2556 // alpha but at least something will be shown like this)
2559 #endif // wxHAVE_RAW_BITMAP
2563 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2564 #ifdef wxHAVE_RAW_BITMAP
2567 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int w
, int h
, int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2569 // get the destination DC pixels
2570 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2572 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2574 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, 0, 0, SRCCOPY
) )
2576 wxLogLastError(_T("BitBlt"));
2579 // combine them with the source bitmap using alpha
2580 wxAlphaPixelData
dataDst(bmpDst
),
2581 dataSrc((wxBitmap
&)bmpSrc
);
2583 wxCHECK_RET( dataDst
&& dataSrc
,
2584 _T("failed to get raw data in wxAlphaBlend") );
2586 wxAlphaPixelData::Iterator
pDst(dataDst
),
2589 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2591 for ( int y
= 0; y
< h
; y
++ )
2593 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2594 pSrcRowStart
= pSrc
;
2596 for ( int x
= 0; x
< w
; x
++ )
2598 // note that source bitmap uses premultiplied alpha (as required by
2599 // the real AlphaBlend)
2600 const unsigned beta
= 255 - pSrc
.Alpha();
2602 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2603 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2604 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2610 pDst
= pDstRowStart
;
2611 pSrc
= pSrcRowStart
;
2612 pDst
.OffsetY(dataDst
, 1);
2613 pSrc
.OffsetY(dataSrc
, 1);
2616 // and finally blit them back to the destination DC
2617 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2619 wxLogLastError(_T("BitBlt"));
2623 #endif // #ifdef wxHAVE_RAW_BITMAP