X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/888dde65f43d5f57e8fb2028b27191cca1741403..96c9640205933ad0673d5af2c96af0816c50160c:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index de8d163efa..c7f3cfa665 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -28,30 +28,31 @@ #include "wx/msw/wrapcdlg.h" #include "wx/image.h" #include "wx/window.h" - #include "wx/dc.h" #include "wx/utils.h" #include "wx/dialog.h" #include "wx/app.h" #include "wx/bitmap.h" #include "wx/dcmemory.h" #include "wx/log.h" + #include "wx/math.h" #include "wx/icon.h" #include "wx/dcprint.h" #include "wx/module.h" #endif +#include "wx/msw/dc.h" #include "wx/sysopt.h" #include "wx/dynlib.h" -#ifdef wxHAVE_RAW_BITMAP -#include "wx/rawbmp.h" +#ifdef wxHAS_RAW_BITMAP + #include "wx/rawbmp.h" #endif #include -#ifndef __WIN32__ - #include -#endif +#include "wx/msw/private/dc.h" + +using namespace wxMSWImpl; #ifndef AC_SRC_ALPHA #define AC_SRC_ALPHA 1 @@ -82,10 +83,9 @@ IMPLEMENT_ABSTRACT_CLASS(wxMSWDCImpl, wxDCImpl) // constants // --------------------------------------------------------------------------- -static const int VIEWPORT_EXTENT = 1000; - -static const int MM_POINTS = 9; -static const int MM_METRIC = 10; +// The device space in Win32 GDI measures 2^27*2^27 , so we use 2^27-1 as the +// maximal possible view port extent. +static const int VIEWPORT_EXTENT = 134217727; // ROPs which don't have standard names (see "Ternary Raster Operations" in the // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) @@ -131,22 +131,22 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } // otherwise static bool AlphaBlt(HDC hdcDst, int x, int y, int dstWidth, int dstHeight, - int srcX, int srcY, + int srcX, int srcY, int srcWidth, int srcHeight, HDC hdcSrc, const wxBitmap& bmp); -#ifdef wxHAVE_RAW_BITMAP +#ifdef wxHAS_RAW_BITMAP // our (limited) AlphaBlend() replacement for Windows versions not providing it static void wxAlphaBlend(HDC hdcDst, int xDst, int yDst, int dstWidth, int dstHeight, - int srcX, int srcY, + int srcX, int srcY, int srcWidth, int srcHeight, const wxBitmap& bmpSrc); -#endif // wxHAVE_RAW_BITMAP +#endif // wxHAS_RAW_BITMAP // ---------------------------------------------------------------------------- // private classes @@ -156,45 +156,47 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes, // encapsulate this in a small helper class -// wxColourChanger: changes the text colours in the ctor if required and +// wxBrushAttrsSetter: changes the text colours in the ctor if required and // restores them in the dtor -class wxColourChanger +class wxBrushAttrsSetter : private wxBkModeChanger, + private wxTextColoursChanger { public: - wxColourChanger(wxMSWDCImpl& dc); - ~wxColourChanger(); + wxBrushAttrsSetter(wxMSWDCImpl& dc); private: - wxMSWDCImpl& m_dc; + wxDECLARE_NO_COPY_CLASS(wxBrushAttrsSetter); +}; - COLORREF m_colFgOld, m_colBgOld; +#ifdef __WXWINCE__ - bool m_changed; +#define SET_STRETCH_BLT_MODE(hdc) - DECLARE_NO_COPY_CLASS(wxColourChanger) -}; +#else // !__WXWINCE__ -// this class saves the old stretch blit mode during its life time +// this class sets the stretch blit mode to COLORONCOLOR during its lifetime +// +// don't use it directly, use SET_STRETCH_BLT_MODE() macro instead as it +// expands to nothing under WinCE which doesn't have SetStretchBltMode() class StretchBltModeChanger { public: - StretchBltModeChanger(HDC hdc, - int WXUNUSED_IN_WINCE(mode)) + StretchBltModeChanger(HDC hdc) : m_hdc(hdc) { -#ifndef __WXWINCE__ - m_modeOld = ::SetStretchBltMode(m_hdc, mode); + m_modeOld = ::SetStretchBltMode(m_hdc, COLORONCOLOR); if ( !m_modeOld ) - wxLogLastError(_T("SetStretchBltMode")); -#endif + { + wxLogLastError(wxT("SetStretchBltMode")); + } } ~StretchBltModeChanger() { -#ifndef __WXWINCE__ if ( !::SetStretchBltMode(m_hdc, m_modeOld) ) - wxLogLastError(_T("SetStretchBltMode")); -#endif + { + wxLogLastError(wxT("SetStretchBltMode")); + } } private: @@ -202,9 +204,14 @@ private: int m_modeOld; - DECLARE_NO_COPY_CLASS(StretchBltModeChanger) + wxDECLARE_NO_COPY_CLASS(StretchBltModeChanger); }; +#define SET_STRETCH_BLT_MODE(hdc) \ + StretchBltModeChanger wxMAKE_UNIQUE_NAME(stretchModeChanger)(hdc) + +#endif // __WXWINCE__/!__WXWINCE__ + #if wxUSE_DYNLIB_CLASS // helper class to cache dynamically loaded libraries and not attempt reloading @@ -251,7 +258,7 @@ private: const wxChar *m_dllName; }; -static wxOnceOnlyDLLLoader wxMSIMG32DLL(_T("msimg32")); +static wxOnceOnlyDLLLoader wxMSIMG32DLL(wxT("msimg32")); // we must ensure that DLLs are unloaded before the static objects cleanup time // because we may hit the notorious DllMain() dead lock in this case if wx is @@ -269,6 +276,98 @@ private: IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule, wxModule) +namespace +{ + +#if wxUSE_DC_TRANSFORM_MATRIX + +// Class used to dynamically load world transform related API functions. +class GdiWorldTransformFuncs +{ +public: + static bool IsOk() + { + if ( !ms_worldTransformSymbolsLoaded ) + LoadWorldTransformSymbols(); + + return ms_pfnSetGraphicsMode && + ms_pfnSetWorldTransform && + ms_pfnGetWorldTransform && + ms_pfnModifyWorldTransform; + } + + typedef int (WINAPI *SetGraphicsMode_t)(HDC, int); + static SetGraphicsMode_t SetGraphicsMode() + { + if ( !ms_worldTransformSymbolsLoaded ) + LoadWorldTransformSymbols(); + + return ms_pfnSetGraphicsMode; + } + + typedef BOOL (WINAPI *SetWorldTransform_t)(HDC, const XFORM *); + static SetWorldTransform_t SetWorldTransform() + { + if ( !ms_worldTransformSymbolsLoaded ) + LoadWorldTransformSymbols(); + + return ms_pfnSetWorldTransform; + } + + typedef BOOL (WINAPI *GetWorldTransform_t)(HDC, LPXFORM); + static GetWorldTransform_t GetWorldTransform() + { + if ( !ms_worldTransformSymbolsLoaded ) + LoadWorldTransformSymbols(); + + return ms_pfnGetWorldTransform; + } + + typedef BOOL (WINAPI *ModifyWorldTransform_t)(HDC, const XFORM *, DWORD); + static ModifyWorldTransform_t ModifyWorldTransform() + { + if ( !ms_worldTransformSymbolsLoaded ) + LoadWorldTransformSymbols(); + + return ms_pfnModifyWorldTransform; + } + +private: + static void LoadWorldTransformSymbols() + { + wxDynamicLibrary dll(wxT("gdi32.dll")); + + wxDL_INIT_FUNC(ms_pfn, SetGraphicsMode, dll); + wxDL_INIT_FUNC(ms_pfn, SetWorldTransform, dll); + wxDL_INIT_FUNC(ms_pfn, GetWorldTransform, dll); + wxDL_INIT_FUNC(ms_pfn, ModifyWorldTransform, dll); + + ms_worldTransformSymbolsLoaded = true; + } + + static SetGraphicsMode_t ms_pfnSetGraphicsMode; + static SetWorldTransform_t ms_pfnSetWorldTransform; + static GetWorldTransform_t ms_pfnGetWorldTransform; + static ModifyWorldTransform_t ms_pfnModifyWorldTransform; + + static bool ms_worldTransformSymbolsLoaded; +}; + +GdiWorldTransformFuncs::SetGraphicsMode_t + GdiWorldTransformFuncs::ms_pfnSetGraphicsMode = NULL; +GdiWorldTransformFuncs::SetWorldTransform_t + GdiWorldTransformFuncs::ms_pfnSetWorldTransform = NULL; +GdiWorldTransformFuncs::GetWorldTransform_t + GdiWorldTransformFuncs::ms_pfnGetWorldTransform = NULL; +GdiWorldTransformFuncs::ModifyWorldTransform_t + GdiWorldTransformFuncs::ms_pfnModifyWorldTransform = NULL; + +bool GdiWorldTransformFuncs::ms_worldTransformSymbolsLoaded = false; + +#endif // wxUSE_DC_TRANSFORM_MATRIX + +} // anonymous namespace + #endif // wxUSE_DYNLIB_CLASS // =========================================================================== @@ -276,68 +375,44 @@ IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule, wxModule) // =========================================================================== // ---------------------------------------------------------------------------- -// wxColourChanger +// wxBrushAttrsSetter // ---------------------------------------------------------------------------- -wxColourChanger::wxColourChanger(wxMSWDCImpl& dc) : m_dc(dc) +wxBrushAttrsSetter::wxBrushAttrsSetter(wxMSWDCImpl& dc) + : wxBkModeChanger(GetHdcOf(dc)), + wxTextColoursChanger(GetHdcOf(dc)) { const wxBrush& brush = dc.GetBrush(); - if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE ) + if ( brush.IsOk() && brush.GetStyle() == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE ) { - HDC hdc = GetHdcOf(dc); - m_colFgOld = ::GetTextColor(hdc); - m_colBgOld = ::GetBkColor(hdc); - // note that Windows convention is opposite to wxWidgets one, this is // why text colour becomes the background one and vice versa - const wxColour& colFg = dc.GetTextForeground(); - if ( colFg.Ok() ) - { - ::SetBkColor(hdc, colFg.GetPixel()); - } - - const wxColour& colBg = dc.GetTextBackground(); - if ( colBg.Ok() ) - { - ::SetTextColor(hdc, colBg.GetPixel()); - } - - SetBkMode(hdc, - dc.GetBackgroundMode() == wxTRANSPARENT ? TRANSPARENT - : OPAQUE); + wxTextColoursChanger::Change(dc.GetTextBackground(), + dc.GetTextForeground()); - // flag which telsl us to undo changes in the dtor - m_changed = true; - } - else - { - // nothing done, nothing to undo - m_changed = false; + wxBkModeChanger::Change(dc.GetBackgroundMode()); } } -wxColourChanger::~wxColourChanger() -{ - if ( m_changed ) - { - // restore the colours we changed - HDC hdc = GetHdcOf(m_dc); +// ---------------------------------------------------------------------------- +// wxDC MSW-specific methods +// ---------------------------------------------------------------------------- - ::SetBkMode(hdc, TRANSPARENT); - ::SetTextColor(hdc, m_colFgOld); - ::SetBkColor(hdc, m_colBgOld); - } +WXHDC wxDC::GetHDC() const +{ + wxMSWDCImpl * const impl = wxDynamicCast(GetImpl(), wxMSWDCImpl); + return impl ? impl->GetHDC() : 0; } // --------------------------------------------------------------------------- // wxMSWDCImpl // --------------------------------------------------------------------------- -wxMSWDCImpl::wxMSWDCImpl( wxDC *owner, WXHDC hDC ) : +wxMSWDCImpl::wxMSWDCImpl( wxDC *owner, WXHDC hDC ) : wxDCImpl( owner ) -{ - Init(); - m_hDC = hDC; +{ + Init(); + m_hDC = hDC; } wxMSWDCImpl::~wxMSWDCImpl() @@ -377,12 +452,10 @@ void wxMSWDCImpl::SelectOldObjects(WXHDC dc) if (m_oldBitmap) { ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap); -#ifdef __WXDEBUG__ - if (m_selectedBitmap.Ok()) + if (m_selectedBitmap.IsOk()) { m_selectedBitmap.SetSelectedInto(NULL); } -#endif } m_oldBitmap = 0; if (m_oldPen) @@ -455,7 +528,7 @@ wxMSWDCImpl::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) co wxDCImpl::DoGetClippingBox(x, y, w, h); } -// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion() +// common part of DoSetClippingRegion() and DoSetDeviceClippingRegion() void wxMSWDCImpl::SetClippingHrgn(WXHRGN hrgn) { wxCHECK_RET( hrgn, wxT("invalid clipping region") ); @@ -490,7 +563,7 @@ void wxMSWDCImpl::SetClippingHrgn(WXHRGN hrgn) #else // !WinCE if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR ) { - wxLogLastError(_T("ExtSelectClipRgn")); + wxLogLastError(wxT("ExtSelectClipRgn")); return; } @@ -513,7 +586,7 @@ void wxMSWDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h LogicalToDeviceY(y + h)); if ( !hrgn ) { - wxLogLastError(_T("CreateRectRgn")); + wxLogLastError(wxT("CreateRectRgn")); } else { @@ -523,7 +596,7 @@ void wxMSWDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h } } -void wxMSWDCImpl::DoSetClippingRegionAsRegion(const wxRegion& region) +void wxMSWDCImpl::DoSetDeviceClippingRegion(const wxRegion& region) { SetClippingHrgn(region.GetHRGN()); } @@ -601,8 +674,8 @@ void wxMSWDCImpl::Clear() { // No, I think we should simply ignore this if printing on e.g. // a printer DC. - // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") ); - if (!m_selectedBitmap.Ok()) + // wxCHECK_RET( m_selectedBitmap.IsOk(), wxT("this DC can't be cleared") ); + if (!m_selectedBitmap.IsOk()) return; rect.left = -m_deviceOriginX; rect.top = -m_deviceOriginY; @@ -625,7 +698,7 @@ void wxMSWDCImpl::Clear() bool wxMSWDCImpl::DoFloodFill(wxCoord WXUNUSED_IN_WINCE(x), wxCoord WXUNUSED_IN_WINCE(y), const wxColour& WXUNUSED_IN_WINCE(col), - int WXUNUSED_IN_WINCE(style)) + wxFloodFillStyle WXUNUSED_IN_WINCE(style)) { #ifdef __WXWINCE__ return false; @@ -663,7 +736,7 @@ bool wxMSWDCImpl::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const { WXMICROWIN_CHECK_HDC_RET(false) - wxCHECK_MSG( col, false, _T("NULL colour parameter in wxMSWDCImpl::GetPixel") ); + wxCHECK_MSG( col, false, wxT("NULL colour parameter in wxMSWDCImpl::GetPixel") ); // get the color of the pixel COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y)); @@ -705,23 +778,23 @@ void wxMSWDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc) { + double dx = xc - x1; + double dy = yc - y1; + wxCoord r = (wxCoord)sqrt(dx*dx + dy*dy); + + #ifdef __WXWINCE__ // Slower emulation since WinCE doesn't support Pie and Arc - double r = sqrt( (x1-xc)*(x1-xc) + (y1-yc)*(y1-yc) ); double sa = acos((x1-xc)/r)/M_PI*180; // between 0 and 180 - if( y1>yc ) sa = -sa; // below center + if( y1>yc ) + sa = -sa; // below center double ea = atan2(yc-y2, x2-xc)/M_PI*180; DoDrawEllipticArcRot( xc-r, yc-r, 2*r, 2*r, sa, ea ); #else WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling - - double dx = xc - x1; - double dy = yc - y1; - double radius = (double)sqrt(dx*dx+dy*dy); - wxCoord r = (wxCoord)radius; + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling // treat the special case of full circle separately if ( x1 == x2 && y1 == y2 ) @@ -736,14 +809,16 @@ void wxMSWDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord yy2 = YLOG2DEV(y2); wxCoord xxc = XLOG2DEV(xc); wxCoord yyc = YLOG2DEV(yc); - wxCoord ray = (wxCoord) sqrt(double((xxc-xx1)*(xxc-xx1)+(yyc-yy1)*(yyc-yy1))); + dx = xxc - xx1; + dy = yyc - yy1; + wxCoord ray = (wxCoord)sqrt(dx*dx + dy*dy); wxCoord xxx1 = (wxCoord) (xxc-ray); wxCoord yyy1 = (wxCoord) (yyc-ray); wxCoord xxx2 = (wxCoord) (xxc+ray); wxCoord yyy2 = (wxCoord) (yyc+ray); - if ( m_brush.Ok() && m_brush.GetStyle() != wxTRANSPARENT ) + if ( m_brush.IsNonTransparent() ) { // Have to add 1 to bottom-right corner of rectangle // to make semi-circles look right (crooked line otherwise). @@ -779,7 +854,7 @@ void wxMSWDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, rect.bottom = y2; #ifdef __WXWINCE__ - DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK); + DrawFrameControl(GetHdc(), &rect, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_CHECKED); #else DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK); #endif @@ -794,7 +869,7 @@ void wxMSWDCImpl::DoDrawPoint(wxCoord x, wxCoord y) WXMICROWIN_CHECK_HDC COLORREF color = 0x00ffffff; - if (m_pen.Ok()) + if (m_pen.IsOk()) { color = m_pen.GetColour().GetPixel(); } @@ -808,11 +883,11 @@ void wxMSWDCImpl::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, - int WXUNUSED_IN_WINCE(fillStyle)) + wxPolygonFillMode WXUNUSED_IN_WINCE(fillStyle)) { WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling // Do things less efficiently if we have offsets if (xoffset != 0 || yoffset != 0) @@ -857,14 +932,14 @@ wxMSWDCImpl::DoDrawPolyPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, - int fillStyle) + wxPolygonFillMode fillStyle) { #ifdef __WXWINCE__ - wxDCBase::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle); + wxDCImpl::DoDrawPolyPolygon(n, count, points, xoffset, yoffset, fillStyle); #else WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling int i, cnt; for (i = cnt = 0; i < n; i++) cnt += count[i]; @@ -939,39 +1014,26 @@ void wxMSWDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord h { WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling wxCoord x2 = x + width; wxCoord y2 = y + height; - if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT)) - { - RECT rect; - rect.left = XLOG2DEV(x); - rect.top = YLOG2DEV(y); - rect.right = XLOG2DEV(x2); - rect.bottom = YLOG2DEV(y2); - (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() ); - } - else - { - // Windows draws the filled rectangles without outline (i.e. drawn with a - // transparent pen) one pixel smaller in both directions and we want them - // to have the same size regardless of which pen is used - adjust + wxCoord x2dev = XLOG2DEV(x2), + y2dev = YLOG2DEV(y2); - // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR. - if ( m_pen.GetStyle() == wxTRANSPARENT ) - { - // Apparently not needed for WinCE (see e.g. Life! demo) + // Windows (but not Windows CE) draws the filled rectangles without outline + // (i.e. drawn with a transparent pen) one pixel smaller in both directions + // and we want them to have the same size regardless of which pen is used #ifndef __WXWINCE__ - x2++; - y2++; -#endif - } - - (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2)); + if ( m_pen.IsTransparent() ) + { + x2dev++; + y2dev++; } +#endif // !__WXWINCE__ + (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), x2dev, y2dev); CalcBoundingBox(x, y); CalcBoundingBox(x2, y2); @@ -981,7 +1043,7 @@ void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wx { WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling // Now, a negative radius value is interpreted to mean // 'the proportion of the smallest X or Y dimension' @@ -998,7 +1060,7 @@ void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wx // Windows draws the filled rectangles without outline (i.e. drawn with a // transparent pen) one pixel smaller in both directions and we want them // to have the same size regardless of which pen is used - adjust - if ( m_pen.GetStyle() == wxTRANSPARENT ) + if ( m_pen.IsTransparent() ) { x2++; y2++; @@ -1015,24 +1077,25 @@ void wxMSWDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord hei { WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling - wxCoord x2 = (x+width); - wxCoord y2 = (y+height); + // +1 below makes the ellipse more similar to other platforms. + // In particular, DoDrawEllipse(x,y,1,1) should draw one point. + wxCoord x2 = x + width + 1; + wxCoord y2 = y + height + 1; + + // Problem: Windows GDI Ellipse() with x2-x == y2-y == 3 and transparent + // pen doesn't draw anything. Should we provide a workaround? - (void)Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2)); + ::Ellipse(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2)); CalcBoundingBox(x, y); CalcBoundingBox(x2, y2); } -#if wxUSE_SPLINES +#if wxUSE_SPLINES && !defined(__WXWINCE__) void wxMSWDCImpl::DoDrawSpline(const wxPointList *points) { -#ifdef __WXWINCE__ - // WinCE does not support ::PolyBezier so use generic version - wxDCBase::DoDrawSpline(points); -#else // quadratic b-spline to cubic bezier spline conversion // // quadratic spline with control points P0,P1,P2 @@ -1080,11 +1143,11 @@ void wxMSWDCImpl::DoDrawSpline(const wxPointList *points) lppt[ bezier_pos ] = lppt[ bezier_pos-1 ]; bezier_pos++; -#if !wxUSE_STL +#if !wxUSE_STD_CONTAINERS while ((node = node->GetNext()) != NULL) #else while ((node = node->GetNext())) -#endif // !wxUSE_STL +#endif // !wxUSE_STD_CONTAINERS { p = (wxPoint *)node->GetData(); x1 = x2; @@ -1121,9 +1184,8 @@ void wxMSWDCImpl::DoDrawSpline(const wxPointList *points) ::PolyBezier( GetHdc(), lppt, bezier_pos ); free(lppt); -#endif } -#endif +#endif // wxUSE_SPLINES // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) @@ -1134,7 +1196,7 @@ void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,doub WXMICROWIN_CHECK_HDC - wxColourChanger cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling + wxBrushAttrsSetter cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling wxCoord x2 = x + w; wxCoord y2 = y + h; @@ -1154,13 +1216,13 @@ void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,doub // Swap start and end positions if the end angle is less than the start angle. if (ea < sa) { - int temp; - temp = rx2; - rx2 = rx1; - rx1 = temp; - temp = ry2; - ry2 = ry1; - ry1 = temp; + int temp; + temp = rx2; + rx2 = rx1; + rx1 = temp; + temp = ry2; + ry2 = ry1; + ry1 = temp; } // draw pie with NULL_PEN first and then outline otherwise a line is @@ -1191,7 +1253,7 @@ void wxMSWDCImpl::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) { WXMICROWIN_CHECK_HDC - wxCHECK_RET( icon.Ok(), wxT("invalid icon in DrawIcon") ); + wxCHECK_RET( icon.IsOk(), wxT("invalid icon in DrawIcon") ); #ifdef __WIN32__ ::DrawIconEx(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), GetHiconOf(icon), icon.GetWidth(), icon.GetHeight(), 0, NULL, DI_NORMAL); @@ -1207,7 +1269,7 @@ void wxMSWDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool { WXMICROWIN_CHECK_HDC - wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxMSWDCImpl::DrawBitmap") ); + wxCHECK_RET( bmp.IsOk(), wxT("invalid bitmap in wxMSWDCImpl::DrawBitmap") ); int width = bmp.GetWidth(), height = bmp.GetHeight(); @@ -1227,6 +1289,8 @@ void wxMSWDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool return; } + SET_STRETCH_BLT_MODE(GetHdc()); + if ( useMask ) { wxMask *mask = bmp.GetMask(); @@ -1245,13 +1309,20 @@ void wxMSWDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool #ifdef __WIN32__ // use MaskBlt() with ROP which doesn't do anything to dst in the mask // points + bool ok = false; + +#if wxUSE_SYSTEM_OPTIONS // On some systems, MaskBlt succeeds yet is much much slower // than the wxWidgets fall-back implementation. So we need // to be able to switch this on and off at runtime. - bool ok = false; -#if wxUSE_SYSTEM_OPTIONS - if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) -#endif + // + // NB: don't query the value of the option every time but do it only + // once as otherwise it can have real (and bad) performance + // implications (see #11172) + static bool + s_maskBltAllowed = wxSystemOptions::GetOptionInt("no-maskblt") == 0; + if ( s_maskBltAllowed ) +#endif // wxUSE_SYSTEM_OPTIONS { HDC cdc = GetHdc(); HDC hdcMem = ::CreateCompatibleDC(GetHdc()); @@ -1301,16 +1372,7 @@ void wxMSWDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool wxASSERT_MSG( hbitmap, wxT("bitmap is ok but HBITMAP is NULL?") ); - COLORREF old_textground = ::GetTextColor(GetHdc()); - COLORREF old_background = ::GetBkColor(GetHdc()); - if (m_textForegroundColour.Ok()) - { - ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() ); - } - if (m_textBackgroundColour.Ok()) - { - ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); - } + wxTextColoursChanger textCol(GetHdc(), *this); #if wxUSE_PALETTE wxPalette *pal = bmp.GetPalette(); @@ -1331,14 +1393,23 @@ void wxMSWDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool ::SelectObject( memdc, hOldBitmap ); ::DeleteDC( memdc ); - - ::SetTextColor(GetHdc(), old_textground); - ::SetBkColor(GetHdc(), old_background); } } void wxMSWDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y) { + // For compatibility with other ports (notably wxGTK) and because it's + // genuinely useful, we allow passing multiline strings to DrawText(). + // However there is no native MSW function to draw them directly so we + // instead reuse the generic DrawLabel() method to render them. Of course, + // DrawLabel() itself will call back to us but with single line strings + // only so there won't be any infinite recursion here. + if ( text.find('\n') != wxString::npos ) + { + GetOwner()->DrawLabel(text, wxRect(x, y, 0, 0)); + return; + } + WXMICROWIN_CHECK_HDC DrawAnyText(text, x, y); @@ -1356,39 +1427,15 @@ void wxMSWDCImpl::DrawAnyText(const wxString& text, wxCoord x, wxCoord y) WXMICROWIN_CHECK_HDC // prepare for drawing the text - if ( m_textForegroundColour.Ok() ) - SetTextColor(GetHdc(), m_textForegroundColour.GetPixel()); - - DWORD old_background = 0; - if ( m_textBackgroundColour.Ok() ) - { - old_background = SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); - } + wxTextColoursChanger textCol(GetHdc(), *this); - SetBkMode(GetHdc(), m_backgroundMode == wxTRANSPARENT ? TRANSPARENT - : OPAQUE); + wxBkModeChanger bkMode(GetHdc(), m_backgroundMode); -#ifdef __WXWINCE__ if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), 0, NULL, text.c_str(), text.length(), NULL) == 0 ) { wxLogLastError(wxT("TextOut")); } -#else - if ( ::TextOut(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), - text.c_str(), text.length()) == 0 ) - { - wxLogLastError(wxT("TextOut")); - } -#endif - - // restore the old parameters (text foreground colour may be left because - // it never is set to anything else, but background should remain - // transparent even if we just drew an opaque string) - if ( m_textBackgroundColour.Ok() ) - (void)SetBkColor(GetHdc(), old_background); - - SetBkMode(GetHdc(), TRANSPARENT); } void wxMSWDCImpl::DoDrawRotatedText(const wxString& text, @@ -1401,7 +1448,7 @@ void wxMSWDCImpl::DoDrawRotatedText(const wxString& text, // "else" part below to avoid that DrawRotatedText(angle = 180) and // DrawRotatedText(angle = 0) use different fonts (we can't use the default // font for drawing rotated fonts unfortunately) - if ( (angle == 0.0) && m_font.Ok() ) + if ( (angle == 0.0) && m_font.IsOk() ) { DoDrawText(text, x, y); } @@ -1411,7 +1458,7 @@ void wxMSWDCImpl::DoDrawRotatedText(const wxString& text, // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT) // because it's not TrueType and so can't have non zero // orientation/escapement under Win9x - wxFont font = m_font.Ok() ? m_font : *wxSWISS_FONT; + wxFont font = m_font.IsOk() ? m_font : *wxSWISS_FONT; HFONT hfont = (HFONT)font.GetResourceHandle(); LOGFONT lf; if ( ::GetObject(hfont, sizeof(lf), &lf) == 0 ) @@ -1478,7 +1525,7 @@ void wxMSWDCImpl::DoSelectPalette(bool realize) m_oldPalette = 0; } - if ( m_palette.Ok() ) + if ( m_palette.IsOk() ) { HPALETTE oldPal = ::SelectPalette(GetHdc(), GetHpaletteOf(m_palette), @@ -1493,7 +1540,7 @@ void wxMSWDCImpl::DoSelectPalette(bool realize) void wxMSWDCImpl::SetPalette(const wxPalette& palette) { - if ( palette.Ok() ) + if ( palette.IsOk() ) { m_palette = palette; DoSelectPalette(true); @@ -1531,12 +1578,12 @@ void wxMSWDCImpl::SetFont(const wxFont& font) if ( font == m_font ) return; - if ( font.Ok() ) + if ( font.IsOk() ) { HGDIOBJ hfont = ::SelectObject(GetHdc(), GetHfontOf(font)); if ( hfont == HGDI_ERROR ) { - wxLogLastError(_T("SelectObject(font)")); + wxLogLastError(wxT("SelectObject(font)")); } else // selected ok { @@ -1552,7 +1599,7 @@ void wxMSWDCImpl::SetFont(const wxFont& font) { if ( ::SelectObject(GetHdc(), (HPEN) m_oldFont) == HGDI_ERROR ) { - wxLogLastError(_T("SelectObject(old font)")); + wxLogLastError(wxT("SelectObject(old font)")); } m_oldFont = 0; @@ -1569,12 +1616,12 @@ void wxMSWDCImpl::SetPen(const wxPen& pen) if ( pen == m_pen ) return; - if ( pen.Ok() ) + if ( pen.IsOk() ) { HGDIOBJ hpen = ::SelectObject(GetHdc(), GetHpenOf(pen)); if ( hpen == HGDI_ERROR ) { - wxLogLastError(_T("SelectObject(pen)")); + wxLogLastError(wxT("SelectObject(pen)")); } else // selected ok { @@ -1590,7 +1637,7 @@ void wxMSWDCImpl::SetPen(const wxPen& pen) { if ( ::SelectObject(GetHdc(), (HPEN) m_oldPen) == HGDI_ERROR ) { - wxLogLastError(_T("SelectObject(old pen)")); + wxLogLastError(wxT("SelectObject(old pen)")); } m_oldPen = 0; @@ -1607,29 +1654,36 @@ void wxMSWDCImpl::SetBrush(const wxBrush& brush) if ( brush == m_brush ) return; - if ( brush.Ok() ) + if ( brush.IsOk() ) { // we must make sure the brush is aligned with the logical coordinates - // before selecting it + // before selecting it or using the same brush for the background of + // different windows would result in discontinuities + wxSize sizeBrushBitmap = wxDefaultSize; wxBitmap *stipple = brush.GetStipple(); - if ( stipple && stipple->Ok() ) + if ( stipple && stipple->IsOk() ) + sizeBrushBitmap = stipple->GetSize(); + else if ( brush.IsHatch() ) + sizeBrushBitmap = wxSize(8, 8); + + if ( sizeBrushBitmap.IsFullySpecified() ) { if ( !::SetBrushOrgEx ( GetHdc(), - m_deviceOriginX % stipple->GetWidth(), - m_deviceOriginY % stipple->GetHeight(), + m_deviceOriginX % sizeBrushBitmap.x, + m_deviceOriginY % sizeBrushBitmap.y, NULL // [out] previous brush origin ) ) { - wxLogLastError(_T("SetBrushOrgEx()")); + wxLogLastError(wxT("SetBrushOrgEx()")); } } HGDIOBJ hbrush = ::SelectObject(GetHdc(), GetHbrushOf(brush)); if ( hbrush == HGDI_ERROR ) { - wxLogLastError(_T("SelectObject(brush)")); + wxLogLastError(wxT("SelectObject(brush)")); } else // selected ok { @@ -1645,7 +1699,7 @@ void wxMSWDCImpl::SetBrush(const wxBrush& brush) { if ( ::SelectObject(GetHdc(), (HPEN) m_oldBrush) == HGDI_ERROR ) { - wxLogLastError(_T("SelectObject(old brush)")); + wxLogLastError(wxT("SelectObject(old brush)")); } m_oldBrush = 0; @@ -1661,7 +1715,7 @@ void wxMSWDCImpl::SetBackground(const wxBrush& brush) m_backgroundBrush = brush; - if ( m_backgroundBrush.Ok() ) + if ( m_backgroundBrush.IsOk() ) { (void)SetBkColor(GetHdc(), m_backgroundBrush.GetColour().GetPixel()); } @@ -1677,7 +1731,7 @@ void wxMSWDCImpl::SetBackgroundMode(int mode) // and m_backgroundMode is used there } -void wxMSWDCImpl::SetLogicalFunction(int function) +void wxMSWDCImpl::SetLogicalFunction(wxRasterOperationMode function) { WXMICROWIN_CHECK_HDC @@ -1711,10 +1765,9 @@ void wxMSWDCImpl::SetRop(WXHDC dc) case wxNAND: rop = R2_NOTMASKPEN; break; case wxOR: rop = R2_MERGEPEN; break; case wxSET: rop = R2_WHITE; break; - default: - wxFAIL_MSG( wxT("unsupported logical function") ); - return; + wxFAIL_MSG( wxS("unknown logical function") ); + return; } SetROP2(GetHdc(), rop); @@ -1764,6 +1817,31 @@ wxCoord wxMSWDCImpl::GetCharWidth() const return lpTextMetric.tmAveCharWidth; } +void wxMSWDCImpl::DoGetFontMetrics(int *height, + int *ascent, + int *descent, + int *internalLeading, + int *externalLeading, + int *averageWidth) const +{ + TEXTMETRIC tm; + + GetTextMetrics(GetHdc(), &tm); + + if ( height ) + *height = tm.tmHeight; + if ( ascent ) + *ascent = tm.tmAscent; + if ( descent ) + *descent = tm.tmDescent; + if ( internalLeading ) + *internalLeading = tm.tmInternalLeading; + if ( externalLeading ) + *externalLeading = tm.tmExternalLeading; + if ( averageWidth ) + *averageWidth = tm.tmAveCharWidth; +} + void wxMSWDCImpl::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, wxCoord *descent, wxCoord *externalLeading, const wxFont *font) const @@ -1782,7 +1860,7 @@ void wxMSWDCImpl::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y HFONT hfontOld; if ( font ) { - wxASSERT_MSG( font->Ok(), _T("invalid font in wxMSWDCImpl::GetTextExtent") ); + wxASSERT_MSG( font->IsOk(), wxT("invalid font in wxMSWDCImpl::GetTextExtent") ); hfontOld = (HFONT)::SelectObject(GetHdc(), GetHfontOf(*font)); } @@ -1795,7 +1873,7 @@ void wxMSWDCImpl::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y const size_t len = string.length(); if ( !::GetTextExtentPoint32(GetHdc(), string.wx_str(), len, &sizeRect) ) { - wxLogLastError(_T("GetTextExtentPoint32()")); + wxLogLastError(wxT("GetTextExtentPoint32()")); } #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) @@ -1826,17 +1904,15 @@ void wxMSWDCImpl::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) - TEXTMETRIC tm; - ::GetTextMetrics(GetHdc(), &tm); - if (x) *x = sizeRect.cx; if (y) *y = sizeRect.cy; - if (descent) - *descent = tm.tmDescent; - if (externalLeading) - *externalLeading = tm.tmExternalLeading; + + if ( descent || externalLeading ) + { + DoGetFontMetrics(NULL, NULL, descent, NULL, externalLeading, NULL); + } if ( hfontOld ) { @@ -1886,27 +1962,58 @@ bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widt return true; } +namespace +{ + +void ApplyEffectiveScale(double scale, int sign, int *device, int *logical) +{ + // To reduce rounding errors as much as possible, we try to use the largest + // possible extent (2^27-1) for the device space but we must also avoid + // overflowing the int range i.e. ensure that logical extents are less than + // 2^31 in magnitude. So the minimal scale we can use is 1/16 as for + // anything smaller VIEWPORT_EXTENT/scale would overflow the int range. + static const double MIN_LOGICAL_SCALE = 1./16; + + double physExtent = VIEWPORT_EXTENT; + if ( scale < MIN_LOGICAL_SCALE ) + { + physExtent *= scale/MIN_LOGICAL_SCALE; + scale = MIN_LOGICAL_SCALE; + } + + *device = wxRound(physExtent); + *logical = sign*wxRound(VIEWPORT_EXTENT/scale); +} + +} // anonymous namespace + void wxMSWDCImpl::RealizeScaleAndOrigin() { - // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of - // cases we could do with MM_TEXT and in the remaining 0.9% with - // MM_ISOTROPIC (TODO!) + // although it may seem wasteful to always use MM_ANISOTROPIC here instead + // of using MM_TEXT if there is no scaling, benchmarking doesn't detect any + // noticeable difference between these mapping modes #ifndef __WXWINCE__ ::SetMapMode(GetHdc(), MM_ANISOTROPIC); - int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX, - height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY; + // wxWidgets API assumes that the coordinate space is "infinite" (i.e. only + // limited by 2^32 range of the integer coordinates) but in MSW API we must + // actually specify the extents that we use so compute them here. + + int devExtX, devExtY, // Viewport, i.e. device space, extents. + logExtX, logExtY; // Window, i.e. logical coordinate space, extents. + + ApplyEffectiveScale(m_scaleX, m_signX, &devExtX, &logExtX); + ApplyEffectiveScale(m_scaleY, m_signY, &devExtY, &logExtY); - ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL); - ::SetWindowExtEx(GetHdc(), width, height, NULL); + ::SetViewportExtEx(GetHdc(), devExtX, devExtY, NULL); + ::SetWindowExtEx(GetHdc(), logExtX, logExtY, NULL); ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL); ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL); #endif - } -void wxMSWDCImpl::SetMapMode(int mode) +void wxMSWDCImpl::SetMapMode(wxMappingMode mode) { WXMICROWIN_CHECK_HDC @@ -1956,12 +2063,12 @@ void wxMSWDCImpl::SetMapMode(int mode) break; default: - wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); + wxFAIL_MSG( wxT("unknown mapping mode in SetMapMode") ); } } - + ComputeScaleAndOrigin(); - + RealizeScaleAndOrigin(); } @@ -1973,7 +2080,7 @@ void wxMSWDCImpl::SetUserScale(double x, double y) return; wxDCImpl::SetUserScale(x,y); - + RealizeScaleAndOrigin(); } @@ -1984,10 +2091,10 @@ void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight, int signX = xLeftRight ? 1 : -1, signY = yBottomUp ? -1 : 1; - + if (signX == m_signX && signY == m_signY) return; - + wxDCImpl::SetAxisOrientation( xLeftRight, yBottomUp ); RealizeScaleAndOrigin(); @@ -2002,9 +2109,15 @@ void wxMSWDCImpl::SetLogicalOrigin(wxCoord x, wxCoord y) wxDCImpl::SetLogicalOrigin( x, y ); -#ifndef __WXWINCE__ - ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL); -#endif + RealizeScaleAndOrigin(); +} + +// For use by wxWidgets only, unless custom units are required. +void wxMSWDCImpl::SetLogicalScale(double x, double y) +{ + WXMICROWIN_CHECK_HDC + + wxDCImpl::SetLogicalScale(x,y); } void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y) @@ -2013,12 +2126,93 @@ void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y) if ( x == m_deviceOriginX && y == m_deviceOriginY ) return; - + wxDCImpl::SetDeviceOrigin( x, y ); ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL); } +// ---------------------------------------------------------------------------- +// Transform matrix +// ---------------------------------------------------------------------------- + +#if wxUSE_DC_TRANSFORM_MATRIX + +bool wxMSWDCImpl::CanUseTransformMatrix() const +{ + return GdiWorldTransformFuncs::IsOk(); +} + +bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix) +{ + if ( !GdiWorldTransformFuncs::IsOk() ) + return false; + + if ( matrix.IsIdentity() ) + { + ResetTransformMatrix(); + return true; + } + + if ( !GdiWorldTransformFuncs::SetGraphicsMode()(GetHdc(), GM_ADVANCED) ) + { + wxLogLastError(wxT("SetGraphicsMode")); + return false; + } + + wxMatrix2D mat; + wxPoint2DDouble tr; + matrix.Get(&mat, &tr); + + XFORM xform; + xform.eM11 = mat.m_11; + xform.eM12 = mat.m_12; + xform.eM21 = mat.m_21; + xform.eM22 = mat.m_22; + xform.eDx = tr.m_x; + xform.eDy = tr.m_y; + + if ( !GdiWorldTransformFuncs::SetWorldTransform()(GetHdc(), &xform) ) + { + wxLogLastError(wxT("SetWorldTransform")); + return false; + } + + return true; +} + +wxAffineMatrix2D wxMSWDCImpl::GetTransformMatrix() const +{ + wxAffineMatrix2D transform; + + if ( !GdiWorldTransformFuncs::IsOk() ) + return transform; + + XFORM xform; + if ( !GdiWorldTransformFuncs::GetWorldTransform()(GetHdc(), &xform) ) + { + wxLogLastError(wxT("GetWorldTransform")); + return transform; + } + + wxMatrix2D m(xform.eM11, xform.eM12, xform.eM21, xform.eM22); + wxPoint2DDouble p(xform.eDx, xform.eDy); + transform.Set(m, p); + + return transform; +} + +void wxMSWDCImpl::ResetTransformMatrix() +{ + if ( GdiWorldTransformFuncs::IsOk() ) + { + GdiWorldTransformFuncs::ModifyWorldTransform()(GetHdc(), NULL, MWT_IDENTITY); + GdiWorldTransformFuncs::SetGraphicsMode()(GetHdc(), GM_COMPATIBLE); + } +} + +#endif // wxUSE_DC_TRANSFORM_MATRIX + // --------------------------------------------------------------------------- // bit blit // --------------------------------------------------------------------------- @@ -2027,7 +2221,7 @@ bool wxMSWDCImpl::DoBlit(wxCoord dstX, wxCoord dstY, wxCoord dstWidth, wxCoord dstHeight, wxDC *source, wxCoord srcX, wxCoord srcY, - int rop, bool useMask, + wxRasterOperationMode rop, bool useMask, wxCoord srcMaskX, wxCoord srcMaskY) { return DoStretchBlit(dstX, dstY, dstWidth, dstHeight, source, srcX, srcY, dstWidth, dstHeight, rop, useMask, srcMaskX, srcMaskY); @@ -2038,30 +2232,30 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight, - int rop, bool useMask, + wxRasterOperationMode rop, bool useMask, wxCoord xsrcMask, wxCoord ysrcMask) { - wxCHECK_MSG( source, false, _T("wxMSWDCImpl::Blit(): NULL wxDC pointer") ); + wxCHECK_MSG( source, false, wxT("wxMSWDCImpl::Blit(): NULL wxDC pointer") ); WXMICROWIN_CHECK_HDC_RET(false) - wxDCImpl *impl = source->GetImpl(); - wxMSWDCImpl *msw_impl = wxDynamicCast( impl, wxMSWDCImpl ); - if (!msw_impl) + wxMSWDCImpl *implSrc = wxDynamicCast( source->GetImpl(), wxMSWDCImpl ); + if ( !implSrc ) { - // TODO: Do we want to be able to blit - // from other DCs too? + // TODO: Do we want to be able to blit from other DCs too? return false; } + const HDC hdcSrc = GetHdcOf(*implSrc); + // if either the source or destination has alpha channel, we must use // AlphaBlt() as other function don't handle it correctly - const wxBitmap& bmpSrc = msw_impl->GetSelectedBitmap(); - if ( bmpSrc.Ok() && (bmpSrc.HasAlpha() || - (m_selectedBitmap.Ok() && m_selectedBitmap.HasAlpha())) ) + const wxBitmap& bmpSrc = implSrc->GetSelectedBitmap(); + if ( bmpSrc.IsOk() && (bmpSrc.HasAlpha() || + (m_selectedBitmap.IsOk() && m_selectedBitmap.HasAlpha())) ) { if ( AlphaBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight, - xsrc, ysrc, srcWidth, srcHeight, GetHdcOf(*msw_impl), bmpSrc) ) + xsrc, ysrc, srcWidth, srcHeight, hdcSrc, bmpSrc) ) return true; } @@ -2070,7 +2264,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, { mask = bmpSrc.GetMask(); - if ( !(bmpSrc.Ok() && mask && mask->GetMaskBitmap()) ) + if ( !(bmpSrc.IsOk() && mask && mask->GetMaskBitmap()) ) { // don't give assert here because this would break existing // programs - just silently ignore useMask parameter @@ -2083,16 +2277,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, xsrcMask = xsrc; ysrcMask = ysrc; } - COLORREF old_textground = ::GetTextColor(GetHdc()); - COLORREF old_background = ::GetBkColor(GetHdc()); - if (m_textForegroundColour.Ok()) - { - ::SetTextColor(GetHdc(), m_textForegroundColour.GetPixel() ); - } - if (m_textBackgroundColour.Ok()) - { - ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() ); - } + wxTextColoursChanger textCol(GetHdc(), *this); DWORD dwRop; switch (rop) @@ -2132,7 +2317,8 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, // than the wxWidgets fall-back implementation. So we need // to be able to switch this on and off at runtime. #if wxUSE_SYSTEM_OPTIONS - if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0) + static bool s_maskBltAllowed = wxSystemOptions::GetOptionInt("no-maskblt") == 0; + if ( s_maskBltAllowed ) #endif { if ( dstWidth == srcWidth && dstHeight == srcHeight ) @@ -2141,7 +2327,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, ( GetHdc(), xdest, ydest, dstWidth, dstHeight, - GetHdcOf(*msw_impl), + hdcSrc, xsrc, ysrc, (HBITMAP)mask->GetMaskBitmap(), xsrcMask, ysrcMask, @@ -2160,7 +2346,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, #if wxUSE_DC_CACHEING // create a temp buffer bitmap and DCs to access it and the mask - wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, msw_impl->GetHDC()); + wxDCCacheEntry* dcCacheEntry1 = FindDCInCache(NULL, hdcSrc); dc_mask = (HDC) dcCacheEntry1->m_dc; wxDCCacheEntry* dcCacheEntry2 = FindDCInCache(dcCacheEntry1, GetHDC()); @@ -2172,7 +2358,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, buffer_bmap = (HBITMAP) bitmapCacheEntry->m_bitmap; #else // !wxUSE_DC_CACHEING // create a temp buffer bitmap and DCs to access it and the mask - dc_mask = ::CreateCompatibleDC(GetHdcOf(*source)); + dc_mask = ::CreateCompatibleDC(hdcSrc); dc_buffer = ::CreateCompatibleDC(GetHdc()); buffer_bmap = ::CreateCompatibleBitmap(GetHdc(), dstWidth, dstHeight); #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING @@ -2180,46 +2366,44 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, HGDIOBJ hOldBufferBitmap = ::SelectObject(dc_buffer, buffer_bmap); // copy dest to buffer - if ( !::BitBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight, + if ( !::BitBlt(dc_buffer, 0, 0, dstWidth, dstHeight, GetHdc(), xdest, ydest, SRCCOPY) ) { wxLogLastError(wxT("BitBlt")); } -#ifndef __WXWINCE__ - StretchBltModeChanger changeMode(dc_buffer, COLORONCOLOR); -#endif + SET_STRETCH_BLT_MODE(GetHdc()); // copy src to buffer using selected raster op - if ( !::StretchBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight, - GetHdcOf(*msw_impl), xsrc, ysrc, srcWidth, srcHeight, dwRop) ) + if ( !::StretchBlt(dc_buffer, 0, 0, dstWidth, dstHeight, + hdcSrc, xsrc, ysrc, srcWidth, srcHeight, dwRop) ) { wxLogLastError(wxT("StretchBlt")); } - // set masked area in buffer to BLACK (pixel value 0) - COLORREF prevBkCol = ::SetBkColor(GetHdc(), RGB(255, 255, 255)); - COLORREF prevCol = ::SetTextColor(GetHdc(), RGB(0, 0, 0)); - if ( !::StretchBlt(dc_buffer, 0, 0, (int)dstWidth, (int)dstHeight, - dc_mask, xsrcMask, ysrcMask, srcWidth, srcHeight, SRCAND) ) + // set masked area in buffer to BLACK { - wxLogLastError(wxT("StretchBlt")); - } + wxTextColoursChanger textCol2(GetHdc(), *wxBLACK, *wxWHITE); + if ( !::StretchBlt(dc_buffer, 0, 0, dstWidth, dstHeight, + dc_mask, xsrcMask, ysrcMask, + srcWidth, srcHeight, SRCAND) ) + { + wxLogLastError(wxT("StretchBlt")); + } - // set unmasked area in dest to BLACK - ::SetBkColor(GetHdc(), RGB(0, 0, 0)); - ::SetTextColor(GetHdc(), RGB(255, 255, 255)); - if ( !::StretchBlt(GetHdc(), xdest, ydest, (int)dstWidth, (int)dstHeight, - dc_mask, xsrcMask, ysrcMask, srcWidth, srcHeight, SRCAND) ) - { - wxLogLastError(wxT("StretchBlt")); - } - ::SetBkColor(GetHdc(), prevBkCol); // restore colours to original values - ::SetTextColor(GetHdc(), prevCol); + // set unmasked area in dest to BLACK + ::SetBkColor(GetHdc(), RGB(0, 0, 0)); + ::SetTextColor(GetHdc(), RGB(255, 255, 255)); + if ( !::StretchBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight, + dc_mask, xsrcMask, ysrcMask, + srcWidth, srcHeight, SRCAND) ) + { + wxLogLastError(wxT("StretchBlt")); + } + } // restore the original text and background colours // OR buffer to dest - success = ::BitBlt(GetHdc(), xdest, ydest, - (int)dstWidth, (int)dstHeight, + success = ::BitBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight, dc_buffer, 0, 0, SRCPAINT) != 0; if ( !success ) { @@ -2247,7 +2431,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, // FIXME: use appropriate WinCE functions #ifndef __WXWINCE__ const int caps = ::GetDeviceCaps(GetHdc(), RASTERCAPS); - if ( bmpSrc.Ok() && (caps & RC_STRETCHDIB) ) + if ( bmpSrc.IsOk() && (caps & RC_STRETCHDIB) ) { DIBSECTION ds; wxZeroMemory(ds); @@ -2256,7 +2440,18 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, sizeof(ds), &ds) == sizeof(ds) ) { - StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR); + SET_STRETCH_BLT_MODE(GetHdc()); + + // Unlike all the other functions used here (i.e. AlphaBlt(), + // MaskBlt(), BitBlt() and StretchBlt()), StretchDIBits() does + // not take into account the source DC logical coordinates + // automatically as it doesn't even work with the source HDC. + // So do this manually to ensure that the coordinates are + // interpreted in the same way here as in all the other cases. + xsrc = source->LogicalToDeviceX(xsrc); + ysrc = source->LogicalToDeviceY(ysrc); + srcWidth = source->LogicalToDeviceXRel(srcWidth); + srcHeight = source->LogicalToDeviceYRel(srcHeight); // Figure out what co-ordinate system we're supposed to specify // ysrc in. @@ -2264,7 +2459,7 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, if ( hDIB > 0 ) { // reflect ysrc - ysrc = hDIB - (ysrc + dstHeight); + ysrc = hDIB - (ysrc + srcHeight); } if ( ::StretchDIBits(GetHdc(), @@ -2295,20 +2490,18 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, #endif // __WXWINCE__ { -#ifndef __WXWINCE__ - StretchBltModeChanger changeMode(GetHdc(), COLORONCOLOR); -#endif + SET_STRETCH_BLT_MODE(GetHdc()); if ( !::StretchBlt ( GetHdc(), xdest, ydest, dstWidth, dstHeight, - GetHdcOf(*msw_impl), + hdcSrc, xsrc, ysrc, srcWidth, srcHeight, dwRop ) ) { - wxLogLastError(_T("StretchBlt")); + wxLogLastError(wxT("StretchBlt")); } else { @@ -2318,17 +2511,10 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, if ( !success ) { - if ( !::BitBlt - ( - GetHdc(), - xdest, ydest, - (int)dstWidth, (int)dstHeight, - GetHdcOf(*msw_impl), - xsrc, ysrc, - dwRop - ) ) + if ( !::BitBlt(GetHdc(), xdest, ydest, dstWidth, dstHeight, + hdcSrc, xsrc, ysrc, dwRop) ) { - wxLogLastError(_T("BitBlt")); + wxLogLastError(wxT("BitBlt")); } else { @@ -2337,9 +2523,6 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, } } - ::SetTextColor(GetHdc(), old_textground); - ::SetBkColor(GetHdc(), old_background); - return success; } @@ -2368,7 +2551,7 @@ void wxMSWDCImpl::DoGetSizeMM(int *w, int *h) const { int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES); - wxCHECK_RET( wTotal, _T("0 width device?") ); + wxCHECK_RET( wTotal, wxT("0 width device?") ); *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal; } @@ -2377,7 +2560,7 @@ void wxMSWDCImpl::DoGetSizeMM(int *w, int *h) const { int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES); - wxCHECK_RET( hTotal, _T("0 height device?") ); + wxCHECK_RET( hTotal, wxT("0 height device?") ); *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal; } @@ -2393,14 +2576,6 @@ wxSize wxMSWDCImpl::GetPPI() const return wxSize(x, y); } -// For use by wxWidgets only, unless custom units are required. -void wxMSWDCImpl::SetLogicalScale(double x, double y) -{ - WXMICROWIN_CHECK_HDC - - wxDCImpl::SetLogicalScale(x,y); -} - // ---------------------------------------------------------------------------- // DC caching // ---------------------------------------------------------------------------- @@ -2544,13 +2719,13 @@ IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule) static bool AlphaBlt(HDC hdcDst, int x, int y, int dstWidth, int dstHeight, - int srcX, int srcY, + int srcX, int srcY, int srcWidth, int srcHeight, HDC hdcSrc, const wxBitmap& bmp) { - wxASSERT_MSG( bmp.Ok() && bmp.HasAlpha(), _T("AlphaBlt(): invalid bitmap") ); - wxASSERT_MSG( hdcDst && hdcSrc, _T("AlphaBlt(): invalid HDC") ); + wxASSERT_MSG( bmp.IsOk() && bmp.HasAlpha(), wxT("AlphaBlt(): invalid bitmap") ); + wxASSERT_MSG( hdcDst && hdcSrc, wxT("AlphaBlt(): invalid HDC") ); // do we have AlphaBlend() and company in the headers? #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS @@ -2560,7 +2735,7 @@ static bool AlphaBlt(HDC hdcDst, BLENDFUNCTION); static AlphaBlend_t - pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend")); + pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(wxT("AlphaBlend")); if ( pfnAlphaBlend ) { BLENDFUNCTION bf; @@ -2577,7 +2752,7 @@ static bool AlphaBlt(HDC hdcDst, return true; } - wxLogLastError(_T("AlphaBlend")); + wxLogLastError(wxT("AlphaBlend")); } #else wxUnusedVar(hdcSrc); @@ -2585,26 +2760,26 @@ static bool AlphaBlt(HDC hdcDst, // AlphaBlend() unavailable of failed: use our own (probably much slower) // implementation -#ifdef wxHAVE_RAW_BITMAP +#ifdef wxHAS_RAW_BITMAP wxAlphaBlend(hdcDst, x, y, dstWidth, dstHeight, srcX, srcY, srcWidth, srcHeight, bmp); return true; -#else // !wxHAVE_RAW_BITMAP +#else // !wxHAS_RAW_BITMAP // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose // alpha but at least something will be shown like this) wxUnusedVar(bmp); return false; -#endif // wxHAVE_RAW_BITMAP +#endif // wxHAS_RAW_BITMAP/!wxHAS_RAW_BITMAP } // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable -#ifdef wxHAVE_RAW_BITMAP +#ifdef wxHAS_RAW_BITMAP static void wxAlphaBlend(HDC hdcDst, int xDst, int yDst, int dstWidth, int dstHeight, - int srcX, int srcY, + int srcX, int srcY, int srcWidth, int srcHeight, const wxBitmap& bmpSrc) { @@ -2615,7 +2790,7 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, if ( !::BitBlt(hdcMem, 0, 0, dstWidth, dstHeight, hdcDst, xDst, yDst, SRCCOPY) ) { - wxLogLastError(_T("BitBlt")); + wxLogLastError(wxT("BitBlt")); } // combine them with the source bitmap using alpha @@ -2623,7 +2798,7 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, dataSrc((wxBitmap &)bmpSrc); wxCHECK_RET( dataDst && dataSrc, - _T("failed to get raw data in wxAlphaBlend") ); + wxT("failed to get raw data in wxAlphaBlend") ); wxAlphaPixelData::Iterator pDst(dataDst), pSrc(dataSrc); @@ -2657,11 +2832,11 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, // and finally blit them back to the destination DC if ( !::BitBlt(hdcDst, xDst, yDst, dstWidth, dstHeight, hdcMem, 0, 0, SRCCOPY) ) { - wxLogLastError(_T("BitBlt")); + wxLogLastError(wxT("BitBlt")); } } -#endif // #ifdef wxHAVE_RAW_BITMAP +#endif // wxHAS_RAW_BITMAP void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect, const wxColour& initialColour, @@ -2675,7 +2850,7 @@ void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect, typedef BOOL (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); static GradientFill_t pfnGradientFill = - (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill")); + (GradientFill_t)wxMSIMG32DLL.GetSymbol(wxT("GradientFill")); if ( pfnGradientFill ) { @@ -2720,7 +2895,7 @@ void wxMSWDCImpl::DoGradientFillLinear (const wxRect& rect, return; } - wxLogLastError(_T("GradientFill")); + wxLogLastError(wxT("GradientFill")); } #endif // wxUSE_DYNLIB_CLASS @@ -2733,7 +2908,7 @@ static DWORD wxGetDCLayout(HDC hdc) { typedef DWORD (WINAPI *GetLayout_t)(HDC); static GetLayout_t - wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(_T("gdi32.dll"))); + wxDL_INIT_FUNC(s_pfn, GetLayout, wxDynamicLibrary(wxT("gdi32.dll"))); return s_pfnGetLayout ? s_pfnGetLayout(hdc) : (DWORD)-1; } @@ -2752,7 +2927,7 @@ void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir) { typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD); static SetLayout_t - wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(_T("gdi32.dll"))); + wxDL_INIT_FUNC(s_pfn, SetLayout, wxDynamicLibrary(wxT("gdi32.dll"))); if ( !s_pfnSetLayout ) return;