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 shouldnt 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
1249 memDC
.SelectObjectAsSource(bmp
);
1251 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1253 memDC
.SelectObject(wxNullBitmap
);
1256 else // no mask, just use BitBlt()
1259 HDC memdc
= ::CreateCompatibleDC( cdc
);
1260 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1262 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1264 COLORREF old_textground
= ::GetTextColor(GetHdc());
1265 COLORREF old_background
= ::GetBkColor(GetHdc());
1266 if (m_textForegroundColour
.Ok())
1268 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1270 if (m_textBackgroundColour
.Ok())
1272 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1276 wxPalette
*pal
= bmp
.GetPalette();
1277 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1279 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1280 ::RealizePalette(memdc
);
1282 #endif // wxUSE_PALETTE
1284 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1285 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1289 ::SelectPalette(memdc
, oldPal
, FALSE
);
1290 #endif // wxUSE_PALETTE
1292 ::SelectObject( memdc
, hOldBitmap
);
1293 ::DeleteDC( memdc
);
1295 ::SetTextColor(GetHdc(), old_textground
);
1296 ::SetBkColor(GetHdc(), old_background
);
1300 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1302 WXMICROWIN_CHECK_HDC
1304 DrawAnyText(text
, x
, y
);
1306 // update the bounding box
1307 CalcBoundingBox(x
, y
);
1310 GetTextExtent(text
, &w
, &h
);
1311 CalcBoundingBox(x
+ w
, y
+ h
);
1314 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1316 WXMICROWIN_CHECK_HDC
1318 // prepare for drawing the text
1319 if ( m_textForegroundColour
.Ok() )
1320 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1322 DWORD old_background
= 0;
1323 if ( m_textBackgroundColour
.Ok() )
1325 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1328 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1332 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1333 text
.c_str(), text
.length(), NULL
) == 0 )
1335 wxLogLastError(wxT("TextOut"));
1338 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1339 text
.c_str(), text
.length()) == 0 )
1341 wxLogLastError(wxT("TextOut"));
1345 // restore the old parameters (text foreground colour may be left because
1346 // it never is set to anything else, but background should remain
1347 // transparent even if we just drew an opaque string)
1348 if ( m_textBackgroundColour
.Ok() )
1349 (void)SetBkColor(GetHdc(), old_background
);
1351 SetBkMode(GetHdc(), TRANSPARENT
);
1354 void wxDC::DoDrawRotatedText(const wxString
& text
,
1355 wxCoord x
, wxCoord y
,
1358 WXMICROWIN_CHECK_HDC
1360 // we test that we have some font because otherwise we should still use the
1361 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1362 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1363 // font for drawing rotated fonts unfortunately)
1364 if ( (angle
== 0.0) && m_font
.Ok() )
1366 DoDrawText(text
, x
, y
);
1368 #ifndef __WXMICROWIN__
1371 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1372 // because it's not TrueType and so can't have non zero
1373 // orientation/escapement under Win9x
1374 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1375 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1377 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1379 wxLogLastError(wxT("GetObject(hfont)"));
1382 // GDI wants the angle in tenth of degree
1383 long angle10
= (long)(angle
* 10);
1384 lf
.lfEscapement
= angle10
;
1385 lf
. lfOrientation
= angle10
;
1387 hfont
= ::CreateFontIndirect(&lf
);
1390 wxLogLastError(wxT("CreateFont"));
1394 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1396 DrawAnyText(text
, x
, y
);
1398 (void)::SelectObject(GetHdc(), hfontOld
);
1399 (void)::DeleteObject(hfont
);
1402 // call the bounding box by adding all four vertices of the rectangle
1403 // containing the text to it (simpler and probably not slower than
1404 // determining which of them is really topmost/leftmost/...)
1406 GetTextExtent(text
, &w
, &h
);
1408 double rad
= DegToRad(angle
);
1410 // "upper left" and "upper right"
1411 CalcBoundingBox(x
, y
);
1412 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1414 // "bottom left" and "bottom right"
1415 x
+= (wxCoord
)(h
*sin(rad
));
1416 y
+= (wxCoord
)(h
*cos(rad
));
1417 CalcBoundingBox(x
, y
);
1418 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1423 // ---------------------------------------------------------------------------
1425 // ---------------------------------------------------------------------------
1429 void wxDC::DoSelectPalette(bool realize
)
1431 WXMICROWIN_CHECK_HDC
1433 // Set the old object temporarily, in case the assignment deletes an object
1434 // that's not yet selected out.
1437 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1441 if ( m_palette
.Ok() )
1443 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1444 GetHpaletteOf(m_palette
),
1447 m_oldPalette
= (WXHPALETTE
) oldPal
;
1450 ::RealizePalette(GetHdc());
1454 void wxDC::SetPalette(const wxPalette
& palette
)
1458 m_palette
= palette
;
1459 DoSelectPalette(true);
1463 void wxDC::InitializePalette()
1465 if ( wxDisplayDepth() <= 8 )
1467 // look for any window or parent that has a custom palette. If any has
1468 // one then we need to use it in drawing operations
1469 wxWindow
*win
= m_canvas
->GetAncestorWithCustomPalette();
1471 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1472 if ( m_hasCustomPalette
)
1474 m_palette
= win
->GetPalette();
1476 // turn on MSW translation for this palette
1482 #endif // wxUSE_PALETTE
1484 // SetFont/Pen/Brush() really ask to be implemented as a single template
1485 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1487 void wxDC::SetFont(const wxFont
& font
)
1489 WXMICROWIN_CHECK_HDC
1491 if ( font
== m_font
)
1496 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1497 if ( hfont
== HGDI_ERROR
)
1499 wxLogLastError(_T("SelectObject(font)"));
1504 m_oldFont
= (WXHFONT
)hfont
;
1509 else // invalid font, reset the current font
1513 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1515 wxLogLastError(_T("SelectObject(old font)"));
1521 m_font
= wxNullFont
;
1525 void wxDC::SetPen(const wxPen
& pen
)
1527 WXMICROWIN_CHECK_HDC
1534 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1535 if ( hpen
== HGDI_ERROR
)
1537 wxLogLastError(_T("SelectObject(pen)"));
1542 m_oldPen
= (WXHPEN
)hpen
;
1547 else // invalid pen, reset the current pen
1551 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1553 wxLogLastError(_T("SelectObject(old pen)"));
1563 void wxDC::SetBrush(const wxBrush
& brush
)
1565 WXMICROWIN_CHECK_HDC
1567 if ( brush
== m_brush
)
1572 // we must make sure the brush is aligned with the logical coordinates
1573 // before selecting it
1574 wxBitmap
*stipple
= brush
.GetStipple();
1575 if ( stipple
&& stipple
->Ok() )
1577 if ( !::SetBrushOrgEx
1580 m_deviceOriginX
% stipple
->GetWidth(),
1581 m_deviceOriginY
% stipple
->GetHeight(),
1582 NULL
// [out] previous brush origin
1585 wxLogLastError(_T("SetBrushOrgEx()"));
1589 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1590 if ( hbrush
== HGDI_ERROR
)
1592 wxLogLastError(_T("SelectObject(brush)"));
1597 m_oldBrush
= (WXHBRUSH
)hbrush
;
1602 else // invalid brush, reset the current brush
1606 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1608 wxLogLastError(_T("SelectObject(old brush)"));
1614 m_brush
= wxNullBrush
;
1618 void wxDC::SetBackground(const wxBrush
& brush
)
1620 WXMICROWIN_CHECK_HDC
1622 m_backgroundBrush
= brush
;
1624 if ( m_backgroundBrush
.Ok() )
1626 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1630 void wxDC::SetBackgroundMode(int mode
)
1632 WXMICROWIN_CHECK_HDC
1634 m_backgroundMode
= mode
;
1636 // SetBackgroundColour now only refers to text background
1637 // and m_backgroundMode is used there
1640 void wxDC::SetLogicalFunction(int function
)
1642 WXMICROWIN_CHECK_HDC
1644 m_logicalFunction
= function
;
1649 void wxDC::SetRop(WXHDC dc
)
1651 if ( !dc
|| m_logicalFunction
< 0 )
1656 switch (m_logicalFunction
)
1658 case wxCLEAR
: rop
= R2_BLACK
; break;
1659 case wxXOR
: rop
= R2_XORPEN
; break;
1660 case wxINVERT
: rop
= R2_NOT
; break;
1661 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1662 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1663 case wxCOPY
: rop
= R2_COPYPEN
; break;
1664 case wxAND
: rop
= R2_MASKPEN
; break;
1665 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1666 case wxNO_OP
: rop
= R2_NOP
; break;
1667 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1668 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1669 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1670 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1671 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1672 case wxOR
: rop
= R2_MERGEPEN
; break;
1673 case wxSET
: rop
= R2_WHITE
; break;
1676 wxFAIL_MSG( wxT("unsupported logical function") );
1680 SetROP2(GetHdc(), rop
);
1683 bool wxDC::StartDoc(const wxString
& WXUNUSED(message
))
1685 // We might be previewing, so return true to let it continue.
1693 void wxDC::StartPage()
1697 void wxDC::EndPage()
1701 // ---------------------------------------------------------------------------
1703 // ---------------------------------------------------------------------------
1705 wxCoord
wxDC::GetCharHeight() const
1707 WXMICROWIN_CHECK_HDC_RET(0)
1709 TEXTMETRIC lpTextMetric
;
1711 GetTextMetrics(GetHdc(), &lpTextMetric
);
1713 return lpTextMetric
.tmHeight
;
1716 wxCoord
wxDC::GetCharWidth() const
1718 WXMICROWIN_CHECK_HDC_RET(0)
1720 TEXTMETRIC lpTextMetric
;
1722 GetTextMetrics(GetHdc(), &lpTextMetric
);
1724 return lpTextMetric
.tmAveCharWidth
;
1727 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1728 wxCoord
*descent
, wxCoord
*externalLeading
,
1731 #ifdef __WXMICROWIN__
1736 if (descent
) *descent
= 0;
1737 if (externalLeading
) *externalLeading
= 0;
1740 #endif // __WXMICROWIN__
1745 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxDC::GetTextExtent") );
1747 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1749 else // don't change the font
1755 const size_t len
= string
.length();
1756 if ( !::GetTextExtentPoint32(GetHdc(), string
, len
, &sizeRect
) )
1758 wxLogLastError(_T("GetTextExtentPoint32()"));
1761 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1762 // the result computed by GetTextExtentPoint32() may be too small as it
1763 // accounts for under/overhang of the first/last character while we want
1764 // just the bounding rect for this string so adjust the width as needed
1765 // (using API not available in 2002 SDKs of WinCE)
1769 const wxChar chFirst
= *string
.begin();
1770 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1772 if ( width
.abcA
< 0 )
1773 sizeRect
.cx
-= width
.abcA
;
1777 const wxChar chLast
= *string
.rbegin();
1778 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1780 //else: we already have the width of the last character
1782 if ( width
.abcC
< 0 )
1783 sizeRect
.cx
-= width
.abcC
;
1785 //else: GetCharABCWidths() failed, not a TrueType font?
1787 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1790 ::GetTextMetrics(GetHdc(), &tm
);
1797 *descent
= tm
.tmDescent
;
1798 if (externalLeading
)
1799 *externalLeading
= tm
.tmExternalLeading
;
1803 ::SelectObject(GetHdc(), hfontOld
);
1808 // Each element of the array will be the width of the string up to and
1809 // including the coresoponding character in text.
1811 bool wxDC::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1813 static int maxLenText
= -1;
1814 static int maxWidth
= -1;
1817 int stlen
= text
.length();
1819 if (maxLenText
== -1)
1821 // Win9x and WinNT+ have different limits
1822 int version
= wxGetOsVersion();
1823 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1824 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1828 widths
.Add(0, stlen
); // fill the array with zeros
1832 if (!::GetTextExtentExPoint(GetHdc(),
1833 text
.c_str(), // string to check
1834 wxMin(stlen
, maxLenText
),
1836 &fit
, // [out] count of chars
1838 &widths
[0], // array to fill
1842 wxLogLastError(wxT("GetTextExtentExPoint"));
1852 void wxDC::SetMapMode(int mode
)
1854 WXMICROWIN_CHECK_HDC
1856 m_mappingMode
= mode
;
1858 if ( mode
== wxMM_TEXT
)
1861 m_logicalScaleY
= 1.0;
1863 else // need to do some calculations
1865 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1866 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1867 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1868 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1870 if ( (mm_width
== 0) || (mm_height
== 0) )
1872 // we can't calculate mm2pixels[XY] then!
1876 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1877 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1882 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1883 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1887 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1888 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1892 m_logicalScaleX
= mm2pixelsX
;
1893 m_logicalScaleY
= mm2pixelsY
;
1897 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1898 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1902 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1906 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1907 // cases we could do with MM_TEXT and in the remaining 0.9% with
1908 // MM_ISOTROPIC (TODO!)
1910 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1912 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1913 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1915 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1916 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1918 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1919 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1923 void wxDC::SetUserScale(double x
, double y
)
1925 WXMICROWIN_CHECK_HDC
1927 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1933 this->SetMapMode(m_mappingMode
);
1936 void wxDC::SetAxisOrientation(bool WXUNUSED_IN_WINCE(xLeftRight
),
1937 bool WXUNUSED_IN_WINCE(yBottomUp
))
1939 WXMICROWIN_CHECK_HDC
1942 int signX
= xLeftRight
? 1 : -1,
1943 signY
= yBottomUp
? -1 : 1;
1945 if ( signX
!= m_signX
|| signY
!= m_signY
)
1950 SetMapMode(m_mappingMode
);
1955 void wxDC::SetSystemScale(double x
, double y
)
1957 WXMICROWIN_CHECK_HDC
1959 if ( x
== m_scaleX
&& y
== m_scaleY
)
1966 SetMapMode(m_mappingMode
);
1970 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1972 WXMICROWIN_CHECK_HDC
1974 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
1977 m_logicalOriginX
= x
;
1978 m_logicalOriginY
= y
;
1981 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1985 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1987 WXMICROWIN_CHECK_HDC
1989 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
1992 m_deviceOriginX
= x
;
1993 m_deviceOriginY
= y
;
1995 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1998 // ---------------------------------------------------------------------------
1999 // coordinates transformations
2000 // ---------------------------------------------------------------------------
2002 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
2004 return DeviceToLogicalXRel(x
- m_deviceOriginX
)*m_signX
+ m_logicalOriginX
;
2007 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
2009 // axis orientation is not taken into account for conversion of a distance
2010 return (wxCoord
)(x
/ (m_logicalScaleX
*m_userScaleX
*m_scaleX
));
2013 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
2015 return DeviceToLogicalYRel(y
- m_deviceOriginY
)*m_signY
+ m_logicalOriginY
;
2018 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
2020 // axis orientation is not taken into account for conversion of a distance
2021 return (wxCoord
)( y
/ (m_logicalScaleY
*m_userScaleY
*m_scaleY
));
2024 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
2026 return LogicalToDeviceXRel(x
- m_logicalOriginX
)*m_signX
+ m_deviceOriginX
;
2029 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
2031 // axis orientation is not taken into account for conversion of a distance
2032 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_scaleX
);
2035 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
2037 return LogicalToDeviceYRel(y
- m_logicalOriginY
)*m_signY
+ m_deviceOriginY
;
2040 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
2042 // axis orientation is not taken into account for conversion of a distance
2043 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_scaleY
);
2046 // ---------------------------------------------------------------------------
2048 // ---------------------------------------------------------------------------
2050 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
2051 wxCoord width
, wxCoord height
,
2052 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
2053 int rop
, bool useMask
,
2054 wxCoord xsrcMask
, wxCoord ysrcMask
)
2056 wxCHECK_MSG( source
, false, _T("wxDC::Blit(): NULL wxDC pointer") );
2058 WXMICROWIN_CHECK_HDC_RET(false)
2060 // if either the source or destination has alpha channel, we must use
2061 // AlphaBlt() as other function don't handle it correctly
2062 const wxBitmap
& bmpSrc
= source
->m_selectedBitmap
;
2063 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2064 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2066 if ( AlphaBlt(GetHdc(), xdest
, ydest
, width
, height
,
2067 xsrc
, ysrc
, GetHdcOf(*source
), bmpSrc
) )
2071 wxMask
*mask
= NULL
;
2074 mask
= bmpSrc
.GetMask();
2076 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2078 // don't give assert here because this would break existing
2079 // programs - just silently ignore useMask parameter
2084 if (xsrcMask
== -1 && ysrcMask
== -1)
2086 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2089 COLORREF old_textground
= ::GetTextColor(GetHdc());
2090 COLORREF old_background
= ::GetBkColor(GetHdc());
2091 if (m_textForegroundColour
.Ok())
2093 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2095 if (m_textBackgroundColour
.Ok())
2097 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2103 case wxXOR
: dwRop
= SRCINVERT
; break;
2104 case wxINVERT
: dwRop
= DSTINVERT
; break;
2105 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2106 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2107 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2108 case wxSET
: dwRop
= WHITENESS
; break;
2109 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2110 case wxAND
: dwRop
= SRCAND
; break;
2111 case wxOR
: dwRop
= SRCPAINT
; break;
2112 case wxEQUIV
: dwRop
= 0x00990066; break;
2113 case wxNAND
: dwRop
= 0x007700E6; break;
2114 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2115 case wxCOPY
: dwRop
= SRCCOPY
; break;
2116 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2117 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2118 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2120 wxFAIL_MSG( wxT("unsupported logical function") );
2124 bool success
= false;
2129 // we want the part of the image corresponding to the mask to be
2130 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2131 // meaning of fg and bg is inverted which corresponds to wxWin notion
2132 // of the mask which is also contrary to the Windows one)
2134 // On some systems, MaskBlt succeeds yet is much much slower
2135 // than the wxWidgets fall-back implementation. So we need
2136 // to be able to switch this on and off at runtime.
2137 #if wxUSE_SYSTEM_OPTIONS
2138 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2144 xdest
, ydest
, width
, height
,
2147 (HBITMAP
)mask
->GetMaskBitmap(),
2149 MAKEROP4(dwRop
, DSTCOPY
)
2156 // Blit bitmap with mask
2159 HBITMAP buffer_bmap
;
2161 #if wxUSE_DC_CACHEING
2162 // create a temp buffer bitmap and DCs to access it and the mask
2163 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, source
->GetHDC());
2164 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2166 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2167 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2169 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2172 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2173 #else // !wxUSE_DC_CACHEING
2174 // create a temp buffer bitmap and DCs to access it and the mask
2175 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2176 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2177 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
2178 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2179 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2180 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2182 // copy dest to buffer
2183 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2184 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2186 wxLogLastError(wxT("BitBlt"));
2189 // copy src to buffer using selected raster op
2190 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2191 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
2193 wxLogLastError(wxT("BitBlt"));
2196 // set masked area in buffer to BLACK (pixel value 0)
2197 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2198 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2199 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
2200 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2202 wxLogLastError(wxT("BitBlt"));
2205 // set unmasked area in dest to BLACK
2206 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2207 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2208 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
2209 dc_mask
, xsrcMask
, ysrcMask
, SRCAND
) )
2211 wxLogLastError(wxT("BitBlt"));
2213 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2214 ::SetTextColor(GetHdc(), prevCol
);
2216 // OR buffer to dest
2217 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2218 (int)width
, (int)height
,
2219 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2222 wxLogLastError(wxT("BitBlt"));
2225 // tidy up temporary DCs and bitmap
2226 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2227 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2229 #if !wxUSE_DC_CACHEING
2231 ::DeleteDC(dc_mask
);
2232 ::DeleteDC(dc_buffer
);
2233 ::DeleteObject(buffer_bmap
);
2238 else // no mask, just BitBlt() it
2240 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2241 // use StretchBlt() if available and finally fall back to BitBlt()
2243 // FIXME: use appropriate WinCE functions
2245 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2246 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2251 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2253 &ds
) == sizeof(ds
) )
2255 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2257 // Figure out what co-ordinate system we're supposed to specify
2259 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2263 ysrc
= hDIB
- (ysrc
+ height
);
2266 if ( ::StretchDIBits(GetHdc(),
2272 (LPBITMAPINFO
)&ds
.dsBmih
,
2275 ) == (int)GDI_ERROR
)
2277 // On Win9x this API fails most (all?) of the time, so
2278 // logging it becomes quite distracting. Since it falls
2279 // back to the code below this is not really serious, so
2281 //wxLogLastError(wxT("StretchDIBits"));
2290 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2295 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2301 xdest
, ydest
, width
, height
,
2303 xsrc
, ysrc
, width
, height
,
2307 wxLogLastError(_T("StretchBlt"));
2321 (int)width
, (int)height
,
2327 wxLogLastError(_T("BitBlt"));
2336 ::SetTextColor(GetHdc(), old_textground
);
2337 ::SetBkColor(GetHdc(), old_background
);
2342 void wxDC::GetDeviceSize(int *width
, int *height
) const
2344 WXMICROWIN_CHECK_HDC
2347 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2349 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2352 void wxDC::DoGetSizeMM(int *w
, int *h
) const
2354 WXMICROWIN_CHECK_HDC
2356 // if we implement it in terms of DoGetSize() instead of directly using the
2357 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2358 // will also work for wxWindowDC and wxClientDC even though their size is
2359 // not the same as the total size of the screen
2360 int wPixels
, hPixels
;
2361 DoGetSize(&wPixels
, &hPixels
);
2365 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2367 wxCHECK_RET( wTotal
, _T("0 width device?") );
2369 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2374 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2376 wxCHECK_RET( hTotal
, _T("0 height device?") );
2378 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2382 wxSize
wxDC::GetPPI() const
2384 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2386 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2387 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2389 return wxSize(x
, y
);
2392 // For use by wxWidgets only, unless custom units are required.
2393 void wxDC::SetLogicalScale(double x
, double y
)
2395 WXMICROWIN_CHECK_HDC
2397 m_logicalScaleX
= x
;
2398 m_logicalScaleY
= y
;
2401 // ----------------------------------------------------------------------------
2403 // ----------------------------------------------------------------------------
2405 #if wxUSE_DC_CACHEING
2408 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2409 * improve it in due course, either using arrays, or simply storing pointers to one
2410 * entry for the bitmap, and two for the DCs. -- JACS
2413 wxList
wxDC::sm_bitmapCache
;
2414 wxList
wxDC::sm_dcCache
;
2416 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2425 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2434 wxDCCacheEntry::~wxDCCacheEntry()
2437 ::DeleteObject((HBITMAP
) m_bitmap
);
2439 ::DeleteDC((HDC
) m_dc
);
2442 wxDCCacheEntry
* wxDC::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2444 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2445 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2448 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2450 if (entry
->m_depth
== depth
)
2452 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2454 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2455 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2456 if ( !entry
->m_bitmap
)
2458 wxLogLastError(wxT("CreateCompatibleBitmap"));
2460 entry
->m_width
= w
; entry
->m_height
= h
;
2466 node
= node
->GetNext();
2468 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2471 wxLogLastError(wxT("CreateCompatibleBitmap"));
2473 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2474 AddToBitmapCache(entry
);
2478 wxDCCacheEntry
* wxDC::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2480 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2481 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2484 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2486 // Don't return the same one as we already have
2487 if (!notThis
|| (notThis
!= entry
))
2489 if (entry
->m_depth
== depth
)
2495 node
= node
->GetNext();
2497 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2500 wxLogLastError(wxT("CreateCompatibleDC"));
2502 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2503 AddToDCCache(entry
);
2507 void wxDC::AddToBitmapCache(wxDCCacheEntry
* entry
)
2509 sm_bitmapCache
.Append(entry
);
2512 void wxDC::AddToDCCache(wxDCCacheEntry
* entry
)
2514 sm_dcCache
.Append(entry
);
2517 void wxDC::ClearCache()
2519 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2520 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2523 // Clean up cache at app exit
2524 class wxDCModule
: public wxModule
2527 virtual bool OnInit() { return true; }
2528 virtual void OnExit() { wxDC::ClearCache(); }
2531 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2534 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2536 #endif // wxUSE_DC_CACHEING
2538 // ----------------------------------------------------------------------------
2539 // alpha channel support
2540 // ----------------------------------------------------------------------------
2542 static bool AlphaBlt(HDC hdcDst
,
2543 int x
, int y
, int width
, int height
,
2544 int srcX
, int srcY
, HDC hdcSrc
,
2545 const wxBitmap
& bmp
)
2547 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2548 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2550 // do we have AlphaBlend() and company in the headers?
2551 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2552 // yes, now try to see if we have it during run-time
2553 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2554 HDC
,int,int,int,int,
2558 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2559 if ( pfnAlphaBlend
)
2562 bf
.BlendOp
= AC_SRC_OVER
;
2564 bf
.SourceConstantAlpha
= 0xff;
2565 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2567 if ( pfnAlphaBlend(hdcDst
, x
, y
, width
, height
,
2568 hdcSrc
, srcX
, srcY
, width
, height
,
2571 // skip wxAlphaBlend() call below
2575 wxLogLastError(_T("AlphaBlend"));
2578 wxUnusedVar(hdcSrc
);
2579 #endif // defined(AC_SRC_OVER)
2581 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2583 #ifdef wxHAVE_RAW_BITMAP
2584 wxAlphaBlend(hdcDst
, x
, y
, width
, height
, srcX
, srcY
, bmp
);
2587 #else // !wxHAVE_RAW_BITMAP
2588 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2589 // alpha but at least something will be shown like this)
2592 #endif // wxHAVE_RAW_BITMAP
2596 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2597 #ifdef wxHAVE_RAW_BITMAP
2600 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2602 int srcX
, int srcY
, const wxBitmap
& bmpSrc
)
2604 // get the destination DC pixels
2605 wxBitmap
bmpDst(w
, h
, 32 /* force creating RGBA DIB */);
2607 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2609 if ( !::BitBlt(hdcMem
, 0, 0, w
, h
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2611 wxLogLastError(_T("BitBlt"));
2614 // combine them with the source bitmap using alpha
2615 wxAlphaPixelData
dataDst(bmpDst
),
2616 dataSrc((wxBitmap
&)bmpSrc
);
2618 wxCHECK_RET( dataDst
&& dataSrc
,
2619 _T("failed to get raw data in wxAlphaBlend") );
2621 wxAlphaPixelData::Iterator
pDst(dataDst
),
2624 pSrc
.Offset(dataSrc
, srcX
, srcY
);
2626 for ( int y
= 0; y
< h
; y
++ )
2628 wxAlphaPixelData::Iterator pDstRowStart
= pDst
,
2629 pSrcRowStart
= pSrc
;
2631 for ( int x
= 0; x
< w
; x
++ )
2633 // note that source bitmap uses premultiplied alpha (as required by
2634 // the real AlphaBlend)
2635 const unsigned beta
= 255 - pSrc
.Alpha();
2637 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2638 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2639 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2645 pDst
= pDstRowStart
;
2646 pSrc
= pSrcRowStart
;
2647 pDst
.OffsetY(dataDst
, 1);
2648 pSrc
.OffsetY(dataSrc
, 1);
2651 // and finally blit them back to the destination DC
2652 if ( !::BitBlt(hdcDst
, xDst
, yDst
, w
, h
, hdcMem
, 0, 0, SRCCOPY
) )
2654 wxLogLastError(_T("BitBlt"));
2658 #endif // #ifdef wxHAVE_RAW_BITMAP
2660 void wxDC::DoGradientFillLinear (const wxRect
& rect
,
2661 const wxColour
& initialColour
,
2662 const wxColour
& destColour
,
2663 wxDirection nDirection
)
2665 // use native function if we have compile-time support it and can load it
2666 // during run-time (linking to it statically would make the program
2667 // unusable on earlier Windows versions)
2668 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2670 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2671 static GradientFill_t pfnGradientFill
=
2672 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2674 if ( pfnGradientFill
)
2676 GRADIENT_RECT grect
;
2677 grect
.UpperLeft
= 0;
2678 grect
.LowerRight
= 1;
2680 // invert colours direction if not filling from left-to-right or
2682 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2684 // one vertex for upper left and one for upper-right
2685 TRIVERTEX vertices
[2];
2687 vertices
[0].x
= rect
.GetLeft();
2688 vertices
[0].y
= rect
.GetTop();
2689 vertices
[1].x
= rect
.GetRight()+1;
2690 vertices
[1].y
= rect
.GetBottom()+1;
2692 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2693 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2694 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2695 vertices
[firstVertex
].Alpha
= 0;
2696 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2697 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2698 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2699 vertices
[1 - firstVertex
].Alpha
= 0;
2701 if ( (*pfnGradientFill
)
2708 nDirection
== wxWEST
|| nDirection
== wxEAST
2709 ? GRADIENT_FILL_RECT_H
2710 : GRADIENT_FILL_RECT_V
2713 // skip call of the base class version below
2717 wxLogLastError(_T("GradientFill"));
2719 #endif // wxUSE_DYNLIB_CLASS
2721 wxDCBase::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2724 static DWORD
wxGetDCLayout(HDC hdc
)
2726 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2728 pfnGetLayout
= (GetLayout_t
)wxGDI32DLL
.GetSymbol(_T("GetLayout"));
2730 return pfnGetLayout
? pfnGetLayout(hdc
) : (DWORD
)-1;
2733 wxLayoutDirection
wxDC::GetLayoutDirection() const
2735 DWORD layout
= wxGetDCLayout(GetHdc());
2737 if ( layout
== (DWORD
)-1 )
2738 return wxLayout_Default
;
2740 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2743 void wxDC::SetLayoutDirection(wxLayoutDirection dir
)
2745 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2747 pfnSetLayout
= (SetLayout_t
)wxGDI32DLL
.GetSymbol(_T("SetLayout"));
2748 if ( !pfnSetLayout
)
2751 if ( dir
== wxLayout_Default
)
2753 dir
= wxTheApp
->GetLayoutDirection();
2754 if ( dir
== wxLayout_Default
)
2758 DWORD layout
= wxGetDCLayout(GetHdc());
2759 if ( dir
== wxLayout_RightToLeft
)
2760 layout
|= LAYOUT_RTL
;
2762 layout
&= ~LAYOUT_RTL
;
2764 pfnSetLayout(GetHdc(), layout
);