wxWidgets/tests/graphics/clippingbox.cpp
Artur Wieczorek a37ed9a2b5 Add tests of setting clipping region and retrieving clipping box
These new tests are about setting clipping region and retrieving clipping box for wxDC and wxGCDC with applied transformations.

See #17646
2016-09-01 20:35:09 +02:00

2161 lines
69 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/graphics/clippingbox.cpp
// Purpose: clipping box unit tests
// Author: Artur Wieczorek
// Created: 2016-06-29
// Copyright: (c) 2016 wxWidgets development team
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/bitmap.h"
#include "wx/dcmemory.h"
#if wxUSE_GRAPHICS_CONTEXT
#include "wx/dcgraph.h"
#endif // wxUSE_GRAPHICS_CONTEXT
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
static const wxSize s_dcSize(100, 120);
static const wxColour s_bgColour(*wxWHITE); // colour to draw outside clipping box
static const wxColour s_fgColour(*wxGREEN); // colour to draw inside clipping box
static const wxColour s_tmpColour(*wxBLUE);
#if wxUSE_IMAGE
static bool CompareImageFuzzy(const wxImage& img1, const wxImage& img2, int posTolerance = 0)
{
// For each (x,y) pixel in the image1 we check
// if there is a pixel of the same value in the square
// area (x-d..x+d, y-d..y+d) around the pixel (x,y)
// in the image2. If not, we consider pixels
// and images as different.
if ( img1.GetWidth() != img2.GetWidth() )
return false;
if ( img1.GetHeight() != img2.GetHeight() )
return false;
const int w = img1.GetWidth();
const int h = img1.GetHeight();
for ( int y1 = 0; y1 < h; y1++ )
{
int y2min = wxMax(y1 - posTolerance, 0);
int y2max = wxMin(y1 + posTolerance, h);
for( int x1 = 0; x1 < w; x1++ )
{
int x2min = wxMax(x1 - posTolerance, 0);
int x2max = wxMin(x1 + posTolerance, w);
unsigned char r1 = img1.GetRed(x1, y1);
unsigned char g1 = img1.GetGreen(x1, y1);
unsigned char b1 = img1.GetBlue(x1, y1);
bool pix2Found = false;
for( int y2 = y2min; y2 <= y2max && !pix2Found; y2++ )
for( int x2 = x2min; x2 <= x2max; x2++ )
{
if( r1 == img2.GetRed(x2, y2) &&
g1 == img2.GetGreen(x2, y2) &&
b1 == img2.GetBlue(x2, y2))
{
pix2Found = true;
break;
}
}
if ( !pix2Found )
return false;
}
}
return true;
}
#endif // wxUSE_IMAGE
class ClippingBoxTestCaseBase : public CppUnit::TestCase
{
public:
ClippingBoxTestCaseBase()
{
m_bmp.Create(s_dcSize);
}
virtual ~ClippingBoxTestCaseBase()
{
m_bmp = wxNullBitmap;
}
protected:
void CheckBoxPosition(int cur_x, int cur_y, int cur_w, int cur_h,
int act_x, int act_y, int act_w, int act_h,
int posTolerance = 0);
void CheckClipRect(int x, int y, int width, int height);
void CheckClipWithBitmap(const wxBitmap& bmpRef, int posTolerance = 0);
wxBitmap m_bmp;
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseBase);
};
// ====================
// wxDC / wxGCDC tests
// ====================
class ClippingBoxTestCaseDCBase : public ClippingBoxTestCaseBase
{
public:
ClippingBoxTestCaseDCBase()
{
m_dc = NULL;
}
virtual ~ClippingBoxTestCaseDCBase()
{
}
virtual void setUp() { wxASSERT( m_dc ); }
virtual wxDC* GetDC(wxMemoryDC* dc) = 0;
protected:
void CheckClipPos(int x, int y, int width, int height, int posTolerance = 0);
void CheckClipBox(int x, int y, int width, int height,
int devX, int devY, int devWidth, int devHeight);
void CheckClipShape(const wxBitmap& bmpRef, int posTolerance);
void InitialState();
void InitialStateWithTransformedDC();
void InitialStateWithRotatedDC();
void OneRegion();
void OneLargeRegion();
void OneOuterRegion();
void OneRegionNegDim();
void OneRegionAndReset();
void OneRegionAndEmpty();
void OneRegionOverTransformedDC();
void OneRegionAndDCTransformation();
void TwoRegionsOverlapping();
void TwoRegionsOverlappingNegDim();
void TwoRegionsNonOverlapping();
void TwoRegionsNonOverlappingNegDim();
void OneDevRegion();
void OneLargeDevRegion();
void OneOuterDevRegion();
void OneDevRegionNegDim();
void OneDevRegionNonRect();
void OneDevRegionAndReset();
void OneDevRegionAndEmpty();
void OneDevRegionOverTransformedDC();
void OneDevRegionAndDCTransformation();
void TwoDevRegionsOverlapping();
void TwoDevRegionsOverlappingNegDim();
void TwoDevRegionsNonOverlapping();
void TwoDevRegionsNonOverlappingNegDim();
virtual void FlushDC() = 0;
wxDC* m_dc;
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseDCBase);
};
// ===========
// wxDC tests
// ===========
class ClippingBoxTestCaseDC : public ClippingBoxTestCaseDCBase
{
public:
ClippingBoxTestCaseDC()
{
m_mdc.SelectObject(m_bmp);
m_dc = &m_mdc;
}
virtual ~ClippingBoxTestCaseDC()
{
m_mdc.SelectObject(wxNullBitmap);
}
virtual void setUp() wxOVERRIDE
{
m_mdc.DestroyClippingRegion();
wxBrush bgBrush(s_bgColour, wxBRUSHSTYLE_SOLID);
m_mdc.SetBackground(bgBrush);
m_mdc.Clear();
}
virtual wxDC* GetDC(wxMemoryDC* dc) wxOVERRIDE
{
return dc;
}
protected:
virtual void FlushDC() wxOVERRIDE {}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseDC );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedDC );
CPPUNIT_TEST( InitialStateWithRotatedDC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionOverTransformedDC );
CPPUNIT_TEST( OneRegionAndDCTransformation );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( OneDevRegion);
CPPUNIT_TEST( OneLargeDevRegion );
CPPUNIT_TEST( OneOuterDevRegion );
CPPUNIT_TEST( OneDevRegionNegDim );
CPPUNIT_TEST( OneDevRegionNonRect );
CPPUNIT_TEST( OneDevRegionAndReset);
CPPUNIT_TEST( OneDevRegionAndEmpty );
CPPUNIT_TEST( OneDevRegionOverTransformedDC);
CPPUNIT_TEST( OneDevRegionAndDCTransformation );
CPPUNIT_TEST( TwoDevRegionsOverlapping );
CPPUNIT_TEST( TwoDevRegionsOverlappingNegDim);
CPPUNIT_TEST( TwoDevRegionsNonOverlapping );
CPPUNIT_TEST( TwoDevRegionsNonOverlappingNegDim );
CPPUNIT_TEST_SUITE_END();
protected:
wxMemoryDC m_mdc;
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseDC);
};
// For GTK+ 3 wxDC is equivalent to wxGCDC
// and hence doesn't need to be tested individually.
#if !defined(__WXGTK3__)
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseDC );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseDC, "ClippingBoxTestCaseDC" );
#endif // !__WXGTK3__
#if wxUSE_GRAPHICS_CONTEXT
// =============
// wxGCDC tests
// =============
class ClippingBoxTestCaseGCDC : public ClippingBoxTestCaseDC
{
public:
ClippingBoxTestCaseGCDC()
{
m_gcdc = new wxGCDC(m_mdc);
m_dc = m_gcdc;
}
virtual ~ClippingBoxTestCaseGCDC()
{
delete m_gcdc;
}
virtual void setUp() wxOVERRIDE
{
CPPUNIT_ASSERT_MESSAGE("Invalid wxGCDC", m_gcdc);
wxGraphicsContext* ctx = m_gcdc->GetGraphicsContext();
ctx->SetAntialiasMode(wxANTIALIAS_NONE);
ctx->DisableOffset();
m_gcdc->DestroyClippingRegion();
wxBrush bgBrush(s_bgColour, wxBRUSHSTYLE_SOLID);
m_gcdc->SetBackground(bgBrush);
m_gcdc->Clear();
}
virtual wxDC* GetDC(wxMemoryDC* dc) wxOVERRIDE
{
wxGraphicsRenderer* rend = m_gcdc->GetGraphicsContext()->GetRenderer();
wxGraphicsContext* ctx = rend->CreateContext(*dc);
ctx->SetAntialiasMode(wxANTIALIAS_NONE);
ctx->DisableOffset();
return new wxGCDC(ctx);
}
protected:
virtual void FlushDC() wxOVERRIDE
{
m_gcdc->GetGraphicsContext()->Flush();
}
void InitialStateWithRotatedGCForDC();
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCDC );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedDC );
CPPUNIT_TEST( InitialStateWithRotatedDC );
CPPUNIT_TEST( InitialStateWithRotatedGCForDC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionOverTransformedDC );
CPPUNIT_TEST( OneRegionAndDCTransformation );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( OneDevRegion);
CPPUNIT_TEST( OneLargeDevRegion );
CPPUNIT_TEST( OneOuterDevRegion );
CPPUNIT_TEST( OneDevRegionNegDim );
CPPUNIT_TEST( OneDevRegionNonRect );
CPPUNIT_TEST( OneDevRegionAndReset);
CPPUNIT_TEST( OneDevRegionAndEmpty );
CPPUNIT_TEST( OneDevRegionOverTransformedDC);
CPPUNIT_TEST( OneDevRegionAndDCTransformation );
CPPUNIT_TEST( TwoDevRegionsOverlapping );
CPPUNIT_TEST( TwoDevRegionsOverlappingNegDim);
CPPUNIT_TEST( TwoDevRegionsNonOverlapping );
CPPUNIT_TEST( TwoDevRegionsNonOverlappingNegDim );
CPPUNIT_TEST_SUITE_END();
protected:
wxGCDC* m_gcdc;
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCDC);
};
// For MSW we have individual test cases for each graphics renderer
// so we don't need to test wxGCDC with default renderer.
#ifndef __WXMSW__
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCDC );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCDC, "ClippingBoxTestCaseGCDC" );
#endif // !__WXMSW__
#ifdef __WXMSW__
// GDI+ and Direct2D are available only under MSW.
#if wxUSE_GRAPHICS_GDIPLUS
class ClippingBoxTestCaseGCDCGDIPlus : public ClippingBoxTestCaseGCDC
{
public:
ClippingBoxTestCaseGCDCGDIPlus()
{
wxGraphicsRenderer* rend = wxGraphicsRenderer::GetGDIPlusRenderer();
wxGraphicsContext* ctx = rend->CreateContext(m_mdc);
m_gcdc->SetGraphicsContext(ctx);
}
virtual ~ClippingBoxTestCaseGCDCGDIPlus() {}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCDCGDIPlus );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedDC );
CPPUNIT_TEST( InitialStateWithRotatedDC );
CPPUNIT_TEST( InitialStateWithRotatedGCForDC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionOverTransformedDC );
CPPUNIT_TEST( OneRegionAndDCTransformation );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( OneDevRegion);
CPPUNIT_TEST( OneLargeDevRegion );
CPPUNIT_TEST( OneOuterDevRegion );
CPPUNIT_TEST( OneDevRegionNegDim );
CPPUNIT_TEST( OneDevRegionNonRect );
CPPUNIT_TEST( OneDevRegionAndReset);
CPPUNIT_TEST( OneDevRegionAndEmpty );
CPPUNIT_TEST( OneDevRegionOverTransformedDC);
CPPUNIT_TEST( OneDevRegionAndDCTransformation );
CPPUNIT_TEST( TwoDevRegionsOverlapping );
CPPUNIT_TEST( TwoDevRegionsOverlappingNegDim);
CPPUNIT_TEST( TwoDevRegionsNonOverlapping );
CPPUNIT_TEST( TwoDevRegionsNonOverlappingNegDim );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCDCGDIPlus);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCDCGDIPlus );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCDCGDIPlus, "ClippingBoxTestCaseGCDCGDIPlus" );
#endif // wxUSE_GRAPHICS_GDIPLUS
#if wxUSE_GRAPHICS_DIRECT2D
class ClippingBoxTestCaseGCDCDirect2D : public ClippingBoxTestCaseGCDC
{
public:
ClippingBoxTestCaseGCDCDirect2D()
{
wxGraphicsRenderer* rend = wxGraphicsRenderer::GetDirect2DRenderer();
wxGraphicsContext* ctx = rend->CreateContext(m_mdc);
m_gcdc->SetGraphicsContext(ctx);
}
virtual ~ClippingBoxTestCaseGCDCDirect2D() {}
virtual void FlushDC()
{
// Apparently, flushing native Direct2D renderer
// is not enough to update underlying DC (bitmap)
// and therefore we have to destroy the renderer
// to do so.
ClippingBoxTestCaseGCDC::FlushDC();
m_gcdc->SetGraphicsContext(NULL);
}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCDCDirect2D );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedDC );
CPPUNIT_TEST( InitialStateWithRotatedDC );
CPPUNIT_TEST( InitialStateWithRotatedGCForDC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionOverTransformedDC );
CPPUNIT_TEST( OneRegionAndDCTransformation );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( OneDevRegion);
CPPUNIT_TEST( OneLargeDevRegion );
CPPUNIT_TEST( OneOuterDevRegion );
CPPUNIT_TEST( OneDevRegionNegDim );
CPPUNIT_TEST( OneDevRegionNonRect );
CPPUNIT_TEST( OneDevRegionAndReset);
CPPUNIT_TEST( OneDevRegionAndEmpty );
CPPUNIT_TEST( OneDevRegionOverTransformedDC);
CPPUNIT_TEST( OneDevRegionAndDCTransformation );
CPPUNIT_TEST( TwoDevRegionsOverlapping );
CPPUNIT_TEST( TwoDevRegionsOverlappingNegDim);
CPPUNIT_TEST( TwoDevRegionsNonOverlapping );
CPPUNIT_TEST( TwoDevRegionsNonOverlappingNegDim );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCDCDirect2D);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCDCDirect2D );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCDCDirect2D, "ClippingBoxTestCaseGCDCDirect2D" );
#endif // wxUSE_GRAPHICS_DIRECT2D
#endif // __WXMSW__
#if wxUSE_CAIRO
class ClippingBoxTestCaseGCDCCairo : public ClippingBoxTestCaseGCDC
{
public:
ClippingBoxTestCaseGCDCCairo()
{
wxGraphicsRenderer* rend = wxGraphicsRenderer::GetCairoRenderer();
wxGraphicsContext* ctx = rend->CreateContext(m_mdc);
m_gcdc->SetGraphicsContext(ctx);
}
virtual ~ClippingBoxTestCaseGCDCCairo() {}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCDCCairo );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedDC );
CPPUNIT_TEST( InitialStateWithRotatedDC );
CPPUNIT_TEST( InitialStateWithRotatedGCForDC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionOverTransformedDC );
CPPUNIT_TEST( OneRegionAndDCTransformation );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( OneDevRegion);
CPPUNIT_TEST( OneLargeDevRegion );
CPPUNIT_TEST( OneOuterDevRegion );
CPPUNIT_TEST( OneDevRegionNegDim );
CPPUNIT_TEST( OneDevRegionNonRect );
CPPUNIT_TEST( OneDevRegionAndReset);
CPPUNIT_TEST( OneDevRegionAndEmpty );
CPPUNIT_TEST( OneDevRegionOverTransformedDC);
CPPUNIT_TEST( OneDevRegionAndDCTransformation );
CPPUNIT_TEST( TwoDevRegionsOverlapping );
CPPUNIT_TEST( TwoDevRegionsOverlappingNegDim);
CPPUNIT_TEST( TwoDevRegionsNonOverlapping );
CPPUNIT_TEST( TwoDevRegionsNonOverlappingNegDim );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCDCCairo);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCDCCairo );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCDCCairo, "ClippingBoxTestCaseGCDCCairo" );
#endif // wxUSE_CAIRO
#endif // wxUSE_GRAPHICS_CONTEXT
// Helper class to hold rectangle
// which size is guaranteed to be >= 0
class wxClipRect : public wxRect
{
public:
wxClipRect(int xx, int yy, int w, int h, int boundWidth = 1)
{
if ( w < 0 )
{
w = -w;
xx -= (w - boundWidth);
}
if ( h < 0 )
{
h = -h;
yy -= (h - boundWidth);
}
x = xx;
y = yy;
width = w;
height = h;
}
};
// ===== Implementation =====
static bool inline IsCoordEqual(int pos1, int pos2, int posTolerance = 0)
{
return abs(pos1 - pos2) <= posTolerance;
}
void ClippingBoxTestCaseBase::CheckBoxPosition(int cur_x, int cur_y, int cur_w, int cur_h,
int x, int y, int w, int h,
int posTolerance)
{
wxString msgPos;
if ( !IsCoordEqual(x, cur_x, posTolerance) ||
!IsCoordEqual(y, cur_y, posTolerance) )
{
msgPos =
wxString::Format(wxS("Invalid position: Actual: (%i, %i) Expected: (%i, %i)"),
cur_x, cur_y, x, y);
}
wxString msgDim;
if ( !IsCoordEqual(w, cur_w, 2*posTolerance) ||
!IsCoordEqual(h, cur_h, 2*posTolerance) )
{
msgDim =
wxString::Format(wxS("Invalid dimension: Actual: %i x %i Expected: %i x %i"),
cur_w, cur_h, w, h);
}
wxString msg;
if ( !msgPos.empty() )
{
msg = msgPos;
if ( !msgDim.empty() )
{
msg += wxS("\n- ");
msg += msgDim;
}
}
else if ( !msgDim.empty() )
{
msg = msgDim;
}
if( !msg.empty() )
{
wxCharBuffer buffer = msg.ToUTF8();
CPPUNIT_FAIL( buffer.data() );
}
}
void ClippingBoxTestCaseBase::CheckClipRect(int x, int y, int width, int height)
{
#if wxUSE_IMAGE
// We check whether diagonal corners of the clipping box are actually
// drawn at the edge of the clipping region.
wxImage img = m_bmp.ConvertToImage();
wxString msg;
wxPoint corners[4];
corners[0] = wxPoint(x, y); // top-left corner
corners[1] = wxPoint(x+width-1, y); // top-right corner
corners[2] = wxPoint(x, y+height-1); // bottom-left corner
corners[3] = wxPoint(x+width-1, y+height-1); // bottom-right corner
// Check area near every corner
for ( unsigned int c = 0; c < WXSIZEOF(corners); c++ )
{
int ymin = corners[c].y-1;
int xmin = corners[c].x-1;
int ymax = corners[c].y+1;
int xmax = corners[c].x+1;
ymin = wxMin(wxMax(ymin, 0), s_dcSize.GetHeight()-1);
xmin = wxMin(wxMax(xmin, 0), s_dcSize.GetWidth()-1);
ymax = wxMin(wxMax(ymax, 0), s_dcSize.GetHeight()-1);
xmax = wxMin(wxMax(xmax, 0), s_dcSize.GetWidth()-1);
for( int py = ymin; py <= ymax; py++ )
for( int px = xmin; px <= xmax; px++ )
{
wxColour c;
unsigned char r = img.GetRed(px, py);
unsigned char g = img.GetGreen(px, py);
unsigned char b = img.GetBlue(px, py);
c.Set(r, g, b);
wxString msgColour;
if ( px >= x && px <= x + (width-1) &&
py >= y && py <= y + (height-1) )
{
// Pixel inside the box.
if ( c != s_fgColour )
{
msgColour =
wxString::Format(wxS("Invalid colour drawn at (%i, %i): Actual: %s Expected: %s"),
px, py, c.GetAsString().mbc_str(), s_fgColour.GetAsString().mbc_str());
}
}
else
{
// Pixel outside the box.
if ( c != s_bgColour )
{
msgColour =
wxString::Format(wxS("Invalid colour drawn at (%i, %i): Actual: %s Expected: %s"),
px, py, c.GetAsString().mbc_str(), s_bgColour.GetAsString().mbc_str());
}
}
if ( !msgColour.empty() )
{
if ( !msg.empty() )
{
msg += wxS("\n- ");
msg += msgColour;
}
else
{
msg = msgColour;
}
}
}
}
if( !msg.empty() )
{
wxCharBuffer buffer = msg.ToUTF8();
CPPUNIT_FAIL( buffer.data() );
}
#endif // wxUSE_IMAGE
}
void ClippingBoxTestCaseBase::CheckClipWithBitmap(const wxBitmap& bmpRef, int posTolerance)
{
#if wxUSE_IMAGE
wxImage img = m_bmp.ConvertToImage();
// If reference bitmap is given then it has to be
// compared with current bitmap.
if ( bmpRef.IsOk() )
{
wxImage imgRef = bmpRef.ConvertToImage();
// Figures created by clipping and drawing procedures
// can be slightly different (shifted by few pixels) due
// to the different algorithms they can use so we need
// to perform a "fuzzy" comparison of the images,
// tolerating some drift of the pixels.
if ( !CompareImageFuzzy(img, imgRef, posTolerance) )
CPPUNIT_FAIL( "Invalid shape of the clipping region" );
}
#endif // wxUSE_IMAGE
}
void ClippingBoxTestCaseDCBase::CheckClipPos(int x, int y, int width, int height, int posTolerance)
{
// Check clipping box boundaries.
int clipX, clipY, clipW, clipH;
m_dc->GetClippingBox(&clipX, &clipY, &clipW, &clipH);
CheckBoxPosition(clipX, clipY, clipW, clipH, x, y, width, height, posTolerance);
}
void ClippingBoxTestCaseDCBase::CheckClipBox(int x, int y, int width, int height,
int devX, int devY, int devWidth, int devHeight)
{
// Check clipping box boundaries.
int clipX, clipY, clipW, clipH;
m_dc->GetClippingBox(&clipX, &clipY, &clipW, &clipH);
CheckBoxPosition(clipX, clipY, clipW, clipH, x, y, width, height);
// Update wxDC contents.
FlushDC();
// We will examine pixels directly in the underlying bitmap
// so we need to use device coordinates of the examined area.
#if wxUSE_IMAGE
// We check whether diagonal corners
// of the rectangular clipping box are actually
// drawn at the edge of the clipping region.
CheckClipRect(devX, devY, devWidth, devHeight);
#endif // wxUSE_IMAGE
}
void ClippingBoxTestCaseDCBase::CheckClipShape(const wxBitmap& bmpRef, int posTolerance)
{
// Update wxDC contents.
FlushDC();
#if wxUSE_IMAGE
// Figures created by clipping and drawing procedures
// can be slightly different (shifted by few pixels) due
// to the different algorithms they can use so we need
// to accept some shift of pixels.
CheckClipWithBitmap(bmpRef, posTolerance);
#endif // wxUSE_IMAGE
}
// Actual tests
void ClippingBoxTestCaseDCBase::InitialState()
{
// Initial clipping box should be the same as the entire DC surface.
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight(),
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseDCBase::InitialStateWithTransformedDC()
{
// Initial clipping box with transformed DC.
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(0), m_dc->DeviceToLogicalY(0),
m_dc->DeviceToLogicalXRel(s_dcSize.GetWidth()),
m_dc->DeviceToLogicalYRel(s_dcSize.GetHeight()),
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseDCBase::InitialStateWithRotatedDC()
{
// Initial clipping box with rotated DC.
#if wxUSE_DC_TRANSFORM_MATRIX
int clipX, clipY, clipW, clipH;
if ( m_dc->CanUseTransformMatrix() )
{
// Apply rotation to DC.
wxAffineMatrix2D m = m_dc->GetTransformMatrix();
m.Rotate(6*M_PI/180.0);
m_dc->SetTransformMatrix(m);
// Calculate expected clipping box.
m.Invert();
double x1, y1, x2, y2;
double x, y;
// Top-left corner
x = 0.0;
y = 0.0;
m.TransformPoint(&x, &y);
x1 = x;
y1 = y;
x2 = x;
y2 = y;
// Top-right corner
x = s_dcSize.GetWidth();
y = 0.0;
m.TransformPoint(&x, &y);
x1 = wxMin(x1, x);
y1 = wxMin(y1, y);
x2 = wxMax(x2, x);
y2 = wxMax(y2, y);
// Bottom-right corner
x = s_dcSize.GetWidth();
y = s_dcSize.GetHeight();
m.TransformPoint(&x, &y);
x1 = wxMin(x1, x);
y1 = wxMin(y1, y);
x2 = wxMax(x2, x);
y2 = wxMax(y2, y);
// Bottom-left corner
x = 0.0;
y = s_dcSize.GetHeight();
m.TransformPoint(&x, &y);
x1 = wxMin(x1, x);
y1 = wxMin(y1, y);
x2 = wxMax(x2, x);
y2 = wxMax(y2, y);
clipX = wxRound(x1);
clipY = wxRound(y1);
clipW = wxRound(x2)-wxRound(x1);
clipH = wxRound(y2)-wxRound(y1);
}
else
{
clipX = 0;
clipY = 0;
clipW = s_dcSize.GetWidth();
clipH = s_dcSize.GetHeight();
}
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(clipX, clipY, clipW, clipH,
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
#endif // wxUSE_DC_TRANSFORM_MATRIX
}
void ClippingBoxTestCaseDCBase::OneRegion()
{
// Setting one clipping region inside DC area.
const int x = 10;
const int y = 20;
const int w = 80;
const int h = 75;
m_dc->SetClippingRegion(x, y, w, h);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(x, y, w, h,
x, y, w, h);
}
void ClippingBoxTestCaseDCBase::OneLargeRegion()
{
// Setting one clipping region larger then DC surface.
// Final clipping box should be limited to the DC extents.
m_dc->SetClippingRegion(-10, -20,
s_dcSize.GetWidth()+30, s_dcSize.GetHeight()+50);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight(),
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneOuterRegion()
{
// Setting one clipping region entirely outside DC surface.
// Final clipping box should be empty.
m_dc->SetClippingRegion(-100, -80, 20, 40);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::OneRegionNegDim()
{
// Setting one clipping region with negative sizes values.
// Final clipping box should have standard positive size values.
const int x = 10;
const int y = 20;
const int w = -80;
const int h = -75;
wxClipRect r1(x, y, w, h);
wxRect r2(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_dc->SetClippingRegion(x, y, w, h);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight(),
r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneRegionAndReset()
{
// Setting one clipping region and next destroy it.
// Final clipping box should be the same as DC surface.
m_dc->SetClippingRegion(10, 20, 80, 75);
m_dc->DestroyClippingRegion();
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight(),
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneRegionAndEmpty()
{
// Setting one clipping region and next an empty box.
// Final clipping box should empty.
m_dc->SetClippingRegion(10, 20, 80, 75);
m_dc->SetClippingRegion(0, 0, 0, 0);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::OneRegionOverTransformedDC()
{
// Setting one clipping region inside DC area
// with applied some transformations.
wxRect r1(-10, -20, 80, 75);
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
m_dc->SetClippingRegion(r1);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
wxRect r2(m_dc->DeviceToLogicalX(0),
m_dc->DeviceToLogicalY(0),
m_dc->DeviceToLogicalXRel(s_dcSize.GetWidth()),
m_dc->DeviceToLogicalYRel(s_dcSize.GetHeight()));
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight(),
m_dc->LogicalToDeviceX(r.GetLeft()),
m_dc->LogicalToDeviceY(r.GetTop()),
m_dc->LogicalToDeviceXRel(r.GetWidth()),
m_dc->LogicalToDeviceYRel(r.GetHeight()));
}
void ClippingBoxTestCaseDCBase::OneRegionAndDCTransformation()
{
// Setting one clipping region inside DC area
// and applying DC transformation afterwards.
wxRect r(-10, -21, 26, 21);
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-16, -21);
m_dc->SetClippingRegion(r);
m_dc->SetBackground(wxBrush(s_tmpColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
m_dc->SetDeviceOrigin(16, 24);
// This should entirely overpaint previous clipping area.
wxCoord x, y, w, h;
m_dc->GetClippingBox(&x, &y, &w, &h);
m_dc->SetClippingRegion(x, y, w, h);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
const int clipX = -13;
const int clipY = -24;
const int clipW = 26;
const int clipH = 21;
CheckClipBox(clipX, clipY, clipW, clipH,
m_dc->LogicalToDeviceX(clipX),
m_dc->LogicalToDeviceY(clipY),
m_dc->LogicalToDeviceXRel(clipW),
m_dc->LogicalToDeviceYRel(clipH));
}
void ClippingBoxTestCaseDCBase::TwoRegionsOverlapping()
{
// Setting one clipping region and next another region (partially overlapping).
// Final clipping box should be an intersection of these two boxes.
wxRect r1(10, 20, 80, 75);
wxRect r2(50, 60, 50, 40);
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_dc->SetClippingRegion(r1);
m_dc->SetClippingRegion(r2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight(),
r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::TwoRegionsOverlappingNegDim()
{
// Setting one clipping region with negative size values
// and next another region (partially overlapping).
// Final clipping box should be an intersection of these two boxes
// with positive size values.
const int x1 = 90;
const int y1 = 95;
const int w1 = -80;
const int h1 = -75;
const int x2 = 50;
const int y2 = 60;
const int w2 = 50;
const int h2 = 40;
wxClipRect r1(x1, y1, w1, h1);
wxRect r2(x2, y2, w2, h2);
wxRect r = r1.Intersect(r2);
m_dc->SetClippingRegion(x1, y1, w1, h1);
m_dc->SetClippingRegion(x2, y2, w2, h2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight(),
r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::TwoRegionsNonOverlapping()
{
// Setting one clipping region and next another region (non-overlapping).
// Final clipping box should be empty.
wxRect r1(10, 20, 30, 30);
wxRect r2(50, 60, 50, 40);
wxASSERT( !r1.Intersects(r2) );
m_dc->SetClippingRegion(r1);
m_dc->SetClippingRegion(r2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::TwoRegionsNonOverlappingNegDim()
{
// Setting one clipping region with negative size values
// and next another region (non-overlapping).
// Final clipping box should be empty.
const int x1 = 10;
const int y1 = 20;
const int w1 = -80;
const int h1 = -75;
const int x2 = 50;
const int y2 = 60;
const int w2 = 50;
const int h2 = 40;
wxClipRect r1(x1, y1, w1, h1);
wxRect r2(x2, y2, w2, h2);
wxASSERT( !r1.Intersects(r2) );
m_dc->SetClippingRegion(x1, y1, w1, h1);
m_dc->SetClippingRegion(x2, y2, w2, h2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::OneDevRegion()
{
// Setting one clipping region in device coordinates
// inside transformed DC area.
const int x = 10;
const int y = 21;
const int w = 80;
const int h = 75;
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg(x, y, w, h);
m_dc->SetDeviceClippingRegion(reg);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(x),
m_dc->DeviceToLogicalY(y),
m_dc->DeviceToLogicalXRel(w),
m_dc->DeviceToLogicalYRel(h),
x, y, w, h);
}
void ClippingBoxTestCaseDCBase::OneLargeDevRegion()
{
// Setting one clipping region in device coordinates larger
// then transformed DC surface.
// Final clipping box should be limited to the DC extents.
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg(-10, -20, s_dcSize.GetWidth()+30, s_dcSize.GetHeight()+50);
m_dc->SetDeviceClippingRegion(reg);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(0),
m_dc->DeviceToLogicalY(0),
m_dc->DeviceToLogicalXRel(s_dcSize.GetWidth()),
m_dc->DeviceToLogicalYRel(s_dcSize.GetHeight()),
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneOuterDevRegion()
{
// Setting one clipping region in device coordinates
// entirely outside transformed DC surface.
// Final clipping box should be empty.
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg(200, 80, 20, 40);
m_dc->SetDeviceClippingRegion(reg);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::OneDevRegionNegDim()
{
// Setting one clipping region in device coordinates
// with negative sizes values.
// Final clipping box should have standard positive size values.
const int x = 19;
const int y = 23;
const int w = -80;
const int h = -75;
wxClipRect r1(x, y, w, h);
wxRect r2(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg(x, y, w, h);
m_dc->SetDeviceClippingRegion(reg);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(r.GetLeft()),
m_dc->DeviceToLogicalY(r.GetTop()),
m_dc->DeviceToLogicalXRel(r.GetWidth()),
m_dc->DeviceToLogicalYRel(r.GetHeight()),
r.GetLeft(), r.GetTop(), r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneDevRegionNonRect()
{
// Setting one triangular clipping region in device coordinates.
const wxPoint poly[3] =
{
wxPoint(3, 5),
wxPoint(68, 18),
wxPoint(40, 72)
};
// Expected clipping box in device coordinates.
const int clipX = 4;
const int clipY = 6;
const int clipW = 64;
const int clipH = 66;
// Draw image with reference triangle.
wxBitmap bmpRef(s_dcSize);
wxMemoryDC* memDC = new wxMemoryDC(bmpRef);
wxDC* dcRef = GetDC(memDC);
dcRef->SetBackground(wxBrush(s_bgColour, wxBRUSHSTYLE_SOLID));
dcRef->Clear();
dcRef->SetBrush(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
dcRef->SetPen(wxPen(s_fgColour));
dcRef->DrawPolygon(WXSIZEOF(poly), poly);
delete dcRef;
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion r(WXSIZEOF(poly), poly);
m_dc->SetDeviceClippingRegion(r);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
// Check clipping box parameters and compare
// filled in clipping region with reference triangle.
// Triangles created by clipping and drawing procedures
// can be slightly different (shifted by few pixels) due
// to the different algorithms used for different operations
// so we need to perform a "fuzzy" comparison of the images,
// tolerating some drift of the pixels.
CheckClipPos(m_dc->DeviceToLogicalX(clipX),
m_dc->DeviceToLogicalY(clipY),
m_dc->DeviceToLogicalXRel(clipW),
m_dc->DeviceToLogicalYRel(clipH), 1);
CheckClipShape(bmpRef, 1);
}
void ClippingBoxTestCaseDCBase::OneDevRegionAndReset()
{
// Setting one clipping region in device coordinates
// and next destroy it.
// Final clipping box should be the same as DC surface.
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg(10, 20, 80, 75);
m_dc->SetDeviceClippingRegion(reg);
m_dc->DestroyClippingRegion();
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(0),
m_dc->DeviceToLogicalY(0),
m_dc->DeviceToLogicalXRel(s_dcSize.GetWidth()),
m_dc->DeviceToLogicalYRel(s_dcSize.GetHeight()),
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneDevRegionAndEmpty()
{
// Setting one clipping region in device coordinates
// and next an empty region.
// Final clipping box should empty.
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg1(10, 20, 80, 75);
m_dc->SetDeviceClippingRegion(reg1);
wxRegion reg2(0, 0, 0, 0);
m_dc->SetDeviceClippingRegion(reg2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::OneDevRegionOverTransformedDC()
{
// Set one clipping region in device coordinates inside
// DC area with applied some transformations.
wxRect r1(8, 15, 60, 75);
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg(r1);
m_dc->SetDeviceClippingRegion(reg);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
wxRect r2(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
CheckClipBox(m_dc->DeviceToLogicalX(r.GetLeft()),
m_dc->DeviceToLogicalY(r.GetTop()),
m_dc->DeviceToLogicalXRel(r.GetWidth()),
m_dc->DeviceToLogicalYRel(r.GetHeight()),
r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::OneDevRegionAndDCTransformation()
{
// Set one clipping region in device coordinates inside
// DC area and apply DC transformation afterwards.
wxRect r1(8, 15, 60, 75);
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-16, -21);
wxRegion reg(r1);
m_dc->SetDeviceClippingRegion(reg);
m_dc->SetBackground(wxBrush(s_tmpColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
m_dc->SetDeviceOrigin(16, 24);
// This should entirely overpaint previous clipping area.
wxCoord x, y, w, h;
m_dc->GetClippingBox(&x, &y, &w, &h);
m_dc->SetClippingRegion(x, y, w, h);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
wxRect r2(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
CheckClipBox(m_dc->DeviceToLogicalX(r.GetLeft()),
m_dc->DeviceToLogicalY(r.GetTop()),
m_dc->DeviceToLogicalXRel(r.GetWidth()),
m_dc->DeviceToLogicalYRel(r.GetHeight()),
r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::TwoDevRegionsOverlapping()
{
// Setting one clipping region in device coordinates
// and next another region in device coordinates (partially overlapping).
// Final clipping box should be an intersection of these two regions.
wxRect r1(30, 39, 40, 30);
wxRect r2(60, 51, 40, 30);
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg1(r1);
m_dc->SetDeviceClippingRegion(reg1);
wxRegion reg2(r2);
m_dc->SetDeviceClippingRegion(reg2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(r.GetLeft()),
m_dc->DeviceToLogicalY(r.GetTop()),
m_dc->DeviceToLogicalXRel(r.GetWidth()),
m_dc->DeviceToLogicalYRel(r.GetHeight()),
r.GetLeft(), r.GetTop(), r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::TwoDevRegionsOverlappingNegDim()
{
// Setting one clipping region in device coordinates with negative size values
// and next another region in device coordinates (partially overlapping).
// Final clipping box should be an intersection of these two regions
// with positive size values.
const int x1 = 31;
const int y1 = 20;
const int w1 = -80;
const int h1 = -75;
const int x2 = 20;
const int y2 = 6;
const int w2 = 40;
const int h2 = 30;
wxClipRect r1(x1, y1, w1, h1);
wxRect r2(x2, y2, w2, h2);
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg1(x1, y1, w1, h1);
m_dc->SetDeviceClippingRegion(reg1);
wxRegion reg2(x2, y2, w2, h2);
m_dc->SetDeviceClippingRegion(reg2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(m_dc->DeviceToLogicalX(r.GetLeft()),
m_dc->DeviceToLogicalY(r.GetTop()),
m_dc->DeviceToLogicalXRel(r.GetWidth()),
m_dc->DeviceToLogicalYRel(r.GetHeight()),
r.GetLeft(), r.GetTop(), r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseDCBase::TwoDevRegionsNonOverlapping()
{
// Setting one clipping region in device coordinates
// and next another region in device coordinates (non-overlapping).
// Final clipping box should be empty.
wxRect r1(10, 20, 30, 30);
wxRect r2(50, 60, 50, 40);
wxASSERT( !r1.Intersects(r2) );
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg1(r1);
m_dc->SetDeviceClippingRegion(reg1);
wxRegion reg2(r2);
m_dc->SetDeviceClippingRegion(reg2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
void ClippingBoxTestCaseDCBase::TwoDevRegionsNonOverlappingNegDim()
{
// Setting one clipping region in device coordinates with negative size values
// and next another region (non-overlapping).
// Final clipping box should be empty.
const int x1 = 10;
const int y1 = 20;
const int w1 = -80;
const int h1 = -75;
const int x2 = 50;
const int y2 = 60;
const int w2 = 50;
const int h2 = 40;
wxClipRect r1(x1, y1, w1, h1);
wxRect r2(x2, y2, w2, h2);
wxASSERT( !r1.Intersects(r2) );
m_dc->SetDeviceOrigin(10, 15);
m_dc->SetUserScale(0.5, 1.5);
m_dc->SetLogicalScale(4.0, 2.0);
m_dc->SetLogicalOrigin(-15, -20);
wxRegion reg1(x1, y1, w1, h1);
m_dc->SetDeviceClippingRegion(reg1);
wxRegion reg2(x2, y2, w2, h2);
m_dc->SetDeviceClippingRegion(reg2);
m_dc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_dc->Clear();
CheckClipBox(0, 0, 0, 0,
0, 0, 0, 0);
}
// Tests specific to wxGCDC
#if wxUSE_GRAPHICS_CONTEXT
void ClippingBoxTestCaseGCDC::InitialStateWithRotatedGCForDC()
{
// Initial wxGCDC clipping box with rotated wxGraphicsContext.
wxGraphicsContext* gc = m_gcdc->GetGraphicsContext();
gc->Rotate(6*M_PI/180.0);
m_gcdc->SetBackground(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_gcdc->Clear();
// Calculate expected clipping box.
int clipX, clipY, clipW, clipH;
wxGraphicsMatrix m = gc->GetTransform();
m.Invert();
double x1, y1, x2, y2;
double x, y;
// Top-left corner
x = 0.0;
y = 0.0;
m.TransformPoint(&x, &y);
x1 = x;
y1 = y;
x2 = x;
y2 = y;
// Top-right corner
x = s_dcSize.GetWidth();
y = 0.0;
m.TransformPoint(&x, &y);
x1 = wxMin(x1, x);
y1 = wxMin(y1, y);
x2 = wxMax(x2, x);
y2 = wxMax(y2, y);
// Bottom-right corner
x = s_dcSize.GetWidth();
y = s_dcSize.GetHeight();
m.TransformPoint(&x, &y);
x1 = wxMin(x1, x);
y1 = wxMin(y1, y);
x2 = wxMax(x2, x);
y2 = wxMax(y2, y);
// Bottom-left corner
x = 0.0;
y = s_dcSize.GetHeight();
m.TransformPoint(&x, &y);
x1 = wxMin(x1, x);
y1 = wxMin(y1, y);
x2 = wxMax(x2, x);
y2 = wxMax(y2, y);
clipX = wxRound(x1);
clipY = wxRound(y1);
clipW = wxRound(x2)-wxRound(x1);
clipH = wxRound(y2)-wxRound(y1);
CheckClipBox(clipX, clipY, clipW, clipH,
0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
#endif // wxUSE_GRAPHICS_CONTEXT
// ========================
// wxGraphicsContext tests
// ========================
#if wxUSE_GRAPHICS_CONTEXT
class ClippingBoxTestCaseGCBase : public ClippingBoxTestCaseBase
{
public:
ClippingBoxTestCaseGCBase()
{
m_rend = NULL;
m_gc = NULL;
m_mdc.SelectObject(m_bmp);
}
virtual ~ClippingBoxTestCaseGCBase()
{
m_mdc.SelectObject(wxNullBitmap);
delete m_gc;
}
virtual void setUp() wxOVERRIDE
{
m_mdc.DestroyClippingRegion();
wxBrush bgBrush(s_bgColour, wxBRUSHSTYLE_SOLID);
m_mdc.SetBackground(bgBrush);
m_mdc.Clear();
CPPUNIT_ASSERT_MESSAGE("Invalid renderer", m_rend);
m_gc = m_rend->CreateContext(m_mdc);
m_gc->SetAntialiasMode(wxANTIALIAS_NONE);
m_gc->DisableOffset();
m_gc->ResetClip();
}
protected:
virtual void FlushGC()
{
m_gc->Flush();
}
void CheckClipPos(int x, int y, int width, int height, int posTolerance = 0);
void CheckClipBox(int x, int y, int width, int height);
void CheckClipShape(const wxBitmap& bmpRef, int posTolerance);
void Clear();
void InitialState();
void InitialStateWithTransformedGC();
void OneRegion();
void OneLargeRegion();
void OneOuterRegion();
void OneRegionNegDim();
void OneRegionAndReset();
void OneRegionAndEmpty();
void OneRegionWithTransformedGC();
void OneRegionWithRotatedGC();
void TwoRegionsOverlapping();
void TwoRegionsOverlappingNegDim();
void TwoRegionsNonOverlapping();
void TwoRegionsNonOverlappingNegDim();
void RegionsAndPushPopState();
protected:
wxGraphicsRenderer* m_rend;
wxGraphicsContext* m_gc;
wxMemoryDC m_mdc;
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCBase);
};
#ifdef __WXMSW__
// GDI+ and Direct2D are available only under MSW.
#if wxUSE_GRAPHICS_GDIPLUS
class ClippingBoxTestCaseGCGDIPlus : public ClippingBoxTestCaseGCBase
{
public:
ClippingBoxTestCaseGCGDIPlus()
{
m_rend = wxGraphicsRenderer::GetGDIPlusRenderer();
}
virtual ~ClippingBoxTestCaseGCGDIPlus() {}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCGDIPlus );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedGC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionWithTransformedGC );
CPPUNIT_TEST( OneRegionWithRotatedGC );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( RegionsAndPushPopState );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCGDIPlus);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCGDIPlus );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCGDIPlus, "ClippingBoxTestCaseGCGDIPlus" );
#endif // wxUSE_GRAPHICS_GDIPLUS
#if wxUSE_GRAPHICS_DIRECT2D
class ClippingBoxTestCaseGCDirect2D : public ClippingBoxTestCaseGCBase
{
public:
ClippingBoxTestCaseGCDirect2D()
{
m_rend = wxGraphicsRenderer::GetDirect2DRenderer();
}
virtual ~ClippingBoxTestCaseGCDirect2D() {}
virtual void FlushGC()
{
// Apparently, flushing native Direct2D renderer
// is not enough to update underlying DC (bitmap)
// and therefore we have to destroy the renderer
// to do so.
ClippingBoxTestCaseGCBase::FlushGC();
delete m_gc;
m_gc = NULL;
}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCDirect2D );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedGC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionWithTransformedGC );
CPPUNIT_TEST( OneRegionWithRotatedGC );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( RegionsAndPushPopState );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCDirect2D);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCDirect2D );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCDirect2D, "ClippingBoxTestCaseGCDirect2D" );
#endif // wxUSE_GRAPHICS_DIRECT2D
#endif // __WXMSW__
#if wxUSE_CAIRO
class ClippingBoxTestCaseGCCairo : public ClippingBoxTestCaseGCBase
{
public:
ClippingBoxTestCaseGCCairo()
{
m_rend = wxGraphicsRenderer::GetCairoRenderer();
}
virtual ~ClippingBoxTestCaseGCCairo() {}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCCairo );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedGC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionWithTransformedGC );
CPPUNIT_TEST( OneRegionWithRotatedGC );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( RegionsAndPushPopState );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCCairo);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCCairo );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCCairo, "ClippingBoxTestCaseGCCairo" );
#endif // wxUSE_CAIRO
#ifdef __WXOSX__
class ClippingBoxTestCaseGCCoreGraphics : public ClippingBoxTestCaseGCBase
{
public:
ClippingBoxTestCaseGCCoreGraphics()
{
m_rend = wxGraphicsRenderer::GetDefaultRenderer();
}
virtual ~ClippingBoxTestCaseGCCoreGraphics() {}
private:
CPPUNIT_TEST_SUITE( ClippingBoxTestCaseGCCoreGraphics );
CPPUNIT_TEST( InitialState );
CPPUNIT_TEST( InitialStateWithTransformedGC );
CPPUNIT_TEST( OneRegion );
CPPUNIT_TEST( OneLargeRegion );
CPPUNIT_TEST( OneOuterRegion );
CPPUNIT_TEST( OneRegionNegDim );
CPPUNIT_TEST( OneRegionAndReset );
CPPUNIT_TEST( OneRegionAndEmpty );
CPPUNIT_TEST( OneRegionWithTransformedGC );
CPPUNIT_TEST( OneRegionWithRotatedGC );
CPPUNIT_TEST( TwoRegionsOverlapping );
CPPUNIT_TEST( TwoRegionsOverlappingNegDim );
CPPUNIT_TEST( TwoRegionsNonOverlapping );
CPPUNIT_TEST( TwoRegionsNonOverlappingNegDim );
CPPUNIT_TEST( RegionsAndPushPopState );
CPPUNIT_TEST_SUITE_END();
protected:
wxDECLARE_NO_COPY_CLASS(ClippingBoxTestCaseGCCoreGraphics);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( ClippingBoxTestCaseGCCoreGraphics );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ClippingBoxTestCaseGCCoreGraphics, "ClippingBoxTestCaseGCCoreGraphics" );
#endif // __WXOSX__
void ClippingBoxTestCaseGCBase::CheckClipPos(int x, int y, int width, int height, int posTolerance)
{
// Check clipping box boundaries.
double clipX, clipY, clipW, clipH;
m_gc->GetClipBox(&clipX, &clipY, &clipW, &clipH);
CheckBoxPosition(wxRound(clipX), wxRound(clipY), wxRound(clipW), wxRound(clipH),
x, y, width, height, posTolerance);
}
void ClippingBoxTestCaseGCBase::CheckClipBox(int x, int y, int width, int height)
{
// Check clipping box boundaries.
double clipX, clipY, clipW, clipH;
m_gc->GetClipBox(&clipX, &clipY, &clipW, &clipH);
CheckBoxPosition(wxRound(clipX), wxRound(clipY), wxRound(clipW), wxRound(clipH),
x, y, width, height);
// We will examine pixels directly in the underlying bitmap
// so we need to get device coordinates of examined area.
wxGraphicsMatrix m = m_gc->GetTransform();
double xdev = x;
double ydev = y;
m.TransformPoint(&xdev, &ydev);
double wdev = width;
double hdev = height;
m.TransformDistance(&wdev, &hdev);
// Update wxGraphicsContext contents.
FlushGC();
#if wxUSE_IMAGE
// We check whether diagonal corners
// of the rectangular clipping box are actually
// drawn at the edge of the clipping region.
CheckClipRect(wxRound(xdev), wxRound(ydev), wxRound(wdev), wxRound(hdev));
#endif // wxUSE_IMAGE
}
void ClippingBoxTestCaseGCBase::CheckClipShape(const wxBitmap& bmpRef, int posTolerance)
{
// Update wxGraphicsContext contents.
FlushGC();
#if wxUSE_IMAGE
// Figures created by clipping and drawing procedures
// can be slightly different (shifted by few pixels) due
// to the different algorithms they can use so we need
// to accept some shift of pixels.
CheckClipWithBitmap(bmpRef, posTolerance);
#endif // wxUSE_IMAGE
}
void ClippingBoxTestCaseGCBase::Clear()
{
double x, y, w, h;
m_gc->GetClipBox(&x, &y, &w, &h);
m_gc->SetBrush(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_gc->SetPen(*wxTRANSPARENT_PEN);
m_gc->SetCompositionMode(wxCOMPOSITION_SOURCE);
m_gc->DrawRectangle(x, y, w, h);
}
// Actual tests
void ClippingBoxTestCaseGCBase::InitialState()
{
// Initial clipping box should be the same as the entire GC surface.
Clear();
CheckClipBox(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseGCBase::InitialStateWithTransformedGC()
{
// Initial clipping box with transformed GC.
wxGraphicsMatrix m = m_gc->CreateMatrix();
m.Translate(10, 15);
m.Scale(1/2.0, 1/3.0);
m.Translate(20, 30);
m_gc->SetTransform(m);
Clear();
m.Invert();
double x = 0;
double y = 0;
m.TransformPoint(&x, &y);
double w = s_dcSize.GetWidth();
double h = s_dcSize.GetHeight();
m.TransformDistance(&w, &h);
CheckClipBox(wxRound(x), wxRound(y), wxRound(w), wxRound(h));
}
void ClippingBoxTestCaseGCBase::OneRegion()
{
// Setting one clipping region inside DC area.
const int x = 10;
const int y = 20;
const int w = 80;
const int h = 75;
m_gc->Clip(x, y, w, h);
Clear();
CheckClipBox(x, y, w, h);
}
void ClippingBoxTestCaseGCBase::OneLargeRegion()
{
// Setting one clipping region larger then GC surface.
// Final clipping box should be limited to the GC extents.
m_gc->Clip(-10, -20,
s_dcSize.GetWidth()+30, s_dcSize.GetHeight()+50);
Clear();
CheckClipBox(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseGCBase::OneOuterRegion()
{
// Setting one clipping region entirely outside GC surface.
// Final clipping box should be empty.
m_gc->Clip(-100, -80, 20, 40);
Clear();
CheckClipBox(0, 0, 0, 0);
}
void ClippingBoxTestCaseGCBase::OneRegionNegDim()
{
// Setting one clipping region with negative sizes values.
// Final clipping box should have standard positive size values.
const int x = 10;
const int y = 20;
const int w = -80;
const int h = -75;
wxClipRect r1(x, y, w, h, 0);
wxRect r2(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_gc->Clip(x, y, w, h);
Clear();
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseGCBase::OneRegionAndReset()
{
// Setting one clipping region and next destroy it.
// Final clipping box should be the same as GC surface.
m_gc->Clip(10, 20, 80, 75);
m_gc->ResetClip();
Clear();
CheckClipBox(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
}
void ClippingBoxTestCaseGCBase::OneRegionAndEmpty()
{
// Setting one clipping region and next an empty box.
// Final clipping box should empty.
m_gc->Clip(10, 20, 80, 75);
m_gc->Clip(0, 0, 0, 0);
Clear();
CheckClipBox(0, 0, 0, 0);
}
void ClippingBoxTestCaseGCBase::OneRegionWithTransformedGC()
{
// Setting one clipping region inside GC area
// with applied some transformations.
wxRect r1(-10, -21, 80, 75);
wxGraphicsMatrix m = m_gc->CreateMatrix();
m.Translate(10, 15);
m.Scale(1/2.0, 1/3.0);
m.Translate(20, 30);
m_gc->SetTransform(m);
m_gc->Clip(r1.x, r1.y, r1.width, r1.height);
Clear();
m.Invert();
double x = 0;
double y = 0;
m.TransformPoint(&x, &y);
double w = s_dcSize.GetWidth();
double h = s_dcSize.GetHeight();
m.TransformDistance(&w, &h);
wxRect r2(wxRound(x), wxRound(y), wxRound(w), wxRound(h));
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseGCBase::OneRegionWithRotatedGC()
{
// Setting one rectangular clipping region for rotated graphics context.
const double rotAngle = 1.0*M_PI/180.0;
const int rectX = 16;
const int rectY = 14;
const int rectW = 60;
const int rectH = 55;
// Set clipping region for rotated wxGC.
m_gc->Rotate(rotAngle);
m_gc->Clip(rectX, rectY, rectW, rectH);
// Fill in clipping region.
Clear();
// Draw reference image with rotated rectangle which
// should look the same as rectangle drawn with Clip().
wxBitmap bmpRef(s_dcSize);
{
wxMemoryDC memDC(bmpRef);
wxGraphicsContext* gcRef = m_rend->CreateContext(memDC);
gcRef->SetAntialiasMode(wxANTIALIAS_NONE);
gcRef->DisableOffset();
gcRef->SetBrush(wxBrush(s_bgColour, wxBRUSHSTYLE_SOLID));
gcRef->SetPen(*wxTRANSPARENT_PEN);
gcRef->DrawRectangle(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
gcRef->Rotate(rotAngle);
gcRef->SetBrush(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
gcRef->SetPen(wxPen(s_fgColour));
gcRef->DrawRectangle(rectX, rectY, rectW, rectH);
delete gcRef;
}
// Compare filled in clipping region with reference rectangle.
// Rotated rectangles created by clipping and drawing procedures
// can be slightly different (shifted by few pixels) due
// to the different algorithms used for different operations
// so we need to perform a "fuzzy" comparison of the images,
// tolerating some drift of the pixels.
CheckClipShape(bmpRef, 1);
}
void ClippingBoxTestCaseGCBase::TwoRegionsOverlapping()
{
// Setting one clipping region and next another region (partially overlapping).
// Final clipping box should be an intersection of these two boxes.
wxRect r1(10, 20, 80, 75);
wxRect r2(50, 60, 50, 40);
wxRect r = r1.Intersect(r2);
wxASSERT( !r.IsEmpty() );
m_gc->Clip(r1.x, r1.y, r1.width, r1.height);
m_gc->Clip(r2.x, r2.y, r2.width, r2.height);
Clear();
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseGCBase::TwoRegionsOverlappingNegDim()
{
// Setting one clipping region with negative size values
// and next another region (partially overlapping).
// Final clipping box should be an intersection of these two boxes
// with positive size values.
const int x1 = 90;
const int y1 = 95;
const int w1 = -80;
const int h1 = -75;
const int x2 = 50;
const int y2 = 60;
const int w2 = 50;
const int h2 = 40;
wxClipRect r1(x1, y1, w1, h1, 0);
wxRect r2(x2, y2, w2, h2);
wxRect r = r1.Intersect(r2);
m_gc->Clip(x1, y1, w1, h1);
m_gc->Clip(x2, y2, w2, h2);
Clear();
CheckClipBox(r.GetLeft(), r.GetTop(),
r.GetWidth(), r.GetHeight());
}
void ClippingBoxTestCaseGCBase::TwoRegionsNonOverlapping()
{
// Setting one clipping region and next another region (non-overlapping).
// Final clipping box should be empty.
wxRect r1(10, 20, 30, 30);
wxRect r2(50, 60, 50, 40);
wxASSERT( !r1.Intersects(r2) );
m_gc->Clip(r1.x, r1.y, r1.width, r1.height);
m_gc->Clip(r2.x, r2.y, r2.width, r2.height);
Clear();
CheckClipBox(0, 0, 0, 0);
}
void ClippingBoxTestCaseGCBase::TwoRegionsNonOverlappingNegDim()
{
// Setting one clipping region with negative size values
// and next another region (non-overlapping).
// Final clipping box should be empty.
const int x1 = 10;
const int y1 = 20;
const int w1 = -80;
const int h1 = -75;
const int x2 = 50;
const int y2 = 60;
const int w2 = 50;
const int h2 = 40;
wxClipRect r1(x1, y1, w1, h1, 0);
wxRect r2(x2, y2, w2, h2);
wxASSERT( !r1.Intersects(r2) );
m_gc->Clip(x1, y1, w1, h1);
m_gc->Clip(x2, y2, w2, h2);
Clear();
CheckClipBox(0, 0, 0, 0);
}
void ClippingBoxTestCaseGCBase::RegionsAndPushPopState()
{
// Setting muliple rectangular clipping regions
// for transformed wxGC and store/restore them.
// Get rectangle of the entire drawing area.
double x, y, w, h;
m_gc->GetClipBox(&x, &y, &w, &h);
// Set clipping regions and store/restore them.
m_gc->SetBrush(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
m_gc->SetPen(wxPen(s_fgColour));
m_gc->Translate(5, 5);
m_gc->Rotate(5*M_PI/180);
m_gc->Clip(20, 15, 50, 45);
m_gc->PushState();
m_gc->Rotate(5*M_PI/180);
m_gc->ResetClip();
m_gc->Clip(10, 5, 60, 15);
m_gc->PushState();
m_gc->Rotate(-15*M_PI/180);
m_gc->ResetClip();
m_gc->Clip(5, 10, 30, 35);
m_gc->DrawRectangle(x, y, w, h);
m_gc->PopState();
m_gc->DrawRectangle(x, y, w, h);
m_gc->PopState();
m_gc->DrawRectangle(x, y, w, h);
// Draw reference image with rotated rectangles which
// should look the same as rectangles drawn with Clip().
wxBitmap bmpRef(s_dcSize);
{
wxMemoryDC memDC(bmpRef);
wxGraphicsContext* gcRef = m_rend->CreateContext(memDC);
gcRef->SetAntialiasMode(wxANTIALIAS_NONE);
gcRef->DisableOffset();
gcRef->SetBrush(wxBrush(s_bgColour, wxBRUSHSTYLE_SOLID));
gcRef->SetPen(*wxTRANSPARENT_PEN);
gcRef->DrawRectangle(0, 0, s_dcSize.GetWidth(), s_dcSize.GetHeight());
gcRef->SetBrush(wxBrush(s_fgColour, wxBRUSHSTYLE_SOLID));
gcRef->SetPen(wxPen(s_fgColour));
gcRef->Translate(5, 5);
gcRef->Rotate(5*M_PI/180);
gcRef->PushState();
gcRef->Rotate(5*M_PI/180);
gcRef->PushState();
gcRef->Rotate(-15*M_PI/180);
gcRef->DrawRectangle(5, 10, 30, 35);
gcRef->PopState();
gcRef->DrawRectangle(10, 5, 60, 15);
gcRef->PopState();
gcRef->DrawRectangle(20, 15, 50, 45);
delete gcRef;
}
// Compare filled in clipping regions with reference image.
// Rotated rectangles created by clipping and drawing procedures
// can be slightly different (shifted by few pixels) due
// to the different algorithms used for different operations
// so we need to perform a "fuzzy" comparison of the images,
// tolerating some drift of the pixels.
CheckClipShape(bmpRef, 1);
}
#endif // wxUSE_GRAPHICS_CONTEXT