From dafd0f217b6130a13f068ed56bdbfe66fe578cfc Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 3 Jul 2016 21:22:43 +0200 Subject: [PATCH] Fixed setting clipping box. While setting a clipping box there is necessary to intersect it either with current clipping region location if such region exists or with wxDC surface extents if no clipping region is set. This way effective clipping box will be always inside the wxDC surface. Note: Effective clipping box can be an empty region. See #17013 --- interface/wx/dc.h | 12 +++++++----- src/common/dcbase.cpp | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/interface/wx/dc.h b/interface/wx/dc.h index ab7660a200..82aa64a36e 100644 --- a/interface/wx/dc.h +++ b/interface/wx/dc.h @@ -767,13 +767,15 @@ public: uses for the clipping region are for clipping text or for speeding up window redraws when only a known area of the screen is damaged. - Notice that you need to call DestroyClippingRegion() if you want to set + @remarks + - Calling GetClippingBox() can only make the clipping region smaller, + never larger. + + - You need to call DestroyClippingRegion() if you want to set the clipping region exactly to the region specified. - Also note that if the clipping region is empty, any previously set - clipping region is destroyed, i.e. it is equivalent to calling - DestroyClippingRegion(), and not to clipping out all drawing on the DC - as might be expected. + - If resulting clipping region is empty, then all drawing on the DC is + clipped out (all changes made by drawing operations are masked out). @see DestroyClippingRegion(), wxRegion */ diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index 63337d7ced..d298ad300c 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -368,21 +368,41 @@ wxDCImpl::~wxDCImpl() 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") ); + + wxRect newRegion(x, y, w, h); + + wxRect clipRegion; if ( m_clipping ) { - m_clipX1 = wxMax( m_clipX1, x ); - m_clipY1 = wxMax( m_clipY1, y ); - m_clipX2 = wxMin( m_clipX2, (x + w) ); - m_clipY2 = wxMin( m_clipY2, (y + h) ); + // 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); + clipRegion = curRegion.Intersect(newRegion); } else { - m_clipping = true; + // Effective clipping box is an intersection + // of required clipping box and DC surface. + int dcWidth, dcHeight; + DoGetSize(&dcWidth, &dcHeight); + wxRect dcRect(wxSize(dcWidth, dcHeight)); + clipRegion = dcRect.Intersect(newRegion); - m_clipX1 = x; - m_clipY1 = y; - m_clipX2 = x + w; - m_clipY2 = y + h; + m_clipping = true; + } + + if ( clipRegion.IsEmpty() ) + { + m_clipX1 = m_clipY1 = m_clipX2 = m_clipY2 = 0; + } + else + { + m_clipX1 = clipRegion.GetLeftTop().x; + m_clipY1 = clipRegion.GetLeftTop().y; + m_clipX2 = clipRegion.GetBottomRight().x + 1; + m_clipY2 = clipRegion.GetBottomRight().y + 1; } }