Fix setting wxGCDC clipping region with device coordinates

Currently region given in device coordinates is decomposed into the stripes which are next transformed to the logical coordinates required by underlying wxGraphicsContext::Clip() function. Some of these stripes given in device coordinates can have 1-pixel height what after transformation to logical coordinates can give zero-height stripes (after rounding). This can lead to the situation that in the region transformed to logical coordinates some stripes can disappear and final transformed region shape is different from the source shape (it has gaps).
To fix this issue device coordinates of the region are not manually transformed to the logical coordinates but instead wxGraphicsContext's is temporarily set to the state where its logical coordinates are equivalent to device coordinates and thus clipping region can be applied directly.

Closes #17609
This commit is contained in:
Artur Wieczorek
2016-07-29 21:12:32 +02:00
parent 0fc246176a
commit ea8cb7a24a

View File

@@ -303,31 +303,34 @@ void wxGCDCImpl::DoSetDeviceClippingRegion( const wxRegion &region )
// region is in device coordinates
wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetDeviceClippingRegion - invalid DC") );
// Convert device coordinates to logical coordinates
// for all region components.
wxRegion logRegion;
if ( region.IsEmpty() )
{
// Empty region is skipped by iterator
// so we have to copy it directly.
logRegion = region;
}
else
{
wxRegionIterator ri(region);
while (ri)
{
logRegion.Union(DeviceToLogicalX(ri.GetX()),
DeviceToLogicalY(ri.GetY()),
DeviceToLogicalXRel(ri.GetWidth()),
DeviceToLogicalYRel(ri.GetHeight()));
++ri;
}
}
// Because graphics context works with logical coordinates
// and clipping region is given in device coordinates
// we need temporarily reset graphics context's coordinate system
// to the initial state in which logical and device coordinate
// systems are equivalent.
// So, at first save current transformation parameters.
wxGraphicsMatrix currTransform = m_graphicContext->CreateMatrix();
currTransform = m_graphicContext->GetTransform();
// Reset coordinate system with identity transformation matrix
// to make logical coordinates the same as device coordinates.
wxGraphicsMatrix m = m_graphicContext->CreateMatrix();
m_graphicContext->SetTransform(m);
m_graphicContext->Clip(logRegion);
// Set clipping region
m_graphicContext->Clip(region);
wxRect newRegion = logRegion.GetBox();
// Restore original transformation settings.
m_graphicContext->SetTransform(currTransform);
// Convert bounding box of the region to logical coordinates
// for further use.
wxRect newRegion = region.GetBox();
wxPoint logPos = wxPoint(DeviceToLogicalX(newRegion.GetLeft()),
DeviceToLogicalY(newRegion.GetTop()));
wxSize logSize = wxSize(DeviceToLogicalXRel(newRegion.GetWidth()),
DeviceToLogicalYRel(newRegion.GetHeight()));
newRegion.SetPosition(logPos);
newRegion.SetSize(logSize);
wxRect clipRegion;
if ( m_clipping )