1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dc.cpp
3 // Purpose: wxDC class for MSW port
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/window.h"
32 #include "wx/dialog.h"
34 #include "wx/bitmap.h"
35 #include "wx/dcmemory.h"
40 #include "wx/sysopt.h"
41 #include "wx/dcprint.h"
42 #include "wx/module.h"
43 #include "wx/dynload.h"
45 #ifdef wxHAVE_RAW_BITMAP
46 #include "wx/rawbmp.h"
51 #include "wx/msw/wrapcdlg.h"
57 #define AC_SRC_ALPHA 1
60 /* Quaternary raster codes */
62 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
65 // apparently with MicroWindows it is possible that HDC is 0 so we have to
66 // check for this ourselves
68 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
69 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
71 #define WXMICROWIN_CHECK_HDC
72 #define WXMICROWIN_CHECK_HDC_RET(x)
75 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxDCBase
)
77 // ---------------------------------------------------------------------------
79 // ---------------------------------------------------------------------------
81 static const int VIEWPORT_EXTENT
= 1000;
83 static const int MM_POINTS
= 9;
84 static const int MM_METRIC
= 10;
86 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
87 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
88 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
90 // ----------------------------------------------------------------------------
91 // macros for logical <-> device coords conversion
92 // ----------------------------------------------------------------------------
95 We currently let Windows do all the translations itself so these macros are
96 not really needed (any more) but keep them to enhance readability of the
97 code by allowing to see where are the logical and where are the device
102 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
103 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
104 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
105 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
107 #define XLOG2DEV(x) (x)
108 #define YLOG2DEV(y) (y)
109 #define XDEV2LOG(x) (x)
110 #define YDEV2LOG(y) (y)
113 // ---------------------------------------------------------------------------
115 // ---------------------------------------------------------------------------
117 // convert degrees to radians
118 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
120 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
122 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
123 // to pass it to this function but as we already have it at the point
124 // of call anyhow we do
126 // return true if we could draw the bitmap in one way or the other, false
128 static bool AlphaBlt(HDC hdcDst
,
129 int x
, int y
, int w
, int h
,
130 int srcX
, int srcY
, HDC hdcSrc
,
131 const wxBitmap
& bmpSrc
);
133 #ifdef wxHAVE_RAW_BITMAP
135 // our (limited) AlphaBlend() replacement for Windows versions not providing it
137 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
,
138 int srcX
, int srcY
, const wxBitmap
& bmp
);
140 #endif // wxHAVE_RAW_BITMAP
142 // ----------------------------------------------------------------------------
144 // ----------------------------------------------------------------------------
146 // instead of duplicating the same code which sets and then restores text
147 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
148 // encapsulate this in a small helper class
150 // wxColourChanger: changes the text colours in the ctor if required and
151 // restores them in the dtor
152 class wxColourChanger
155 wxColourChanger(wxDC
& dc
);
161 COLORREF m_colFgOld
, m_colBgOld
;
165 DECLARE_NO_COPY_CLASS(wxColourChanger
)
168 // this class saves the old stretch blit mode during its life time
169 class StretchBltModeChanger
172 StretchBltModeChanger(HDC hdc
,
173 int WXUNUSED_IN_WINCE(mode
))
177 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
179 wxLogLastError(_T("SetStretchBltMode"));
183 ~StretchBltModeChanger()
186 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
187 wxLogLastError(_T("SetStretchBltMode"));
196 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
199 // ===========================================================================
201 // ===========================================================================
203 // ----------------------------------------------------------------------------
205 // ----------------------------------------------------------------------------
207 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
209 const wxBrush
& brush
= dc
.GetBrush();
210 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
212 HDC hdc
= GetHdcOf(dc
);
213 m_colFgOld
= ::GetTextColor(hdc
);
214 m_colBgOld
= ::GetBkColor(hdc
);
216 // note that Windows convention is opposite to wxWidgets one, this is
217 // why text colour becomes the background one and vice versa
218 const wxColour
& colFg
= dc
.GetTextForeground();
221 ::SetBkColor(hdc
, colFg
.GetPixel());
224 const wxColour
& colBg
= dc
.GetTextBackground();
227 ::SetTextColor(hdc
, colBg
.GetPixel());
231 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
234 // flag which telsl us to undo changes in the dtor
239 // nothing done, nothing to undo
244 wxColourChanger::~wxColourChanger()
248 // restore the colours we changed
249 HDC hdc
= GetHdcOf(m_dc
);
251 ::SetBkMode(hdc
, TRANSPARENT
);
252 ::SetTextColor(hdc
, m_colFgOld
);
253 ::SetBkColor(hdc
, m_colBgOld
);
257 // ---------------------------------------------------------------------------
259 // ---------------------------------------------------------------------------
265 SelectOldObjects(m_hDC
);
267 // if we own the HDC, we delete it, otherwise we just release it
271 ::DeleteDC(GetHdc());
273 else // we don't own our HDC
277 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
281 // Must have been a wxScreenDC
282 ::ReleaseDC((HWND
) NULL
, GetHdc());
288 // This will select current objects out of the DC,
289 // which is what you have to do before deleting the
291 void wxDC::SelectOldObjects(WXHDC dc
)
297 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
299 if (m_selectedBitmap
.Ok())
301 m_selectedBitmap
.SetSelectedInto(NULL
);
308 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
313 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
318 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
325 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
328 #endif // wxUSE_PALETTE
331 m_brush
= wxNullBrush
;
334 m_palette
= wxNullPalette
;
335 #endif // wxUSE_PALETTE
337 m_backgroundBrush
= wxNullBrush
;
338 m_selectedBitmap
= wxNullBitmap
;
341 // ---------------------------------------------------------------------------
343 // ---------------------------------------------------------------------------
345 void wxDC::UpdateClipBox()
350 ::GetClipBox(GetHdc(), &rect
);
352 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
353 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
354 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
355 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
359 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
361 // check if we should try to retrieve the clipping region possibly not set
362 // by our SetClippingRegion() but preset by Windows:this can only happen
363 // when we're associated with an existing HDC usign SetHDC(), see there
364 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
366 wxDC
*self
= wxConstCast(this, wxDC
);
367 self
->UpdateClipBox();
369 if ( !m_clipX1
&& !m_clipX2
)
370 self
->m_clipping
= false;
373 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
376 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
377 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
379 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
383 // note that we combine the new clipping region with the existing one: this
384 // is compatible with what the other ports do and is the documented
385 // behaviour now (starting with 2.3.3)
386 #if defined(__WXWINCE__)
388 if ( !::GetClipBox(GetHdc(), &rectClip
) )
391 // GetClipBox returns logical coordinates, so transform to device
392 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
393 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
394 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
395 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
397 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
398 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
399 rectClip
.right
, rectClip
.bottom
);
401 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
403 ::SelectClipRgn(GetHdc(), hrgnDest
);
406 ::DeleteObject(hrgnClipOld
);
407 ::DeleteObject(hrgnDest
);
409 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
411 wxLogLastError(_T("ExtSelectClipRgn"));
415 #endif // WinCE/!WinCE
422 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
424 // the region coords are always the device ones, so do the translation
427 // FIXME: possible +/-1 error here, to check!
428 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
430 LogicalToDeviceX(x
+ w
),
431 LogicalToDeviceY(y
+ h
));
434 wxLogLastError(_T("CreateRectRgn"));
438 SetClippingHrgn((WXHRGN
)hrgn
);
440 ::DeleteObject(hrgn
);
444 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
446 SetClippingHrgn(region
.GetHRGN());
449 void wxDC::DestroyClippingRegion()
453 if (m_clipping
&& m_hDC
)
455 // TODO: this should restore the previous clipping region,
456 // so that OnPaint processing works correctly, and the update
457 // clipping region doesn't get destroyed after the first
458 // DestroyClippingRegion.
459 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
460 ::SelectClipRgn(GetHdc(), rgn
);
464 wxDCBase::DestroyClippingRegion();
467 // ---------------------------------------------------------------------------
468 // query capabilities
469 // ---------------------------------------------------------------------------
471 bool wxDC::CanDrawBitmap() const
476 bool wxDC::CanGetTextExtent() const
478 #ifdef __WXMICROWIN__
479 // TODO Extend MicroWindows' GetDeviceCaps function
482 // What sort of display is it?
483 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
485 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
489 int wxDC::GetDepth() const
491 WXMICROWIN_CHECK_HDC_RET(16)
493 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
496 // ---------------------------------------------------------------------------
498 // ---------------------------------------------------------------------------
507 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
511 // No, I think we should simply ignore this if printing on e.g.
513 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
514 if (!m_selectedBitmap
.Ok())
517 rect
.left
= 0; rect
.top
= 0;
518 rect
.right
= m_selectedBitmap
.GetWidth();
519 rect
.bottom
= m_selectedBitmap
.GetHeight();
523 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
526 DWORD colour
= ::GetBkColor(GetHdc());
527 HBRUSH brush
= ::CreateSolidBrush(colour
);
528 ::FillRect(GetHdc(), &rect
, brush
);
529 ::DeleteObject(brush
);
532 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
533 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
535 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
537 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
538 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
539 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
540 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
544 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
545 wxCoord
WXUNUSED_IN_WINCE(y
),
546 const wxColour
& WXUNUSED_IN_WINCE(col
),
547 int WXUNUSED_IN_WINCE(style
))
552 WXMICROWIN_CHECK_HDC_RET(false)
554 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
556 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
557 : FLOODFILLBORDER
) ) ;
560 // quoting from the MSDN docs:
562 // Following are some of the reasons this function might fail:
564 // * The filling could not be completed.
565 // * The specified point has the boundary color specified by the
566 // crColor parameter (if FLOODFILLBORDER was requested).
567 // * The specified point does not have the color specified by
568 // crColor (if FLOODFILLSURFACE was requested)
569 // * The point is outside the clipping region that is, it is not
570 // visible on the device.
572 wxLogLastError(wxT("ExtFloodFill"));
575 CalcBoundingBox(x
, y
);
581 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
583 WXMICROWIN_CHECK_HDC_RET(false)
585 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
587 // get the color of the pixel
588 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
590 wxRGBToColour(*col
, pixelcolor
);
595 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
599 wxCoord x1
= x
-VIEWPORT_EXTENT
;
600 wxCoord y1
= y
-VIEWPORT_EXTENT
;
601 wxCoord x2
= x
+VIEWPORT_EXTENT
;
602 wxCoord y2
= y
+VIEWPORT_EXTENT
;
604 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
605 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
607 CalcBoundingBox(x1
, y1
);
608 CalcBoundingBox(x2
, y2
);
611 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
615 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
617 CalcBoundingBox(x1
, y1
);
618 CalcBoundingBox(x2
, y2
);
621 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
622 // and ending at (x2, y2)
623 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
624 wxCoord x2
, wxCoord y2
,
625 wxCoord xc
, wxCoord yc
)
628 // Slower emulation since WinCE doesn't support Pie and Arc
629 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
630 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
631 if( y1
>yc
) sa
= -sa
; // below center
632 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
633 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
638 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
642 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
643 wxCoord r
= (wxCoord
)radius
;
645 // treat the special case of full circle separately
646 if ( x1
== x2
&& y1
== y2
)
648 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
652 wxCoord xx1
= XLOG2DEV(x1
);
653 wxCoord yy1
= YLOG2DEV(y1
);
654 wxCoord xx2
= XLOG2DEV(x2
);
655 wxCoord yy2
= YLOG2DEV(y2
);
656 wxCoord xxc
= XLOG2DEV(xc
);
657 wxCoord yyc
= YLOG2DEV(yc
);
658 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
660 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
661 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
662 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
663 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
665 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
667 // Have to add 1 to bottom-right corner of rectangle
668 // to make semi-circles look right (crooked line otherwise).
669 // Unfortunately this is not a reliable method, depends
670 // on the size of shape.
671 // TODO: figure out why this happens!
672 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
676 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
679 CalcBoundingBox(xc
- r
, yc
- r
);
680 CalcBoundingBox(xc
+ r
, yc
+ r
);
684 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
685 wxCoord width
, wxCoord height
)
689 wxCoord x2
= x1
+ width
,
692 #if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__)
700 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
702 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
704 #else // Symantec-MicroWin
706 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
707 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
708 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
709 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
710 ::SetROP2(GetHdc(), R2_COPYPEN
);
711 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
712 MoveToEx(GetHdc(), x1
, y1
, NULL
);
713 LineTo(GetHdc(), x2
, y2
);
714 MoveToEx(GetHdc(), x2
, y1
, NULL
);
715 LineTo(GetHdc(), x1
, y2
);
716 ::SelectObject(GetHdc(), hPenOld
);
717 ::SelectObject(GetHdc(), hBrushOld
);
718 ::DeleteObject(blackPen
);
719 #endif // Win32/Symantec-MicroWin
721 CalcBoundingBox(x1
, y1
);
722 CalcBoundingBox(x2
, y2
);
725 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
729 COLORREF color
= 0x00ffffff;
732 color
= m_pen
.GetColour().GetPixel();
735 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
737 CalcBoundingBox(x
, y
);
740 void wxDC::DoDrawPolygon(int n
,
744 int WXUNUSED_IN_WINCE(fillStyle
))
748 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
750 // Do things less efficiently if we have offsets
751 if (xoffset
!= 0 || yoffset
!= 0)
753 POINT
*cpoints
= new POINT
[n
];
755 for (i
= 0; i
< n
; i
++)
757 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
758 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
760 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
763 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
765 (void)Polygon(GetHdc(), cpoints
, n
);
767 SetPolyFillMode(GetHdc(),prev
);
774 for (i
= 0; i
< n
; i
++)
775 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
778 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
780 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
782 SetPolyFillMode(GetHdc(),prev
);
788 wxDC::DoDrawPolyPolygon(int n
,
796 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
800 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
802 for (i
= cnt
= 0; i
< n
; i
++)
805 // Do things less efficiently if we have offsets
806 if (xoffset
!= 0 || yoffset
!= 0)
808 POINT
*cpoints
= new POINT
[cnt
];
809 for (i
= 0; i
< cnt
; i
++)
811 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
812 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
814 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
817 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
819 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
821 SetPolyFillMode(GetHdc(),prev
);
827 for (i
= 0; i
< cnt
; i
++)
828 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
831 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
833 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
835 SetPolyFillMode(GetHdc(),prev
);
842 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
846 // Do things less efficiently if we have offsets
847 if (xoffset
!= 0 || yoffset
!= 0)
849 POINT
*cpoints
= new POINT
[n
];
851 for (i
= 0; i
< n
; i
++)
853 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
854 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
856 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
858 (void)Polyline(GetHdc(), cpoints
, n
);
864 for (i
= 0; i
< n
; i
++)
865 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
867 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
871 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
875 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
877 wxCoord x2
= x
+ width
;
878 wxCoord y2
= y
+ height
;
880 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
883 rect
.left
= XLOG2DEV(x
);
884 rect
.top
= YLOG2DEV(y
);
885 rect
.right
= XLOG2DEV(x2
);
886 rect
.bottom
= YLOG2DEV(y2
);
887 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
891 // Windows draws the filled rectangles without outline (i.e. drawn with a
892 // transparent pen) one pixel smaller in both directions and we want them
893 // to have the same size regardless of which pen is used - adjust
895 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
896 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
898 // Apparently not needed for WinCE (see e.g. Life! demo)
905 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
909 CalcBoundingBox(x
, y
);
910 CalcBoundingBox(x2
, y2
);
913 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
917 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
919 // Now, a negative radius value is interpreted to mean
920 // 'the proportion of the smallest X or Y dimension'
924 double smallest
= (width
< height
) ? width
: height
;
925 radius
= (- radius
* smallest
);
928 wxCoord x2
= (x
+width
);
929 wxCoord y2
= (y
+height
);
931 // Windows draws the filled rectangles without outline (i.e. drawn with a
932 // transparent pen) one pixel smaller in both directions and we want them
933 // to have the same size regardless of which pen is used - adjust
934 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
940 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
941 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
943 CalcBoundingBox(x
, y
);
944 CalcBoundingBox(x2
, y2
);
947 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
951 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
953 wxCoord x2
= (x
+width
);
954 wxCoord y2
= (y
+height
);
956 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
958 CalcBoundingBox(x
, y
);
959 CalcBoundingBox(x2
, y2
);
963 void wxDC::DoDrawSpline(wxList
*points
)
966 // WinCE does not support ::PolyBezier so use generic version
967 wxDCBase::DoDrawSpline(points
);
969 // quadratic b-spline to cubic bezier spline conversion
971 // quadratic spline with control points P0,P1,P2
972 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
974 // bezier spline with control points B0,B1,B2,B3
975 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
977 // control points of bezier spline calculated from b-spline
979 // B1 = (2*P1 + P0)/3
980 // B2 = (2*P1 + P2)/3
985 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
987 const size_t n_points
= points
->GetCount();
988 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
990 const size_t n_bezier_points
= n_points
* 3 + 1;
991 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
992 size_t bezier_pos
= 0;
993 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
995 wxList::compatibility_iterator node
= points
->GetFirst();
996 wxPoint
*p
= (wxPoint
*)node
->GetData();
997 lppt
[ bezier_pos
].x
= x1
= p
->x
;
998 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1000 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1003 node
= node
->GetNext();
1004 p
= (wxPoint
*)node
->GetData();
1008 cx1
= ( x1
+ x2
) / 2;
1009 cy1
= ( y1
+ y2
) / 2;
1010 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1011 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1013 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1017 while ((node
= node
->GetNext()) != NULL
)
1019 while ((node
= node
->GetNext()))
1020 #endif // !wxUSE_STL
1022 p
= (wxPoint
*)node
->GetData();
1027 cx4
= (x1
+ x2
) / 2;
1028 cy4
= (y1
+ y2
) / 2;
1029 // B0 is B3 of previous segment
1031 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1032 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1035 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1036 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1039 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1040 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1046 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1048 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1049 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1051 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1054 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1061 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1062 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1065 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1068 WXMICROWIN_CHECK_HDC
1070 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1075 int rx1
= XLOG2DEV(x
+w
/2);
1076 int ry1
= YLOG2DEV(y
+h
/2);
1083 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1084 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1085 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1086 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1088 // draw pie with NULL_PEN first and then outline otherwise a line is
1089 // drawn from the start and end points to the centre
1090 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1093 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1094 rx1
, ry1
, rx2
, ry2
);
1098 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1099 rx1
, ry1
-1, rx2
, ry2
-1);
1102 ::SelectObject(GetHdc(), hpenOld
);
1104 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1105 rx1
, ry1
, rx2
, ry2
);
1107 CalcBoundingBox(x
, y
);
1108 CalcBoundingBox(x2
, y2
);
1112 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1114 WXMICROWIN_CHECK_HDC
1116 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1119 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1121 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1124 CalcBoundingBox(x
, y
);
1125 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1128 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1130 WXMICROWIN_CHECK_HDC
1132 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1134 int width
= bmp
.GetWidth(),
1135 height
= bmp
.GetHeight();
1137 HBITMAP hbmpMask
= 0;
1140 HPALETTE oldPal
= 0;
1141 #endif // wxUSE_PALETTE
1143 if ( bmp
.HasAlpha() )
1146 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1148 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1154 wxMask
*mask
= bmp
.GetMask();
1156 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1160 // don't give assert here because this would break existing
1161 // programs - just silently ignore useMask parameter
1168 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1170 // On some systems, MaskBlt succeeds yet is much much slower
1171 // than the wxWidgets fall-back implementation. So we need
1172 // to be able to switch this on and off at runtime.
1174 #if wxUSE_SYSTEM_OPTIONS
1175 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1179 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1180 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1182 wxPalette
*pal
= bmp
.GetPalette();
1183 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1185 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1186 ::RealizePalette(hdcMem
);
1188 #endif // wxUSE_PALETTE
1190 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1193 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1197 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1198 #endif // wxUSE_PALETTE
1200 ::SelectObject(hdcMem
, hOldBitmap
);
1207 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1210 memDC
.SelectObject(bmp
);
1212 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1214 memDC
.SelectObject(wxNullBitmap
);
1217 else // no mask, just use BitBlt()
1220 HDC memdc
= ::CreateCompatibleDC( cdc
);
1221 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1223 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1225 COLORREF old_textground
= ::GetTextColor(GetHdc());
1226 COLORREF old_background
= ::GetBkColor(GetHdc());
1227 if (m_textForegroundColour
.Ok())
1229 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1231 if (m_textBackgroundColour
.Ok())
1233 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1237 wxPalette
*pal
= bmp
.GetPalette();
1238 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1240 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1241 ::RealizePalette(memdc
);
1243 #endif // wxUSE_PALETTE
1245 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1246 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1250 ::SelectPalette(memdc
, oldPal
, FALSE
);
1251 #endif // wxUSE_PALETTE
1253 ::SelectObject( memdc
, hOldBitmap
);
1254 ::DeleteDC( memdc
);
1256 ::SetTextColor(GetHdc(), old_textground
);
1257 ::SetBkColor(GetHdc(), old_background
);
1261 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1263 WXMICROWIN_CHECK_HDC
1265 DrawAnyText(text
, x
, y
);
1267 // update the bounding box
1268 CalcBoundingBox(x
, y
);
1271 GetTextExtent(text
, &w
, &h
);
1272 CalcBoundingBox(x
+ w
, y
+ h
);
1275 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1277 WXMICROWIN_CHECK_HDC
1279 // prepare for drawing the text
1280 if ( m_textForegroundColour
.Ok() )
1281 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1283 DWORD old_background
= 0;
1284 if ( m_textBackgroundColour
.Ok() )
1286 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1289 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1293 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1294 text
.c_str(), text
.length(), NULL
) == 0 )
1296 wxLogLastError(wxT("TextOut"));
1299 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1300 text
.c_str(), text
.length()) == 0 )
1302 wxLogLastError(wxT("TextOut"));
1306 // restore the old parameters (text foreground colour may be left because
1307 // it never is set to anything else, but background should remain
1308 // transparent even if we just drew an opaque string)
1309 if ( m_textBackgroundColour
.Ok() )
1310 (void)SetBkColor(GetHdc(), old_background
);
1312 SetBkMode(GetHdc(), TRANSPARENT
);
1315 void wxDC::DoDrawRotatedText(const wxString
& text
,
1316 wxCoord x
, wxCoord y
,
1319 WXMICROWIN_CHECK_HDC
1321 // we test that we have some font because otherwise we should still use the
1322 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1323 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1324 // font for drawing rotated fonts unfortunately)
1325 if ( (angle
== 0.0) && m_font
.Ok() )
1327 DoDrawText(text
, x
, y
);
1329 #ifndef __WXMICROWIN__
1332 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1333 // because it's not TrueType and so can't have non zero
1334 // orientation/escapement under Win9x
1335 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1336 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1338 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1340 wxLogLastError(wxT("GetObject(hfont)"));
1343 // GDI wants the angle in tenth of degree
1344 long angle10
= (long)(angle
* 10);
1345 lf
.lfEscapement
= angle10
;
1346 lf
. lfOrientation
= angle10
;
1348 hfont
= ::CreateFontIndirect(&lf
);
1351 wxLogLastError(wxT("CreateFont"));
1355 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1357 DrawAnyText(text
, x
, y
);
1359 (void)::SelectObject(GetHdc(), hfontOld
);
1360 (void)::DeleteObject(hfont
);
1363 // call the bounding box by adding all four vertices of the rectangle
1364 // containing the text to it (simpler and probably not slower than
1365 // determining which of them is really topmost/leftmost/...)
1367 GetTextExtent(text
, &w
, &h
);
1369 double rad
= DegToRad(angle
);
1371 // "upper left" and "upper right"
1372 CalcBoundingBox(x
, y
);
1373 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1375 // "bottom left" and "bottom right"
1376 x
+= (wxCoord
)(h
*sin(rad
));
1377 y
+= (wxCoord
)(h
*cos(rad
));
1378 CalcBoundingBox(x
, y
);
1379 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1384 // ---------------------------------------------------------------------------
1386 // ---------------------------------------------------------------------------
1390 void wxDC::DoSelectPalette(bool realize
)
1392 WXMICROWIN_CHECK_HDC
1394 // Set the old object temporarily, in case the assignment deletes an object
1395 // that's not yet selected out.
1398 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1402 if ( m_palette
.Ok() )
1404 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1405 GetHpaletteOf(m_palette
),
1408 m_oldPalette
= (WXHPALETTE
) oldPal
;
1411 ::RealizePalette(GetHdc());
1415 void wxDC::SetPalette(const wxPalette
& palette
)
1419 m_palette
= palette
;
1420 DoSelectPalette(true);
1424 void wxDC::InitializePalette()
1426 if ( wxDisplayDepth() <= 8 )
1428 // look for any window or parent that has a custom palette. If any has
1429 // one then we need to use it in drawing operations
1430 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1432 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1433 if ( m_hasCustomPalette
)
1435 m_palette
= win
->GetPalette();
1437 // turn on MSW translation for this palette
1443 #endif // wxUSE_PALETTE
1445 // SetFont/Pen/Brush() really ask to be implemented as a single template
1446 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1448 void wxDC::SetFont(const wxFont
& font
)
1450 WXMICROWIN_CHECK_HDC
1452 if ( font
== m_font
)
1457 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1458 if ( hfont
== HGDI_ERROR
)
1460 wxLogLastError(_T("SelectObject(font)"));
1465 m_oldFont
= (WXHPEN
)hfont
;
1470 else // invalid font, reset the current font
1474 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1476 wxLogLastError(_T("SelectObject(old font)"));
1482 m_font
= wxNullFont
;
1486 void wxDC::SetPen(const wxPen
& pen
)
1488 WXMICROWIN_CHECK_HDC
1495 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1496 if ( hpen
== HGDI_ERROR
)
1498 wxLogLastError(_T("SelectObject(pen)"));
1503 m_oldPen
= (WXHPEN
)hpen
;
1508 else // invalid pen, reset the current pen
1512 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1514 wxLogLastError(_T("SelectObject(old pen)"));
1524 void wxDC::SetBrush(const wxBrush
& brush
)
1526 WXMICROWIN_CHECK_HDC
1528 if ( brush
== m_brush
)
1533 // we must make sure the brush is aligned with the logical coordinates
1534 // before selecting it
1535 wxBitmap
*stipple
= brush
.GetStipple();
1536 if ( stipple
&& stipple
->Ok() )
1538 if ( !::SetBrushOrgEx
1541 m_deviceOriginX
% stipple
->GetWidth(),
1542 m_deviceOriginY
% stipple
->GetHeight(),
1543 NULL
// [out] previous brush origin
1546 wxLogLastError(_T("SetBrushOrgEx()"));
1550 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1551 if ( hbrush
== HGDI_ERROR
)
1553 wxLogLastError(_T("SelectObject(brush)"));
1558 m_oldBrush
= (WXHPEN
)hbrush
;
1563 else // invalid brush, reset the current brush
1567 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1569 wxLogLastError(_T("SelectObject(old brush)"));
1575 m_brush
= wxNullBrush
;
1579 void wxDC::SetBackground(const wxBrush
& brush
)
1581 WXMICROWIN_CHECK_HDC
1583 m_backgroundBrush
= brush
;
1585 if ( m_backgroundBrush
.Ok() )
1587 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1591 void wxDC::SetBackgroundMode(int mode
)
1593 WXMICROWIN_CHECK_HDC
1595 m_backgroundMode
= mode
;
1597 // SetBackgroundColour now only refers to text background
1598 // and m_backgroundMode is used there
1601 void wxDC::SetLogicalFunction(int function
)
1603 WXMICROWIN_CHECK_HDC
1605 m_logicalFunction
= function
;
1610 void wxDC::SetRop(WXHDC dc
)
1612 if ( !dc
|| m_logicalFunction
< 0 )
1617 switch (m_logicalFunction
)
1619 case wxCLEAR
: rop
= R2_BLACK
; break;
1620 case wxXOR
: rop
= R2_XORPEN
; break;
1621 case wxINVERT
: rop
= R2_NOT
; break;
1622 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1623 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1624 case wxCOPY
: rop
= R2_COPYPEN
; break;
1625 case wxAND
: rop
= R2_MASKPEN
; break;
1626 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1627 case wxNO_OP
: rop
= R2_NOP
; break;
1628 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1629 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1630 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1631 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1632 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1633 case wxOR
: rop
= R2_MERGEPEN
; break;
1634 case wxSET
: rop
= R2_WHITE
; break;
1637 wxFAIL_MSG( wxT("unsupported logical function") );
1641 SetROP2(GetHdc(), rop
);
1644 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1646 // We might be previewing, so return true to let it continue.
1654 void wxDC::StartPage()
1658 void wxDC::EndPage()
1662 // ---------------------------------------------------------------------------
1664 // ---------------------------------------------------------------------------
1666 wxCoord
wxDC::GetCharHeight() const
1668 WXMICROWIN_CHECK_HDC_RET(0)
1670 TEXTMETRIC lpTextMetric
;
1672 GetTextMetrics(GetHdc(), &lpTextMetric
);
1674 return lpTextMetric
.tmHeight
;
1677 wxCoord
wxDC::GetCharWidth() const
1679 WXMICROWIN_CHECK_HDC_RET(0)
1681 TEXTMETRIC lpTextMetric
;
1683 GetTextMetrics(GetHdc(), &lpTextMetric
);
1685 return lpTextMetric
.tmAveCharWidth
;
1688 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1689 wxCoord
*descent
, wxCoord
*externalLeading
,
1692 #ifdef __WXMICROWIN__
1697 if (descent
) *descent
= 0;
1698 if (externalLeading
) *externalLeading
= 0;
1701 #endif // __WXMICROWIN__
1706 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1708 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1710 else // don't change the font
1718 ::GetTextExtentPoint32(GetHdc(), string
, string
.length(), &sizeRect
);
1719 GetTextMetrics(GetHdc(), &tm
);
1726 *descent
= tm
.tmDescent
;
1727 if (externalLeading
)
1728 *externalLeading
= tm
.tmExternalLeading
;
1732 ::SelectObject(GetHdc(), hfontOld
);
1737 // Each element of the array will be the width of the string up to and
1738 // including the coresoponding character in text.
1740 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1742 static int maxLenText
= -1;
1743 static int maxWidth
= -1;
1746 int stlen
= text
.length();
1748 if (maxLenText
== -1)
1750 // Win9x and WinNT+ have different limits
1751 int version
= wxGetOsVersion();
1752 maxLenText
= version
== wxWINDOWS_NT
? 65535 : 8192;
1753 maxWidth
= version
== wxWINDOWS_NT
? INT_MAX
: 32767;
1757 widths
.Add(0, stlen
); // fill the array with zeros
1761 if (!::GetTextExtentExPoint(GetHdc(),
1762 text
.c_str(), // string to check
1763 wxMin(stlen
, maxLenText
),
1765 &fit
, // [out] count of chars
1767 &widths
[0], // array to fill
1771 wxLogLastError(wxT("GetTextExtentExPoint"));
1781 void wxDC::SetMapMode(int mode
)
1783 WXMICROWIN_CHECK_HDC
1785 m_mappingMode
= mode
;
1787 if ( mode
== wxMM_TEXT
)
1790 m_logicalScaleY
= 1.0;
1792 else // need to do some calculations
1794 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1795 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1796 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1797 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1799 if ( (mm_width
== 0) || (mm_height
== 0) )
1801 // we can't calculate mm2pixels[XY] then!
1805 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1806 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1811 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1812 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1816 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1817 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1821 m_logicalScaleX
= mm2pixelsX
;
1822 m_logicalScaleY
= mm2pixelsY
;
1826 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1827 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1831 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1835 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1836 // cases we could do with MM_TEXT and in the remaining 0.9% with
1837 // MM_ISOTROPIC (TODO!)
1839 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1841 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1842 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1844 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1845 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1847 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1848 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1852 void wxDC::SetUserScale(double x
, double y
)
1854 WXMICROWIN_CHECK_HDC
1856 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1862 this->SetMapMode(m_mappingMode
);
1865 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1866 bool WXUNUSED_IN_WINCE(yBottomUp
))
1868 WXMICROWIN_CHECK_HDC
1871 int signX
= xLeftRight
? 1 : -1,
1872 signY
= yBottomUp
? -1 : 1;
1874 if ( signX
!= m_signX
|| signY
!= m_signY
)
1879 SetMapMode(m_mappingMode
);
1884 void wxDC::SetSystemScale(double x
, double y
)
1886 WXMICROWIN_CHECK_HDC
1888 if ( x
== m_scaleX
&& y
== m_scaleY
)
1895 SetMapMode(m_mappingMode
);
1899 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1901 WXMICROWIN_CHECK_HDC
1903 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1906 m_logicalOriginX
= x
;
1907 m_logicalOriginY
= y
;
1910 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1914 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1916 WXMICROWIN_CHECK_HDC
1918 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1921 m_deviceOriginX
= x
;
1922 m_deviceOriginY
= y
;
1924 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1927 // ---------------------------------------------------------------------------
1928 // coordinates transformations
1929 // ---------------------------------------------------------------------------
1931 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1933 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
1936 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1938 // axis orientation is not taken into account for conversion of a distance
1939 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
1942 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1944 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
1947 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1949 // axis orientation is not taken into account for conversion of a distance
1950 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
1953 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1955 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
1958 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1960 // axis orientation is not taken into account for conversion of a distance
1961 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
1964 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1966 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
1969 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1971 // axis orientation is not taken into account for conversion of a distance
1972 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
1975 // ---------------------------------------------------------------------------
1977 // ---------------------------------------------------------------------------
1979 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1980 wxCoord width
, wxCoord height
,
1981 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1982 int rop
, bool useMask
,
1983 wxCoord xsrcMask
, wxCoord ysrcMask
)
1985 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
1987 WXMICROWIN_CHECK_HDC_RET(false)
1989 // if either the source or destination has alpha channel, we must use
1990 // AlphaBlt() as other function don't handle it correctly
1991 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
1992 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
1993 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
1995 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
1996 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2000 wxMask
*mask
= NULL
;
2003 mask
= bmpSrc
.GetMask();
2005 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2007 // don't give assert here because this would break existing
2008 // programs - just silently ignore useMask parameter
2013 if (xsrcMask
== -1 && ysrcMask
== -1)
2015 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2018 COLORREF old_textground
= ::GetTextColor(GetHdc());
2019 COLORREF old_background
= ::GetBkColor(GetHdc());
2020 if (m_textForegroundColour
.Ok())
2022 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2024 if (m_textBackgroundColour
.Ok())
2026 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2032 case wxXOR
: dwRop
= SRCINVERT
; break;
2033 case wxINVERT
: dwRop
= DSTINVERT
; break;
2034 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2035 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2036 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2037 case wxSET
: dwRop
= WHITENESS
; break;
2038 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2039 case wxAND
: dwRop
= SRCAND
; break;
2040 case wxOR
: dwRop
= SRCPAINT
; break;
2041 case wxEQUIV
: dwRop
= 0x00990066; break;
2042 case wxNAND
: dwRop
= 0x007700E6; break;
2043 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2044 case wxCOPY
: dwRop
= SRCCOPY
; break;
2045 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2046 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2047 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2049 wxFAIL_MSG( wxT("unsupported logical function") );
2053 bool success
= false;
2058 // we want the part of the image corresponding to the mask to be
2059 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2060 // meaning of fg and bg is inverted which corresponds to wxWin notion
2061 // of the mask which is also contrary to the Windows one)
2063 // On some systems, MaskBlt succeeds yet is much much slower
2064 // than the wxWidgets fall-back implementation. So we need
2065 // to be able to switch this on and off at runtime.
2066 #if wxUSE_SYSTEM_OPTIONS
2067 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2073 xdest
, ydest
, width
, height
,
2076 (HBITMAP
)mask
->GetMaskBitmap(),
2078 MAKEROP4(dwRop
, DSTCOPY
)
2085 // Blit bitmap with mask
2088 HBITMAP buffer_bmap
;
2090 #if wxUSE_DC_CACHEING
2091 // create a temp buffer bitmap and DCs to access it and the mask
2092 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2093 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2095 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2096 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2098 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2101 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2102 #else // !wxUSE_DC_CACHEING
2103 // create a temp buffer bitmap and DCs to access it and the mask
2104 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2105 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2106 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2107 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2108 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2109 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2111 // copy dest to buffer
2112 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2113 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2115 wxLogLastError(wxT("BitBlt"));
2118 // copy src to buffer using selected raster op
2119 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2120 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2122 wxLogLastError(wxT("BitBlt"));
2125 // set masked area in buffer to BLACK (pixel value 0)
2126 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2127 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2128 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2129 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2131 wxLogLastError(wxT("BitBlt"));
2134 // set unmasked area in dest to BLACK
2135 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2136 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2137 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2138 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2140 wxLogLastError(wxT("BitBlt"));
2142 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2143 ::SetTextColor(GetHdc(), prevCol
);
2145 // OR buffer to dest
2146 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2147 (int)width
, (int)height
,
2148 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2151 wxLogLastError(wxT("BitBlt"));
2154 // tidy up temporary DCs and bitmap
2155 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2156 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2158 #if !wxUSE_DC_CACHEING
2160 ::DeleteDC(dc_mask
);
2161 ::DeleteDC(dc_buffer
);
2162 ::DeleteObject(buffer_bmap
);
2167 else // no mask, just BitBlt() it
2169 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2170 // use StretchBlt() if available and finally fall back to BitBlt()
2172 // FIXME: use appropriate WinCE functions
2174 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2175 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2180 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2182 &ds
) == sizeof(ds
) )
2184 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2186 // Figure out what co-ordinate system we're supposed to specify
2188 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2192 ysrc
= hDIB
- (ysrc
+ height
);
2195 if ( ::StretchDIBits(GetHdc(),
2201 (LPBITMAPINFO
)&ds
.dsBmih
,
2204 ) == (int)GDI_ERROR
)
2206 // On Win9x this API fails most (all?) of the time, so
2207 // logging it becomes quite distracting. Since it falls
2208 // back to the code below this is not really serious, so
2210 //wxLogLastError(wxT("StretchDIBits"));
2219 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2224 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2230 xdest
, ydest
, width
, height
,
2232 xsrc
, ysrc
, width
, height
,
2236 wxLogLastError(_T("StretchBlt"));
2250 (int)width
, (int)height
,
2256 wxLogLastError(_T("BitBlt"));
2265 ::SetTextColor(GetHdc(), old_textground
);
2266 ::SetBkColor(GetHdc(), old_background
);
2271 void wxDC::GetDeviceSize(int *width
, int *height
) const
2273 WXMICROWIN_CHECK_HDC
2276 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2278 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2281 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2283 WXMICROWIN_CHECK_HDC
2285 // if we implement it in terms of DoGetSize() instead of directly using the
2286 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2287 // will also work for wxWindowDC and wxClientDC even though their size is
2288 // not the same as the total size of the screen
2289 int wPixels
, hPixels
;
2290 DoGetSize(&wPixels
, &hPixels
);
2294 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2296 wxCHECK_RET( wTotal
, _T("0 width device?") );
2298 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2303 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2305 wxCHECK_RET( hTotal
, _T("0 height device?") );
2307 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2311 wxSize
wxDC::GetPPI() const
2313 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2315 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2316 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2318 return wxSize(x
, y
);
2321 // For use by wxWidgets only, unless custom units are required.
2322 void wxDC::SetLogicalScale(double x
, double y
)
2324 WXMICROWIN_CHECK_HDC
2326 m_logicalScaleX
= x
;
2327 m_logicalScaleY
= y
;
2330 // ----------------------------------------------------------------------------
2332 // ----------------------------------------------------------------------------
2334 #if wxUSE_DC_CACHEING
2337 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2338 * improve it in due course, either using arrays, or simply storing pointers to one
2339 * entry for the bitmap, and two for the DCs. -- JACS
2342 wxList
wxDC::sm_bitmapCache
;
2343 wxList
wxDC::sm_dcCache
;
2345 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2354 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2363 wxDCCacheEntry::~wxDCCacheEntry()
2366 ::DeleteObject((HBITMAP
) m_bitmap
);
2368 ::DeleteDC((HDC
) m_dc
);
2371 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2373 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2374 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2377 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2379 if (entry
->m_depth
== depth
)
2381 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2383 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2384 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2385 if ( !entry
->m_bitmap
)
2387 wxLogLastError(wxT("CreateCompatibleBitmap"));
2389 entry
->m_width
= w
; entry
->m_height
= h
;
2395 node
= node
->GetNext();
2397 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2400 wxLogLastError(wxT("CreateCompatibleBitmap"));
2402 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2403 AddToBitmapCache(entry
);
2407 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2409 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2410 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2413 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2415 // Don't return the same one as we already have
2416 if (!notThis
|| (notThis
!= entry
))
2418 if (entry
->m_depth
== depth
)
2424 node
= node
->GetNext();
2426 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2429 wxLogLastError(wxT("CreateCompatibleDC"));
2431 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2432 AddToDCCache(entry
);
2436 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2438 sm_bitmapCache
.Append(entry
);
2441 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2443 sm_dcCache
.Append(entry
);
2446 void wxDC::ClearCache()
2448 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2449 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2452 // Clean up cache at app exit
2453 class wxDCModule
: public wxModule
2456 virtual bool OnInit() { return true; }
2457 virtual void OnExit() { wxDC::ClearCache(); }
2460 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2463 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2465 #endif // wxUSE_DC_CACHEING
2467 // ----------------------------------------------------------------------------
2468 // alpha channel support
2469 // ----------------------------------------------------------------------------
2471 static bool AlphaBlt(HDC hdcDst
,
2472 int x
, int y
, int width
, int height
,
2473 int srcX
, int srcY
, HDC hdcSrc
,
2474 const wxBitmap
& bmp
)
2476 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2477 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2479 // do we have AlphaBlend() and company in the headers?
2480 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2481 // yes, now try to see if we have it during run-time
2482 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2483 HDC
,int,int,int,int,
2486 // bitmaps can be drawn only from GUI thread so there is no need to
2487 // protect this static variable from multiple threads
2488 static bool s_triedToLoad
= false;
2489 static AlphaBlend_t pfnAlphaBlend
= NULL
;
2490 if ( !s_triedToLoad
)
2492 s_triedToLoad
= true;
2494 // don't give errors about the DLL being unavailable, we're
2495 // prepared to handle this
2498 wxDynamicLibrary
dll(_T("msimg32.dll"));
2499 if ( dll
.IsLoaded() )
2501 pfnAlphaBlend
= (AlphaBlend_t
)dll
.GetSymbol(_T("AlphaBlend"));
2502 if ( pfnAlphaBlend
)
2504 // we must keep the DLL loaded if we want to be able to
2505 // call AlphaBlend() so just never unload it at all, not a
2512 if ( pfnAlphaBlend
)
2515 bf
.BlendOp
= AC_SRC_OVER
;
2517 bf
.SourceConstantAlpha
= 0xff;
2518 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2520 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2521 hdcSrc
, srcX
, srcY
, width
, height
,
2524 // skip wxAlphaBlend() call below
2528 wxLogLastError(_T("AlphaBlend"));
2531 wxUnusedVar(hdcSrc
);
2532 #endif // defined(AC_SRC_OVER)
2534 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2536 #ifdef wxHAVE_RAW_BITMAP
2537 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2540 #else // !wxHAVE_RAW_BITMAP
2541 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2542 // alpha but at least something will be shown like this)
2545 #endif // wxHAVE_RAW_BITMAP
2549 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2550 #ifdef wxHAVE_RAW_BITMAP
2553 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2555 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2557 // get the destination DC pixels
2558 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2560 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2562 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2564 wxLogLastError(_T("BitBlt"));
2567 // combine them with the source bitmap using alpha
2568 wxAlphaPixelData
dataDst(bmpDst
),
2569 dataSrc((wxBitmap
&)bmpSrc
);
2571 wxCHECK_RET( dataDst
&& dataSrc
,
2572 _T("failed to get raw data in wxAlphaBlend") );
2574 wxAlphaPixelData::Iterator
pDst(dataDst
),
2577 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2579 for ( int y
= 0; y
< h
; y
++ )
2581 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2582 pSrcRowStart
= pSrc
;
2584 for ( int x
= 0; x
< w
; x
++ )
2586 // note that source bitmap uses premultiplied alpha (as required by
2587 // the real AlphaBlend)
2588 const unsigned beta
= 255 - pSrc
.Alpha();
2590 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2591 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2592 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2598 pDst
= pDstRowStart
;
2599 pSrc
= pSrcRowStart
;
2600 pDst
.OffsetY(dataDst
, 1);
2601 pSrc
.OffsetY(dataSrc
, 1);
2604 // and finally blit them back to the destination DC
2605 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2607 wxLogLastError(_T("BitBlt"));
2611 #endif // #ifdef wxHAVE_RAW_BITMAP