From dfc966bf1e8bdac2ae2450770d9bbb01f9b6c6ab Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Thu, 1 Sep 2016 20:48:26 +0200 Subject: [PATCH] Fix retrieving clipping box after changing wxDC coordinates (MSW) Member data containing clipping box have to be updated not only when the clipping region is explicitly changed by SetClippingRegion()/DestroyClippingRegion() but also when existing HDC is associated with wxDC using SetHDC() or when wxDC coordinates are transformed with SetDeviceOrigin(), SetLogicalOrigin(), SetUserScale(), SetLogicalScale(), SetTransformMatrix() or ResetTransformMatrix(). When any of these functions is called then clipping box data are marked as invalid and updated using GetClipBox() Win API at nearest call to GetClippingBox(). See #17646. --- docs/changes.txt | 1 + include/wx/msw/dc.h | 6 ++++-- src/msw/dc.cpp | 26 ++++++++++++++++++++++---- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 6c2029a5cf..e02c41a436 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -124,6 +124,7 @@ wxMSW: - Restore dispatching wxThreadEvent while resizing the window broken in 3.1.0. - Fix wxGraphicsMatrix::TransformDistance for Direct2D renderer. - Fix wxDC::Clear() for rotated DC. +- Fix wxDC::GetClippingBox() for transformed wxDC. wxOSX: diff --git a/include/wx/msw/dc.h b/include/wx/msw/dc.h index b4f603023c..01eb90fbe8 100644 --- a/include/wx/msw/dc.h +++ b/include/wx/msw/dc.h @@ -121,8 +121,7 @@ public: // return it if asked -- but avoid calling ::GetClipBox() right now as // it could be unnecessary wasteful m_clipping = true; - m_clipX1 = - m_clipX2 = 0; + m_isClipBoxValid = false; } void* GetHandle() const { return (void*)GetHDC(); } @@ -164,6 +163,7 @@ protected: #if wxUSE_PALETTE m_oldPalette = NULL; #endif // wxUSE_PALETTE + m_isClipBoxValid = false; } // create an uninitialized DC: this should be only used by the derived @@ -323,6 +323,8 @@ protected: static wxObjectList sm_dcCache; #endif + bool m_isClipBoxValid; + wxDECLARE_CLASS(wxMSWDCImpl); wxDECLARE_NO_COPY_CLASS(wxMSWDCImpl); }; diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 193067414c..5d19524668 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -579,21 +579,32 @@ void wxMSWDCImpl::UpdateClipBox() m_clipY1 = (wxCoord) YDEV2LOG(rect.top); m_clipX2 = (wxCoord) XDEV2LOG(rect.right); m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); + m_isClipBoxValid = true; } void wxMSWDCImpl::DoGetClippingBox(wxCoord *x, wxCoord *y, wxCoord *w, wxCoord *h) const { // check if we should try to retrieve the clipping region possibly not set - // by our SetClippingRegion() but preset by Windows:this can only happen - // when we're associated with an existing HDC usign SetHDC(), see there - if ( m_clipping && !m_clipX1 && !m_clipX2 ) + // by our SetClippingRegion() but preset or modified by Windows: this + // can happen when we're associated with an existing HDC using SetHDC() or + // when wxDC logical coordinates are transformed with SetDeviceOrigin(), + // SetLogicalOrigin(), SetUserScale(), SetLogicalScale(), + // SetTransformMatrix(), ResetTransformMatrix(). + if ( !m_isClipBoxValid ) { wxMSWDCImpl *self = wxConstCast(this, wxMSWDCImpl); self->UpdateClipBox(); } - wxDCImpl::DoGetClippingBox(x, y, w, h); + if ( x ) + *x = m_clipX1; + if ( y ) + *y = m_clipY1; + if ( w ) + *w = m_clipX2 - m_clipX1; + if ( h ) + *h = m_clipY2 - m_clipY1; } // common part of DoSetClippingRegion() and DoSetDeviceClippingRegion() @@ -679,6 +690,7 @@ void wxMSWDCImpl::DestroyClippingRegion() } wxDCImpl::DestroyClippingRegion(); + m_isClipBoxValid = false; } // --------------------------------------------------------------------------- @@ -1868,6 +1880,8 @@ void wxMSWDCImpl::RealizeScaleAndOrigin() ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL); ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL); + + m_isClipBoxValid = false; } void wxMSWDCImpl::SetMapMode(wxMappingMode mode) @@ -1977,6 +1991,8 @@ void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y) wxDCImpl::SetDeviceOrigin( x, y ); ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL); + + m_isClipBoxValid = false; } // ---------------------------------------------------------------------------- @@ -2022,6 +2038,7 @@ bool wxMSWDCImpl::SetTransformMatrix(const wxAffineMatrix2D &matrix) return false; } + m_isClipBoxValid = false; return true; } @@ -2047,6 +2064,7 @@ void wxMSWDCImpl::ResetTransformMatrix() { ::ModifyWorldTransform(GetHdc(), NULL, MWT_IDENTITY); ::SetGraphicsMode(GetHdc(), GM_COMPATIBLE); + m_isClipBoxValid = false; } #endif // wxUSE_DC_TRANSFORM_MATRIX