Add wxGraphicsContext::GetClipBox() function

This method returns bounding box of the current clipping region.
Added declaration, documentation and implemented for GDI+, Direct2D, Cairo renderers.
This commit is contained in:
Artur Wieczorek
2016-08-21 20:57:39 +02:00
parent 1927a2f8a0
commit 480a003c00
7 changed files with 159 additions and 0 deletions

View File

@@ -3230,6 +3230,7 @@ public:
void Clip(const wxRegion&) wxOVERRIDE {}
void Clip(wxDouble, wxDouble, wxDouble, wxDouble) wxOVERRIDE {}
void ResetClip() wxOVERRIDE {}
void GetClipBox(wxDouble*, wxDouble*, wxDouble*, wxDouble*) wxOVERRIDE {}
void* GetNativeContext() wxOVERRIDE { return NULL; }
bool SetAntialiasMode(wxAntialiasMode) wxOVERRIDE { return false; }
bool SetInterpolationQuality(wxInterpolationQuality) wxOVERRIDE { return false; }
@@ -3327,6 +3328,8 @@ public:
void ResetClip() wxOVERRIDE;
void GetClipBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h) wxOVERRIDE;
// The native context used by wxD2DContext is a Direct2D render target.
void* GetNativeContext() wxOVERRIDE;
@@ -3618,6 +3621,102 @@ void wxD2DContext::ResetClip()
GetRenderTarget()->SetTransform(&currTransform);
}
void wxD2DContext::GetClipBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h)
{
// To obtain actual clipping box we have to start with rectangle
// covering the entire render target and interesect with this rectangle
// all clipping layers. Bounding box of the final geometry
// (being intersection of all clipping layers) is a clipping box.
HRESULT hr;
wxCOMPtr<ID2D1RectangleGeometry> rectGeometry;
hr = m_direct2dFactory->CreateRectangleGeometry(
D2D1::RectF(0.0F, 0.0F, (FLOAT)m_width, (FLOAT)m_height),
&rectGeometry);
wxCHECK_HRESULT_RET(hr);
wxCOMPtr<ID2D1Geometry> clipGeometry(rectGeometry);
wxStack<LayerData> layers(m_layers);
while( !layers.empty() )
{
LayerData ld = layers.top();
layers.pop();
if ( ld.type == CLIP_LAYER )
{
// If current geometry is empty (null region)
// or there is no intersection between geometries
// then final result is "null" rectangle geometry.
FLOAT area;
hr = ld.geometry->ComputeArea(ld.transformMatrix, &area);
wxCHECK_HRESULT_RET(hr);
D2D1_GEOMETRY_RELATION geomRel;
hr = clipGeometry->CompareWithGeometry(ld.geometry, ld.transformMatrix, &geomRel);
wxCHECK_HRESULT_RET(hr);
if ( area <= FLT_MIN || geomRel == D2D1_GEOMETRY_RELATION_DISJOINT )
{
wxCOMPtr<ID2D1RectangleGeometry> nullGeometry;
hr = m_direct2dFactory->CreateRectangleGeometry(
D2D1::RectF(0.0F, 0.0F, 0.0F, 0.0F), &nullGeometry);
wxCHECK_HRESULT_RET(hr);
clipGeometry.reset();
clipGeometry = nullGeometry;
break;
}
wxCOMPtr<ID2D1PathGeometry> pathGeometryClip;
hr = m_direct2dFactory->CreatePathGeometry(&pathGeometryClip);
wxCHECK_HRESULT_RET(hr);
wxCOMPtr<ID2D1GeometrySink> pGeometrySink;
hr = pathGeometryClip->Open(&pGeometrySink);
wxCHECK_HRESULT_RET(hr);
hr = clipGeometry->CombineWithGeometry(ld.geometry, D2D1_COMBINE_MODE_INTERSECT,
ld.transformMatrix, pGeometrySink);
wxCHECK_HRESULT_RET(hr);
hr = pGeometrySink->Close();
wxCHECK_HRESULT_RET(hr);
pGeometrySink.reset();
clipGeometry = pathGeometryClip;
pathGeometryClip.reset();
}
}
// Final clipping geometry is given in device coordinates
// so we need to transform its bounds to logical coordinates.
D2D1::Matrix3x2F currTransform;
GetRenderTarget()->GetTransform(&currTransform);
currTransform.Invert();
D2D1_RECT_F bounds;
// First check if clip region is empty.
FLOAT clipArea;
hr = clipGeometry->ComputeArea(currTransform, &clipArea);
wxCHECK_HRESULT_RET(hr);
if ( clipArea <= FLT_MIN )
{
bounds.left = bounds.top = bounds.right = bounds.bottom = 0.0F;
}
else
{
// If it is not empty then get it bounds.
hr = clipGeometry->GetBounds(currTransform, &bounds);
wxCHECK_HRESULT_RET(hr);
}
if ( x )
*x = bounds.left;
if ( y )
*y = bounds.top;
if ( w )
*w = (double)bounds.right - bounds.left;
if ( h )
*h = (double)bounds.bottom - bounds.top;
}
void* wxD2DContext::GetNativeContext()
{
return &m_renderTargetHolder;