X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/dfc2e4961e425f40d39849cf3546f70e07c9239d..96c9640205933ad0673d5af2c96af0816c50160c:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index e0e1ec6523..c7f3cfa665 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -34,6 +34,7 @@ #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" @@ -82,7 +83,9 @@ IMPLEMENT_ABSTRACT_CLASS(wxMSWDCImpl, wxDCImpl) // constants // --------------------------------------------------------------------------- -static const int VIEWPORT_EXTENT = 1024; +// 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) @@ -1959,6 +1962,31 @@ 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() { // although it may seem wasteful to always use MM_ANISOTROPIC here instead @@ -1969,34 +1997,13 @@ void wxMSWDCImpl::RealizeScaleAndOrigin() // 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 we more or less arbitrarily - // decide to use "base" VIEWPORT_EXTENT and adjust it depending on scale. - // - // To avoid rounding errors we prefer to multiply by the scale if it's > 1 - // and to divide by it if it's < 1. + // 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. - if ( m_scaleX >= 1 ) - { - devExtX = VIEWPORT_EXTENT*m_scaleX; - logExtX = m_signX*VIEWPORT_EXTENT; - } - else - { - devExtX = VIEWPORT_EXTENT; - logExtX = m_signX*VIEWPORT_EXTENT/m_scaleX; - } - if ( m_scaleY >= 1 ) - { - devExtY = VIEWPORT_EXTENT*m_scaleY; - logExtY = m_signY*VIEWPORT_EXTENT; - } - else - { - devExtY = VIEWPORT_EXTENT; - logExtY = m_signY*VIEWPORT_EXTENT/m_scaleY; - } + ApplyEffectiveScale(m_scaleX, m_signX, &devExtX, &logExtX); + ApplyEffectiveScale(m_scaleY, m_signY, &devExtY, &logExtY); ::SetViewportExtEx(GetHdc(), devExtX, devExtY, NULL); ::SetWindowExtEx(GetHdc(), logExtX, logExtY, NULL); @@ -2310,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 ) @@ -2434,6 +2442,17 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, { 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. const LONG hDIB = ds.dsBmih.biHeight;