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"
28 #include "wx/msw/wrapcdlg.h"
30 #include "wx/window.h"
33 #include "wx/dialog.h"
35 #include "wx/bitmap.h"
36 #include "wx/dcmemory.h"
39 #include "wx/dcprint.h"
40 #include "wx/module.h"
43 #include "wx/sysopt.h"
44 #include "wx/dynlib.h"
46 #ifdef wxHAVE_RAW_BITMAP
47 #include "wx/rawbmp.h"
57 #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
139 // our (limited) AlphaBlend() replacement for Windows versions not providing it
141 wxAlphaBlend(HDC hdcDst
, int x
, int y
, int w
, int h
,
142 int srcX
, int srcY
, const wxBitmap
& bmp
);
144 #endif // wxHAVE_RAW_BITMAP
146 // ----------------------------------------------------------------------------
148 // ----------------------------------------------------------------------------
150 // instead of duplicating the same code which sets and then restores text
151 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
152 // encapsulate this in a small helper class
154 // wxColourChanger: changes the text colours in the ctor if required and
155 // restores them in the dtor
156 class wxColourChanger
159 wxColourChanger(wxDC
& dc
);
165 COLORREF m_colFgOld
, m_colBgOld
;
169 DECLARE_NO_COPY_CLASS(wxColourChanger
)
172 // this class saves the old stretch blit mode during its life time
173 class StretchBltModeChanger
176 StretchBltModeChanger(HDC hdc
,
177 int WXUNUSED_IN_WINCE(mode
))
181 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
183 wxLogLastError(_T("SetStretchBltMode"));
187 ~StretchBltModeChanger()
190 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
191 wxLogLastError(_T("SetStretchBltMode"));
200 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
203 // helper class to cache dynamically loaded libraries and not attempt reloading
205 class wxOnceOnlyDLLLoader
208 // ctor argument must be a literal string as we don't make a copy of it!
209 wxOnceOnlyDLLLoader(const wxChar
*dllName
)
215 // return the symbol with the given name or NULL if the DLL not loaded
216 // or symbol not present
217 void *GetSymbol(const wxChar
*name
)
219 // we're prepared to handle errors here
224 m_dll
.Load(m_dllName
);
226 // reset the name whether we succeeded or failed so that we don't
227 // try again the next time
231 return m_dll
.IsLoaded() ? m_dll
.GetSymbol(name
) : NULL
;
235 wxDynamicLibrary m_dll
;
236 const wxChar
*m_dllName
;
239 static wxOnceOnlyDLLLoader
wxGDI32DLL(_T("gdi32"));
240 static wxOnceOnlyDLLLoader
wxMSIMG32DLL(_T("msimg32"));
242 // ===========================================================================
244 // ===========================================================================
246 // ----------------------------------------------------------------------------
248 // ----------------------------------------------------------------------------
250 wxColourChanger::wxColourChanger(wxDC
& dc
) : m_dc(dc
)
252 const wxBrush
& brush
= dc
.GetBrush();
253 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
255 HDC hdc
= GetHdcOf(dc
);
256 m_colFgOld
= ::GetTextColor(hdc
);
257 m_colBgOld
= ::GetBkColor(hdc
);
259 // note that Windows convention is opposite to wxWidgets one, this is
260 // why text colour becomes the background one and vice versa
261 const wxColour
& colFg
= dc
.GetTextForeground();
264 ::SetBkColor(hdc
, colFg
.GetPixel());
267 const wxColour
& colBg
= dc
.GetTextBackground();
270 ::SetTextColor(hdc
, colBg
.GetPixel());
274 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
277 // flag which telsl us to undo changes in the dtor
282 // nothing done, nothing to undo
287 wxColourChanger::~wxColourChanger()
291 // restore the colours we changed
292 HDC hdc
= GetHdcOf(m_dc
);
294 ::SetBkMode(hdc
, TRANSPARENT
);
295 ::SetTextColor(hdc
, m_colFgOld
);
296 ::SetBkColor(hdc
, m_colBgOld
);
300 // ---------------------------------------------------------------------------
302 // ---------------------------------------------------------------------------
308 SelectOldObjects(m_hDC
);
310 // if we own the HDC, we delete it, otherwise we just release it
314 ::DeleteDC(GetHdc());
316 else // we don't own our HDC
320 ::ReleaseDC(GetHwndOf(m_canvas
), GetHdc());
324 // Must have been a wxScreenDC
325 ::ReleaseDC((HWND
) NULL
, GetHdc());
331 // This will select current objects out of the DC,
332 // which is what you have to do before deleting the
334 void wxDC::SelectOldObjects(WXHDC dc
)
340 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
342 if (m_selectedBitmap
.Ok())
344 m_selectedBitmap
.SetSelectedInto(NULL
);
351 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
356 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
361 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
368 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
371 #endif // wxUSE_PALETTE
374 m_brush
= wxNullBrush
;
377 m_palette
= wxNullPalette
;
378 #endif // wxUSE_PALETTE
380 m_backgroundBrush
= wxNullBrush
;
381 m_selectedBitmap
= wxNullBitmap
;
384 // ---------------------------------------------------------------------------
386 // ---------------------------------------------------------------------------
388 void wxDC::UpdateClipBox()
393 ::GetClipBox(GetHdc(), &rect
);
395 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
396 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
397 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
398 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
402 wxDC::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
404 // check if we should try to retrieve the clipping region possibly not set
405 // by our SetClippingRegion() but preset by Windows:this can only happen
406 // when we're associated with an existing HDC usign SetHDC(), see there
407 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
409 wxDC
*self
= wxConstCast(this, wxDC
);
410 self
->UpdateClipBox();
412 if ( !m_clipX1
&& !m_clipX2
)
413 self
->m_clipping
= false;
416 wxDCBase::DoGetClippingBox(x
, y
, w
, h
);
419 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
420 void wxDC::SetClippingHrgn(WXHRGN hrgn
)
422 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
426 // note that we combine the new clipping region with the existing one: this
427 // is compatible with what the other ports do and is the documented
428 // behaviour now (starting with 2.3.3)
429 #if defined(__WXWINCE__)
431 if ( !::GetClipBox(GetHdc(), &rectClip
) )
434 // GetClipBox returns logical coordinates, so transform to device
435 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
436 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
437 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
438 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
440 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
441 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
442 rectClip
.right
, rectClip
.bottom
);
444 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
446 ::SelectClipRgn(GetHdc(), hrgnDest
);
449 ::DeleteObject(hrgnClipOld
);
450 ::DeleteObject(hrgnDest
);
452 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
454 wxLogLastError(_T("ExtSelectClipRgn"));
458 #endif // WinCE/!WinCE
465 void wxDC::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
467 // the region coords are always the device ones, so do the translation
470 // FIXME: possible +/-1 error here, to check!
471 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
473 LogicalToDeviceX(x
+ w
),
474 LogicalToDeviceY(y
+ h
));
477 wxLogLastError(_T("CreateRectRgn"));
481 SetClippingHrgn((WXHRGN
)hrgn
);
483 ::DeleteObject(hrgn
);
487 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
489 SetClippingHrgn(region
.GetHRGN());
492 void wxDC::DestroyClippingRegion()
496 if (m_clipping
&& m_hDC
)
499 // On a PocketPC device (not necessarily emulator), resetting
500 // the clip region as per the old method causes bad display
501 // problems. In fact setting a null region is probably OK
502 // on desktop WIN32 also, since the WIN32 docs imply that the user
503 // clipping region is independent from the paint clipping region.
504 ::SelectClipRgn(GetHdc(), 0);
506 // TODO: this should restore the previous clipping region,
507 // so that OnPaint processing works correctly, and the update
508 // clipping region doesn't get destroyed after the first
509 // DestroyClippingRegion.
510 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
511 ::SelectClipRgn(GetHdc(), rgn
);
516 wxDCBase::DestroyClippingRegion();
519 // ---------------------------------------------------------------------------
520 // query capabilities
521 // ---------------------------------------------------------------------------
523 bool wxDC::CanDrawBitmap() const
528 bool wxDC::CanGetTextExtent() const
530 #ifdef __WXMICROWIN__
531 // TODO Extend MicroWindows' GetDeviceCaps function
534 // What sort of display is it?
535 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
537 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
541 int wxDC::GetDepth() const
543 WXMICROWIN_CHECK_HDC_RET(16)
545 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
548 // ---------------------------------------------------------------------------
550 // ---------------------------------------------------------------------------
559 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
563 // No, I think we should simply ignore this if printing on e.g.
565 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
566 if (!m_selectedBitmap
.Ok())
569 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
570 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
571 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
575 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
578 DWORD colour
= ::GetBkColor(GetHdc());
579 HBRUSH brush
= ::CreateSolidBrush(colour
);
580 ::FillRect(GetHdc(), &rect
, brush
);
581 ::DeleteObject(brush
);
584 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
585 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
587 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
589 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
590 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
591 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
592 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
596 bool wxDC::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
597 wxCoord
WXUNUSED_IN_WINCE(y
),
598 const wxColour
& WXUNUSED_IN_WINCE(col
),
599 int WXUNUSED_IN_WINCE(style
))
604 WXMICROWIN_CHECK_HDC_RET(false)
606 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
608 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
609 : FLOODFILLBORDER
) ) ;
612 // quoting from the MSDN docs:
614 // Following are some of the reasons this function might fail:
616 // * The filling could not be completed.
617 // * The specified point has the boundary color specified by the
618 // crColor parameter (if FLOODFILLBORDER was requested).
619 // * The specified point does not have the color specified by
620 // crColor (if FLOODFILLSURFACE was requested)
621 // * The point is outside the clipping region that is, it is not
622 // visible on the device.
624 wxLogLastError(wxT("ExtFloodFill"));
627 CalcBoundingBox(x
, y
);
633 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
635 WXMICROWIN_CHECK_HDC_RET(false)
637 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxDC::GetPixel") );
639 // get the color of the pixel
640 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
642 wxRGBToColour(*col
, pixelcolor
);
647 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
651 wxCoord x1
= x
-VIEWPORT_EXTENT
;
652 wxCoord y1
= y
-VIEWPORT_EXTENT
;
653 wxCoord x2
= x
+VIEWPORT_EXTENT
;
654 wxCoord y2
= y
+VIEWPORT_EXTENT
;
656 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
657 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
659 CalcBoundingBox(x1
, y1
);
660 CalcBoundingBox(x2
, y2
);
663 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
667 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
669 CalcBoundingBox(x1
, y1
);
670 CalcBoundingBox(x2
, y2
);
673 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
674 // and ending at (x2, y2)
675 void wxDC::DoDrawArc(wxCoord x1
, wxCoord y1
,
676 wxCoord x2
, wxCoord y2
,
677 wxCoord xc
, wxCoord yc
)
680 // Slower emulation since WinCE doesn't support Pie and Arc
681 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
682 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
683 if( y1
>yc
) sa
= -sa
; // below center
684 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
685 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
690 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
694 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
695 wxCoord r
= (wxCoord
)radius
;
697 // treat the special case of full circle separately
698 if ( x1
== x2
&& y1
== y2
)
700 DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
704 wxCoord xx1
= XLOG2DEV(x1
);
705 wxCoord yy1
= YLOG2DEV(y1
);
706 wxCoord xx2
= XLOG2DEV(x2
);
707 wxCoord yy2
= YLOG2DEV(y2
);
708 wxCoord xxc
= XLOG2DEV(xc
);
709 wxCoord yyc
= YLOG2DEV(yc
);
710 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
712 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
713 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
714 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
715 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
717 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
719 // Have to add 1 to bottom-right corner of rectangle
720 // to make semi-circles look right (crooked line otherwise).
721 // Unfortunately this is not a reliable method, depends
722 // on the size of shape.
723 // TODO: figure out why this happens!
724 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
728 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
731 CalcBoundingBox(xc
- r
, yc
- r
);
732 CalcBoundingBox(xc
+ r
, yc
+ r
);
736 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
737 wxCoord width
, wxCoord height
)
739 // cases when we don't have DrawFrameControl()
740 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
741 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
743 wxCoord x2
= x1
+ width
,
753 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
755 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
758 CalcBoundingBox(x1
, y1
);
759 CalcBoundingBox(x2
, y2
);
760 #endif // Microwin/Normal
763 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
767 COLORREF color
= 0x00ffffff;
770 color
= m_pen
.GetColour().GetPixel();
773 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
775 CalcBoundingBox(x
, y
);
778 void wxDC::DoDrawPolygon(int n
,
782 int WXUNUSED_IN_WINCE(fillStyle
))
786 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
788 // Do things less efficiently if we have offsets
789 if (xoffset
!= 0 || yoffset
!= 0)
791 POINT
*cpoints
= new POINT
[n
];
793 for (i
= 0; i
< n
; i
++)
795 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
796 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
798 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
801 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
803 (void)Polygon(GetHdc(), cpoints
, n
);
805 SetPolyFillMode(GetHdc(),prev
);
812 for (i
= 0; i
< n
; i
++)
813 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
816 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
818 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
820 SetPolyFillMode(GetHdc(),prev
);
826 wxDC::DoDrawPolyPolygon(int n
,
834 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
838 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
840 for (i
= cnt
= 0; i
< n
; i
++)
843 // Do things less efficiently if we have offsets
844 if (xoffset
!= 0 || yoffset
!= 0)
846 POINT
*cpoints
= new POINT
[cnt
];
847 for (i
= 0; i
< cnt
; i
++)
849 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
850 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
852 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
855 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
857 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
859 SetPolyFillMode(GetHdc(),prev
);
865 for (i
= 0; i
< cnt
; i
++)
866 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
869 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
871 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
873 SetPolyFillMode(GetHdc(),prev
);
880 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
884 // Do things less efficiently if we have offsets
885 if (xoffset
!= 0 || yoffset
!= 0)
887 POINT
*cpoints
= new POINT
[n
];
889 for (i
= 0; i
< n
; i
++)
891 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
892 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
894 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
896 (void)Polyline(GetHdc(), cpoints
, n
);
902 for (i
= 0; i
< n
; i
++)
903 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
905 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
909 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
913 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
915 wxCoord x2
= x
+ width
;
916 wxCoord y2
= y
+ height
;
918 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
921 rect
.left
= XLOG2DEV(x
);
922 rect
.top
= YLOG2DEV(y
);
923 rect
.right
= XLOG2DEV(x2
);
924 rect
.bottom
= YLOG2DEV(y2
);
925 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
929 // Windows draws the filled rectangles without outline (i.e. drawn with a
930 // transparent pen) one pixel smaller in both directions and we want them
931 // to have the same size regardless of which pen is used - adjust
933 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
934 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
936 // Apparently not needed for WinCE (see e.g. Life! demo)
943 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
947 CalcBoundingBox(x
, y
);
948 CalcBoundingBox(x2
, y2
);
951 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
955 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
957 // Now, a negative radius value is interpreted to mean
958 // 'the proportion of the smallest X or Y dimension'
962 double smallest
= (width
< height
) ? width
: height
;
963 radius
= (- radius
* smallest
);
966 wxCoord x2
= (x
+width
);
967 wxCoord y2
= (y
+height
);
969 // Windows draws the filled rectangles without outline (i.e. drawn with a
970 // transparent pen) one pixel smaller in both directions and we want them
971 // to have the same size regardless of which pen is used - adjust
972 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
978 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
979 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
981 CalcBoundingBox(x
, y
);
982 CalcBoundingBox(x2
, y2
);
985 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
989 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
991 wxCoord x2
= (x
+width
);
992 wxCoord y2
= (y
+height
);
994 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
996 CalcBoundingBox(x
, y
);
997 CalcBoundingBox(x2
, y2
);
1001 void wxDC::DoDrawSpline(wxList
*points
)
1004 // WinCE does not support ::PolyBezier so use generic version
1005 wxDCBase::DoDrawSpline(points
);
1007 // quadratic b-spline to cubic bezier spline conversion
1009 // quadratic spline with control points P0,P1,P2
1010 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1012 // bezier spline with control points B0,B1,B2,B3
1013 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1015 // control points of bezier spline calculated from b-spline
1017 // B1 = (2*P1 + P0)/3
1018 // B2 = (2*P1 + P2)/3
1021 WXMICROWIN_CHECK_HDC
1023 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1025 const size_t n_points
= points
->GetCount();
1026 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1028 const size_t n_bezier_points
= n_points
* 3 + 1;
1029 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1030 size_t bezier_pos
= 0;
1031 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1033 wxList::compatibility_iterator node
= points
->GetFirst();
1034 wxPoint
*p
= (wxPoint
*)node
->GetData();
1035 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1036 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1038 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1041 node
= node
->GetNext();
1042 p
= (wxPoint
*)node
->GetData();
1046 cx1
= ( x1
+ x2
) / 2;
1047 cy1
= ( y1
+ y2
) / 2;
1048 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1049 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1051 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1055 while ((node
= node
->GetNext()) != NULL
)
1057 while ((node
= node
->GetNext()))
1058 #endif // !wxUSE_STL
1060 p
= (wxPoint
*)node
->GetData();
1065 cx4
= (x1
+ x2
) / 2;
1066 cy4
= (y1
+ y2
) / 2;
1067 // B0 is B3 of previous segment
1069 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1070 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1073 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1074 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1077 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1078 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1084 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1086 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1087 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1089 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1092 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1099 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1100 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1103 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1106 WXMICROWIN_CHECK_HDC
1108 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1113 int rx1
= XLOG2DEV(x
+w
/2);
1114 int ry1
= YLOG2DEV(y
+h
/2);
1121 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1122 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1123 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1124 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1126 // draw pie with NULL_PEN first and then outline otherwise a line is
1127 // drawn from the start and end points to the centre
1128 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1131 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1132 rx1
, ry1
, rx2
, ry2
);
1136 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1137 rx1
, ry1
-1, rx2
, ry2
-1);
1140 ::SelectObject(GetHdc(), hpenOld
);
1142 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1143 rx1
, ry1
, rx2
, ry2
);
1145 CalcBoundingBox(x
, y
);
1146 CalcBoundingBox(x2
, y2
);
1150 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1152 WXMICROWIN_CHECK_HDC
1154 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1157 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1159 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1162 CalcBoundingBox(x
, y
);
1163 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1166 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1168 WXMICROWIN_CHECK_HDC
1170 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
1172 int width
= bmp
.GetWidth(),
1173 height
= bmp
.GetHeight();
1175 HBITMAP hbmpMask
= 0;
1178 HPALETTE oldPal
= 0;
1179 #endif // wxUSE_PALETTE
1181 if ( bmp
.HasAlpha() )
1184 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1186 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, hdcMem
, bmp
) )
1192 wxMask
*mask
= bmp
.GetMask();
1194 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1198 // don't give assert here because this would break existing
1199 // programs - just silently ignore useMask parameter
1206 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1208 // On some systems, MaskBlt succeeds yet is much much slower
1209 // than the wxWidgets fall-back implementation. So we need
1210 // to be able to switch this on and off at runtime.
1212 #if wxUSE_SYSTEM_OPTIONS
1213 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1217 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1218 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1220 wxPalette
*pal
= bmp
.GetPalette();
1221 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1223 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1224 ::RealizePalette(hdcMem
);
1226 #endif // wxUSE_PALETTE
1228 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1231 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1235 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1236 #endif // wxUSE_PALETTE
1238 ::SelectObject(hdcMem
, hOldBitmap
);
1245 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
1248 memDC
.SelectObject(bmp
);
1250 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1252 memDC
.SelectObject(wxNullBitmap
);
1255 else // no mask, just use BitBlt()
1258 HDC memdc
= ::CreateCompatibleDC( cdc
);
1259 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1261 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1263 COLORREF old_textground
= ::GetTextColor(GetHdc());
1264 COLORREF old_background
= ::GetBkColor(GetHdc());
1265 if (m_textForegroundColour
.Ok())
1267 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1269 if (m_textBackgroundColour
.Ok())
1271 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1275 wxPalette
*pal
= bmp
.GetPalette();
1276 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1278 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1279 ::RealizePalette(memdc
);
1281 #endif // wxUSE_PALETTE
1283 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1284 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1288 ::SelectPalette(memdc
, oldPal
, FALSE
);
1289 #endif // wxUSE_PALETTE
1291 ::SelectObject( memdc
, hOldBitmap
);
1292 ::DeleteDC( memdc
);
1294 ::SetTextColor(GetHdc(), old_textground
);
1295 ::SetBkColor(GetHdc(), old_background
);
1299 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1301 WXMICROWIN_CHECK_HDC
1303 DrawAnyText(text
, x
, y
);
1305 // update the bounding box
1306 CalcBoundingBox(x
, y
);
1309 GetTextExtent(text
, &w
, &h
);
1310 CalcBoundingBox(x
+ w
, y
+ h
);
1313 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1315 WXMICROWIN_CHECK_HDC
1317 // prepare for drawing the text
1318 if ( m_textForegroundColour
.Ok() )
1319 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1321 DWORD old_background
= 0;
1322 if ( m_textBackgroundColour
.Ok() )
1324 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1327 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1331 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1332 text
.c_str(), text
.length(), NULL
) == 0 )
1334 wxLogLastError(wxT("TextOut"));
1337 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1338 text
.c_str(), text
.length()) == 0 )
1340 wxLogLastError(wxT("TextOut"));
1344 // restore the old parameters (text foreground colour may be left because
1345 // it never is set to anything else, but background should remain
1346 // transparent even if we just drew an opaque string)
1347 if ( m_textBackgroundColour
.Ok() )
1348 (void)SetBkColor(GetHdc(), old_background
);
1350 SetBkMode(GetHdc(), TRANSPARENT
);
1353 void wxDC::DoDrawRotatedText(const wxString
& text
,
1354 wxCoord x
, wxCoord y
,
1357 WXMICROWIN_CHECK_HDC
1359 // we test that we have some font because otherwise we should still use the
1360 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1361 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1362 // font for drawing rotated fonts unfortunately)
1363 if ( (angle
== 0.0) && m_font
.Ok() )
1365 DoDrawText(text
, x
, y
);
1367 #ifndef __WXMICROWIN__
1370 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1371 // because it's not TrueType and so can't have non zero
1372 // orientation/escapement under Win9x
1373 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1374 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1376 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1378 wxLogLastError(wxT("GetObject(hfont)"));
1381 // GDI wants the angle in tenth of degree
1382 long angle10
= (long)(angle
* 10);
1383 lf
.lfEscapement
= angle10
;
1384 lf
. lfOrientation
= angle10
;
1386 hfont
= ::CreateFontIndirect(&lf
);
1389 wxLogLastError(wxT("CreateFont"));
1393 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1395 DrawAnyText(text
, x
, y
);
1397 (void)::SelectObject(GetHdc(), hfontOld
);
1398 (void)::DeleteObject(hfont
);
1401 // call the bounding box by adding all four vertices of the rectangle
1402 // containing the text to it (simpler and probably not slower than
1403 // determining which of them is really topmost/leftmost/...)
1405 GetTextExtent(text
, &w
, &h
);
1407 double rad
= DegToRad(angle
);
1409 // "upper left" and "upper right"
1410 CalcBoundingBox(x
, y
);
1411 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1413 // "bottom left" and "bottom right"
1414 x
+= (wxCoord
)(h
*sin(rad
));
1415 y
+= (wxCoord
)(h
*cos(rad
));
1416 CalcBoundingBox(x
, y
);
1417 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1422 // ---------------------------------------------------------------------------
1424 // ---------------------------------------------------------------------------
1428 void wxDC::DoSelectPalette(bool realize
)
1430 WXMICROWIN_CHECK_HDC
1432 // Set the old object temporarily, in case the assignment deletes an object
1433 // that's not yet selected out.
1436 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1440 if ( m_palette
.Ok() )
1442 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1443 GetHpaletteOf(m_palette
),
1446 m_oldPalette
= (WXHPALETTE
) oldPal
;
1449 ::RealizePalette(GetHdc());
1453 void wxDC::SetPalette(const wxPalette
& palette
)
1457 m_palette
= palette
;
1458 DoSelectPalette(true);
1462 void wxDC::InitializePalette()
1464 if ( wxDisplayDepth() <= 8 )
1466 // look for any window or parent that has a custom palette. If any has
1467 // one then we need to use it in drawing operations
1468 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1470 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1471 if ( m_hasCustomPalette
)
1473 m_palette
= win
->GetPalette();
1475 // turn on MSW translation for this palette
1481 #endif // wxUSE_PALETTE
1483 // SetFont/Pen/Brush() really ask to be implemented as a single template
1484 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1486 void wxDC::SetFont(const wxFont
& font
)
1488 WXMICROWIN_CHECK_HDC
1490 if ( font
== m_font
)
1495 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1496 if ( hfont
== HGDI_ERROR
)
1498 wxLogLastError(_T("SelectObject(font)"));
1503 m_oldFont
= (WXHFONT
)hfont
;
1508 else // invalid font, reset the current font
1512 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1514 wxLogLastError(_T("SelectObject(old font)"));
1520 m_font
= wxNullFont
;
1524 void wxDC::SetPen(const wxPen
& pen
)
1526 WXMICROWIN_CHECK_HDC
1533 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1534 if ( hpen
== HGDI_ERROR
)
1536 wxLogLastError(_T("SelectObject(pen)"));
1541 m_oldPen
= (WXHPEN
)hpen
;
1546 else // invalid pen, reset the current pen
1550 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1552 wxLogLastError(_T("SelectObject(old pen)"));
1562 void wxDC::SetBrush(const wxBrush
& brush
)
1564 WXMICROWIN_CHECK_HDC
1566 if ( brush
== m_brush
)
1571 // we must make sure the brush is aligned with the logical coordinates
1572 // before selecting it
1573 wxBitmap
*stipple
= brush
.GetStipple();
1574 if ( stipple
&& stipple
->Ok() )
1576 if ( !::SetBrushOrgEx
1579 m_deviceOriginX
% stipple
->GetWidth(),
1580 m_deviceOriginY
% stipple
->GetHeight(),
1581 NULL
// [out] previous brush origin
1584 wxLogLastError(_T("SetBrushOrgEx()"));
1588 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1589 if ( hbrush
== HGDI_ERROR
)
1591 wxLogLastError(_T("SelectObject(brush)"));
1596 m_oldBrush
= (WXHBRUSH
)hbrush
;
1601 else // invalid brush, reset the current brush
1605 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1607 wxLogLastError(_T("SelectObject(old brush)"));
1613 m_brush
= wxNullBrush
;
1617 void wxDC::SetBackground(const wxBrush
& brush
)
1619 WXMICROWIN_CHECK_HDC
1621 m_backgroundBrush
= brush
;
1623 if ( m_backgroundBrush
.Ok() )
1625 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1629 void wxDC::SetBackgroundMode(int mode
)
1631 WXMICROWIN_CHECK_HDC
1633 m_backgroundMode
= mode
;
1635 // SetBackgroundColour now only refers to text background
1636 // and m_backgroundMode is used there
1639 void wxDC::SetLogicalFunction(int function
)
1641 WXMICROWIN_CHECK_HDC
1643 m_logicalFunction
= function
;
1648 void wxDC::SetRop(WXHDC dc
)
1650 if ( !dc
|| m_logicalFunction
< 0 )
1655 switch (m_logicalFunction
)
1657 case wxCLEAR
: rop
= R2_BLACK
; break;
1658 case wxXOR
: rop
= R2_XORPEN
; break;
1659 case wxINVERT
: rop
= R2_NOT
; break;
1660 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1661 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1662 case wxCOPY
: rop
= R2_COPYPEN
; break;
1663 case wxAND
: rop
= R2_MASKPEN
; break;
1664 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1665 case wxNO_OP
: rop
= R2_NOP
; break;
1666 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1667 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1668 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1669 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1670 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1671 case wxOR
: rop
= R2_MERGEPEN
; break;
1672 case wxSET
: rop
= R2_WHITE
; break;
1675 wxFAIL_MSG( wxT("unsupported logical function") );
1679 SetROP2(GetHdc(), rop
);
1682 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1684 // We might be previewing, so return true to let it continue.
1692 void wxDC::StartPage()
1696 void wxDC::EndPage()
1700 // ---------------------------------------------------------------------------
1702 // ---------------------------------------------------------------------------
1704 wxCoord
wxDC::GetCharHeight() const
1706 WXMICROWIN_CHECK_HDC_RET(0)
1708 TEXTMETRIC lpTextMetric
;
1710 GetTextMetrics(GetHdc(), &lpTextMetric
);
1712 return lpTextMetric
.tmHeight
;
1715 wxCoord
wxDC::GetCharWidth() const
1717 WXMICROWIN_CHECK_HDC_RET(0)
1719 TEXTMETRIC lpTextMetric
;
1721 GetTextMetrics(GetHdc(), &lpTextMetric
);
1723 return lpTextMetric
.tmAveCharWidth
;
1726 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1727 wxCoord
*descent
, wxCoord
*externalLeading
,
1730 #ifdef __WXMICROWIN__
1735 if (descent
) *descent
= 0;
1736 if (externalLeading
) *externalLeading
= 0;
1739 #endif // __WXMICROWIN__
1744 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1746 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1748 else // don't change the font
1754 const size_t len
= string
.length();
1755 if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) )
1757 wxLogLastError(_T("GetTextExtentPoint32()"));
1760 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1761 // the result computed by GetTextExtentPoint32() may be too small as it
1762 // accounts for under/overhang of the first/last character while we want
1763 // just the bounding rect for this string so adjust the width as needed
1764 // (using API not available in 2002 SDKs of WinCE)
1768 const wxChar chFirst
= *string
.begin();
1769 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1771 if ( width
.abcA
< 0 )
1772 sizeRect
.cx
-= width
.abcA
;
1776 const wxChar chLast
= *string
.rbegin();
1777 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1779 //else: we already have the width of the last character
1781 if ( width
.abcC
< 0 )
1782 sizeRect
.cx
-= width
.abcC
;
1784 //else: GetCharABCWidths() failed, not a TrueType font?
1786 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1789 ::GetTextMetrics(GetHdc(), &tm
);
1796 *descent
= tm
.tmDescent
;
1797 if (externalLeading
)
1798 *externalLeading
= tm
.tmExternalLeading
;
1802 ::SelectObject(GetHdc(), hfontOld
);
1807 // Each element of the array will be the width of the string up to and
1808 // including the coresoponding character in text.
1810 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1812 static int maxLenText
= -1;
1813 static int maxWidth
= -1;
1816 int stlen
= text
.length();
1818 if (maxLenText
== -1)
1820 // Win9x and WinNT+ have different limits
1821 int version
= wxGetOsVersion();
1822 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1823 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1827 widths
.Add(0, stlen
); // fill the array with zeros
1831 if (!::GetTextExtentExPoint(GetHdc(),
1832 text
.c_str(), // string to check
1833 wxMin(stlen
, maxLenText
),
1835 &fit
, // [out] count of chars
1837 &widths
[0], // array to fill
1841 wxLogLastError(wxT("GetTextExtentExPoint"));
1851 void wxDC::SetMapMode(int mode
)
1853 WXMICROWIN_CHECK_HDC
1855 m_mappingMode
= mode
;
1857 if ( mode
== wxMM_TEXT
)
1860 m_logicalScaleY
= 1.0;
1862 else // need to do some calculations
1864 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1865 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1866 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1867 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1869 if ( (mm_width
== 0) || (mm_height
== 0) )
1871 // we can't calculate mm2pixels[XY] then!
1875 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1876 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1881 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1882 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1886 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1887 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1891 m_logicalScaleX
= mm2pixelsX
;
1892 m_logicalScaleY
= mm2pixelsY
;
1896 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1897 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1901 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1905 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1906 // cases we could do with MM_TEXT and in the remaining 0.9% with
1907 // MM_ISOTROPIC (TODO!)
1909 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1911 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1912 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1914 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1915 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1917 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1918 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1922 void wxDC::SetUserScale(double x
, double y
)
1924 WXMICROWIN_CHECK_HDC
1926 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1932 this->SetMapMode(m_mappingMode
);
1935 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1936 bool WXUNUSED_IN_WINCE(yBottomUp
))
1938 WXMICROWIN_CHECK_HDC
1941 int signX
= xLeftRight
? 1 : -1,
1942 signY
= yBottomUp
? -1 : 1;
1944 if ( signX
!= m_signX
|| signY
!= m_signY
)
1949 SetMapMode(m_mappingMode
);
1954 void wxDC::SetSystemScale(double x
, double y
)
1956 WXMICROWIN_CHECK_HDC
1958 if ( x
== m_scaleX
&& y
== m_scaleY
)
1965 SetMapMode(m_mappingMode
);
1969 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1971 WXMICROWIN_CHECK_HDC
1973 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1976 m_logicalOriginX
= x
;
1977 m_logicalOriginY
= y
;
1980 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1984 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1986 WXMICROWIN_CHECK_HDC
1988 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1991 m_deviceOriginX
= x
;
1992 m_deviceOriginY
= y
;
1994 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1997 // ---------------------------------------------------------------------------
1998 // coordinates transformations
1999 // ---------------------------------------------------------------------------
2001 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
2003 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
2006 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
2008 // axis orientation is not taken into account for conversion of a distance
2009 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
2012 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
2014 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
2017 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
2019 // axis orientation is not taken into account for conversion of a distance
2020 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
2023 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
2025 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
2028 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
2030 // axis orientation is not taken into account for conversion of a distance
2031 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
2034 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
2036 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
2039 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
2041 // axis orientation is not taken into account for conversion of a distance
2042 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
2045 // ---------------------------------------------------------------------------
2047 // ---------------------------------------------------------------------------
2049 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
2050 wxCoord width
, wxCoord height
,
2051 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
2052 int rop
, bool useMask
,
2053 wxCoord xsrcMask
, wxCoord ysrcMask
)
2055 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2057 WXMICROWIN_CHECK_HDC_RET(false)
2059 // if either the source or destination has alpha channel, we must use
2060 // AlphaBlt() as other function don't handle it correctly
2061 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2062 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2063 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2065 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2066 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2070 wxMask
*mask
= NULL
;
2073 mask
= bmpSrc
.GetMask();
2075 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2077 // don't give assert here because this would break existing
2078 // programs - just silently ignore useMask parameter
2083 if (xsrcMask
== -1 && ysrcMask
== -1)
2085 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2088 COLORREF old_textground
= ::GetTextColor(GetHdc());
2089 COLORREF old_background
= ::GetBkColor(GetHdc());
2090 if (m_textForegroundColour
.Ok())
2092 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2094 if (m_textBackgroundColour
.Ok())
2096 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2102 case wxXOR
: dwRop
= SRCINVERT
; break;
2103 case wxINVERT
: dwRop
= DSTINVERT
; break;
2104 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2105 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2106 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2107 case wxSET
: dwRop
= WHITENESS
; break;
2108 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2109 case wxAND
: dwRop
= SRCAND
; break;
2110 case wxOR
: dwRop
= SRCPAINT
; break;
2111 case wxEQUIV
: dwRop
= 0x00990066; break;
2112 case wxNAND
: dwRop
= 0x007700E6; break;
2113 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2114 case wxCOPY
: dwRop
= SRCCOPY
; break;
2115 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2116 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2117 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2119 wxFAIL_MSG( wxT("unsupported logical function") );
2123 bool success
= false;
2128 // we want the part of the image corresponding to the mask to be
2129 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2130 // meaning of fg and bg is inverted which corresponds to wxWin notion
2131 // of the mask which is also contrary to the Windows one)
2133 // On some systems, MaskBlt succeeds yet is much much slower
2134 // than the wxWidgets fall-back implementation. So we need
2135 // to be able to switch this on and off at runtime.
2136 #if wxUSE_SYSTEM_OPTIONS
2137 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2143 xdest
, ydest
, width
, height
,
2146 (HBITMAP
)mask
->GetMaskBitmap(),
2148 MAKEROP4(dwRop
, DSTCOPY
)
2155 // Blit bitmap with mask
2158 HBITMAP buffer_bmap
;
2160 #if wxUSE_DC_CACHEING
2161 // create a temp buffer bitmap and DCs to access it and the mask
2162 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2163 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2165 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2166 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2168 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2171 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2172 #else // !wxUSE_DC_CACHEING
2173 // create a temp buffer bitmap and DCs to access it and the mask
2174 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2175 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2176 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2177 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2178 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2179 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2181 // copy dest to buffer
2182 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2183 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2185 wxLogLastError(wxT("BitBlt"));
2188 // copy src to buffer using selected raster op
2189 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2190 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2192 wxLogLastError(wxT("BitBlt"));
2195 // set masked area in buffer to BLACK (pixel value 0)
2196 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2197 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2198 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2199 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2201 wxLogLastError(wxT("BitBlt"));
2204 // set unmasked area in dest to BLACK
2205 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2206 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2207 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2208 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2210 wxLogLastError(wxT("BitBlt"));
2212 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2213 ::SetTextColor(GetHdc(), prevCol
);
2215 // OR buffer to dest
2216 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2217 (int)width
, (int)height
,
2218 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2221 wxLogLastError(wxT("BitBlt"));
2224 // tidy up temporary DCs and bitmap
2225 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2226 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2228 #if !wxUSE_DC_CACHEING
2230 ::DeleteDC(dc_mask
);
2231 ::DeleteDC(dc_buffer
);
2232 ::DeleteObject(buffer_bmap
);
2237 else // no mask, just BitBlt() it
2239 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2240 // use StretchBlt() if available and finally fall back to BitBlt()
2242 // FIXME: use appropriate WinCE functions
2244 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2245 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2250 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2252 &ds
) == sizeof(ds
) )
2254 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2256 // Figure out what co-ordinate system we're supposed to specify
2258 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2262 ysrc
= hDIB
- (ysrc
+ height
);
2265 if ( ::StretchDIBits(GetHdc(),
2271 (LPBITMAPINFO
)&ds
.dsBmih
,
2274 ) == (int)GDI_ERROR
)
2276 // On Win9x this API fails most (all?) of the time, so
2277 // logging it becomes quite distracting. Since it falls
2278 // back to the code below this is not really serious, so
2280 //wxLogLastError(wxT("StretchDIBits"));
2289 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2294 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2300 xdest
, ydest
, width
, height
,
2302 xsrc
, ysrc
, width
, height
,
2306 wxLogLastError(_T("StretchBlt"));
2320 (int)width
, (int)height
,
2326 wxLogLastError(_T("BitBlt"));
2335 ::SetTextColor(GetHdc(), old_textground
);
2336 ::SetBkColor(GetHdc(), old_background
);
2341 void wxDC::GetDeviceSize(int *width
, int *height
) const
2343 WXMICROWIN_CHECK_HDC
2346 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2348 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2351 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2353 WXMICROWIN_CHECK_HDC
2355 // if we implement it in terms of DoGetSize() instead of directly using the
2356 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2357 // will also work for wxWindowDC and wxClientDC even though their size is
2358 // not the same as the total size of the screen
2359 int wPixels
, hPixels
;
2360 DoGetSize(&wPixels
, &hPixels
);
2364 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2366 wxCHECK_RET( wTotal
, _T("0 width device?") );
2368 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2373 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2375 wxCHECK_RET( hTotal
, _T("0 height device?") );
2377 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2381 wxSize
wxDC::GetPPI() const
2383 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2385 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2386 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2388 return wxSize(x
, y
);
2391 // For use by wxWidgets only, unless custom units are required.
2392 void wxDC::SetLogicalScale(double x
, double y
)
2394 WXMICROWIN_CHECK_HDC
2396 m_logicalScaleX
= x
;
2397 m_logicalScaleY
= y
;
2400 // ----------------------------------------------------------------------------
2402 // ----------------------------------------------------------------------------
2404 #if wxUSE_DC_CACHEING
2407 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2408 * improve it in due course, either using arrays, or simply storing pointers to one
2409 * entry for the bitmap, and two for the DCs. -- JACS
2412 wxList
wxDC::sm_bitmapCache
;
2413 wxList
wxDC::sm_dcCache
;
2415 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2424 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2433 wxDCCacheEntry::~wxDCCacheEntry()
2436 ::DeleteObject((HBITMAP
) m_bitmap
);
2438 ::DeleteDC((HDC
) m_dc
);
2441 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2443 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2444 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2447 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2449 if (entry
->m_depth
== depth
)
2451 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2453 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2454 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2455 if ( !entry
->m_bitmap
)
2457 wxLogLastError(wxT("CreateCompatibleBitmap"));
2459 entry
->m_width
= w
; entry
->m_height
= h
;
2465 node
= node
->GetNext();
2467 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2470 wxLogLastError(wxT("CreateCompatibleBitmap"));
2472 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2473 AddToBitmapCache(entry
);
2477 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2479 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2480 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2483 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2485 // Don't return the same one as we already have
2486 if (!notThis
|| (notThis
!= entry
))
2488 if (entry
->m_depth
== depth
)
2494 node
= node
->GetNext();
2496 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2499 wxLogLastError(wxT("CreateCompatibleDC"));
2501 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2502 AddToDCCache(entry
);
2506 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2508 sm_bitmapCache
.Append(entry
);
2511 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2513 sm_dcCache
.Append(entry
);
2516 void wxDC::ClearCache()
2518 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2519 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2522 // Clean up cache at app exit
2523 class wxDCModule
: public wxModule
2526 virtual bool OnInit() { return true; }
2527 virtual void OnExit() { wxDC::ClearCache(); }
2530 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2533 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2535 #endif // wxUSE_DC_CACHEING
2537 // ----------------------------------------------------------------------------
2538 // alpha channel support
2539 // ----------------------------------------------------------------------------
2541 static bool AlphaBlt(HDC hdcDst
,
2542 int x
, int y
, int width
, int height
,
2543 int srcX
, int srcY
, HDC hdcSrc
,
2544 const wxBitmap
& bmp
)
2546 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2547 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2549 // do we have AlphaBlend() and company in the headers?
2550 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2551 // yes, now try to see if we have it during run-time
2552 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2553 HDC
,int,int,int,int,
2557 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2558 if ( pfnAlphaBlend
)
2561 bf
.BlendOp
= AC_SRC_OVER
;
2563 bf
.SourceConstantAlpha
= 0xff;
2564 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2566 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2567 hdcSrc
, srcX
, srcY
, width
, height
,
2570 // skip wxAlphaBlend() call below
2574 wxLogLastError(_T("AlphaBlend"));
2577 wxUnusedVar(hdcSrc
);
2578 #endif // defined(AC_SRC_OVER)
2580 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2582 #ifdef wxHAVE_RAW_BITMAP
2583 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2586 #else // !wxHAVE_RAW_BITMAP
2587 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2588 // alpha but at least something will be shown like this)
2591 #endif // wxHAVE_RAW_BITMAP
2595 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2596 #ifdef wxHAVE_RAW_BITMAP
2599 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2601 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2603 // get the destination DC pixels
2604 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2606 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2608 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2610 wxLogLastError(_T("BitBlt"));
2613 // combine them with the source bitmap using alpha
2614 wxAlphaPixelData
dataDst(bmpDst
),
2615 dataSrc((wxBitmap
&)bmpSrc
);
2617 wxCHECK_RET( dataDst
&& dataSrc
,
2618 _T("failed to get raw data in wxAlphaBlend") );
2620 wxAlphaPixelData::Iterator
pDst(dataDst
),
2623 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2625 for ( int y
= 0; y
< h
; y
++ )
2627 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2628 pSrcRowStart
= pSrc
;
2630 for ( int x
= 0; x
< w
; x
++ )
2632 // note that source bitmap uses premultiplied alpha (as required by
2633 // the real AlphaBlend)
2634 const unsigned beta
= 255 - pSrc
.Alpha();
2636 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2637 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2638 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2644 pDst
= pDstRowStart
;
2645 pSrc
= pSrcRowStart
;
2646 pDst
.OffsetY(dataDst
, 1);
2647 pSrc
.OffsetY(dataSrc
, 1);
2650 // and finally blit them back to the destination DC
2651 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2653 wxLogLastError(_T("BitBlt"));
2657 #endif // #ifdef wxHAVE_RAW_BITMAP
2659 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2660 const wxColour
& initialColour
,
2661 const wxColour
& destColour
,
2662 wxDirection nDirection
)
2664 // use native function if we have compile-time support it and can load it
2665 // during run-time (linking to it statically would make the program
2666 // unusable on earlier Windows versions)
2667 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2669 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2670 static GradientFill_t pfnGradientFill
=
2671 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2673 if ( pfnGradientFill
)
2675 GRADIENT_RECT grect
;
2676 grect
.UpperLeft
= 0;
2677 grect
.LowerRight
= 1;
2679 // invert colours direction if not filling from left-to-right or
2681 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2683 // one vertex for upper left and one for upper-right
2684 TRIVERTEX vertices
[2];
2686 vertices
[0].x
= rect
.GetLeft();
2687 vertices
[0].y
= rect
.GetTop();
2688 vertices
[1].x
= rect
.GetRight();
2689 vertices
[1].y
= rect
.GetBottom();
2691 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2692 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2693 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2694 vertices
[firstVertex
].Alpha
= 0;
2695 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2696 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2697 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2698 vertices
[1 - firstVertex
].Alpha
= 0;
2700 if ( (*pfnGradientFill
)
2707 nDirection
== wxWEST
|| nDirection
== wxEAST
2708 ? GRADIENT_FILL_RECT_H
2709 : GRADIENT_FILL_RECT_V
2712 // skip call of the base class version below
2716 wxLogLastError(_T("GradientFill"));
2718 #endif // wxUSE_DYNLIB_CLASS
2720 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2723 static DWORD
wxGetDCLayout(HDC hdc
)
2725 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2727 pfnGetLayout
= (GetLayout_t
)wxGDI32DLL
.GetSymbol(_T("GetLayout"));
2729 return pfnGetLayout
? pfnGetLayout(hdc
) : (DWORD
)-1;
2732 wxLayoutDirection
wxDC::GetLayoutDirection() const
2734 DWORD layout
= wxGetDCLayout(GetHdc());
2736 if ( layout
== (DWORD
)-1 )
2737 return wxLayout_Default
;
2739 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2742 void wxDC::SetLayoutDirection(wxLayoutDirection dir
)
2744 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2746 pfnSetLayout
= (SetLayout_t
)wxGDI32DLL
.GetSymbol(_T("SetLayout"));
2747 if ( !pfnSetLayout
)
2750 if ( dir
== wxLayout_Default
)
2752 dir
= wxTheApp
->GetLayoutDirection();
2753 if ( dir
== wxLayout_Default
)
2757 DWORD layout
= wxGetDCLayout(GetHdc());
2758 if ( dir
== wxLayout_RightToLeft
)
2759 layout
|= LAYOUT_RTL
;
2761 layout
&= ~LAYOUT_RTL
;
2763 pfnSetLayout(GetHdc(), layout
);