From eb055dba71c89c00dd7734c37903a891bcecea18 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Tue, 27 Jul 2021 17:14:50 +0200 Subject: [PATCH] Store clipping box in device units only if it's set with wxDCImpl::DoSetClippingRegion If derived class sets clipping region in a legitimate way by call to DoSetClippingRegion() instead of directly storing logical coordinates of the box in the internal variables we can store coordinates in device units to determine final logical coordinates more reliably even in case when coordinate transformations were applied to DC in the meantime. --- include/wx/dc.h | 6 ++++-- src/common/dcbase.cpp | 32 ++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/wx/dc.h b/include/wx/dc.h index 85c55342f9..8a3e796114 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -742,8 +742,7 @@ protected: // bounding and clipping boxes wxCoord m_minX, m_minY, m_maxX, m_maxY; // Bounding box is stored in device units. - wxCoord m_clipX1, m_clipY1, m_clipX2, m_clipY2; // Clipping box is stored in device units. - // Derived classes may store it in logical units. + wxCoord m_clipX1, m_clipY1, m_clipX2, m_clipY2; // Some derived classes operate directly on clipping box given in logical units. wxRasterOperationMode m_logicalFunction; int m_backgroundMode; @@ -765,6 +764,9 @@ private: // Return the full DC area in logical coordinates. wxRect GetLogicalArea() const; + wxCoord m_devClipX1, m_devClipY1, m_devClipX2, m_devClipY2; // For proper calculations of clipping box we need to store it in device units. + bool m_useDevClipCoords; + wxDECLARE_ABSTRACT_CLASS(wxDCImpl); }; diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index 0784915fbc..c669a028b9 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -345,6 +345,8 @@ wxDCImpl::wxDCImpl( wxDC *owner ) , m_palette() , m_hasCustomPalette(false) #endif // wxUSE_PALETTE + , m_devClipX1(0), m_devClipY1(0), m_devClipX2(0), m_devClipY2(0) + , m_useDevClipCoords(false) { m_owner = owner; } @@ -362,13 +364,16 @@ void wxDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) wxASSERT_MSG( w >= 0 && h >= 0, wxS("Clipping box size values cannot be negative") ); + // If we set clipping box with this method we can operate on device coordinates + // and calculate clipping box properly also when transfromations were applied to DC. + m_useDevClipCoords = true; wxRect clipRegion(LogicalToDevice(x, y), LogicalToDeviceRel(w, h)); if ( m_clipping ) { // New clipping box is an intersection // of required clipping box and the current one. - wxRect curRegion(m_clipX1, m_clipY1, m_clipX2 - m_clipX1, m_clipY2 - m_clipY1); + wxRect curRegion(m_devClipX1, m_devClipY1, m_devClipX2 - m_devClipX1, m_devClipY2 - m_devClipY1); clipRegion.Intersect(curRegion); } else @@ -385,14 +390,14 @@ void wxDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) if ( clipRegion.IsEmpty() ) { - m_clipX1 = m_clipY1 = m_clipX2 = m_clipY2 = 0; + m_devClipX1 = m_devClipY1 = m_devClipX2 = m_devClipY2 = 0; } else { - m_clipX1 = clipRegion.GetLeft(); - m_clipY1 = clipRegion.GetTop(); - m_clipX2 = clipRegion.GetRight() + 1; - m_clipY2 = clipRegion.GetBottom() + 1; + m_devClipX1 = clipRegion.GetLeft(); + m_devClipY1 = clipRegion.GetTop(); + m_devClipX2 = clipRegion.GetRight() + 1; + m_devClipY2 = clipRegion.GetBottom() + 1; } } @@ -420,11 +425,18 @@ bool wxDCImpl::DoGetClippingRect(wxRect& rect) const if ( m_clipping ) { - if ( m_clipX1 == m_clipX2 || m_clipY1 == m_clipY2 ) - rect = wxRect(); // empty clip region + if ( m_useDevClipCoords ) + { + if ( m_devClipX1 == m_devClipX2 || m_devClipY1 == m_devClipY2 ) + rect = wxRect(); // empty clip region + else + rect = wxRect(DeviceToLogical(m_devClipX1, m_devClipY1), DeviceToLogicalRel(m_devClipX2 - m_devClipX1, m_devClipY2 - m_devClipY1)); + } else - rect = wxRect(DeviceToLogical(m_clipX1, m_clipY1), DeviceToLogicalRel(m_clipX2 - m_clipX1, m_clipY2 - m_clipY1)); - + { + // When derived class set coordinates in logical units directly... + rect = wxRect(m_clipX1, m_clipY1, m_clipX2 - m_clipX1, m_clipY2 - m_clipY1); + } return true; } else // No active clipping region.