Files
wxWidgets/tests/graphics/clipper.cpp
Vadim Zeitlin fa5964c100 Use WaitFor() and new YieldForAWhile() helpers in the tests
Reuse the existing function (and another new one, which is even simpler)
instead of duplicating its code in many places in the tests.

No real changes.
2023-10-02 15:10:36 +02:00

758 lines
17 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/graphics/clipper.cpp
// Purpose: wxDCClipper unit tests
// Author: Artur Wieczorek
// Created: 2022-12-27
// Copyright: (c) 2022 wxWidgets development team
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#include <memory>
#include "wx/bitmap.h"
#include "wx/dcclient.h"
#include "wx/dcgraph.h"
#include "wx/dcmemory.h"
#include "wx/dcsvg.h"
#include "wx/app.h"
#include "wx/window.h"
#include "testfile.h"
#include "waitfor.h"
static const wxSize s_dcSize(260, 300);
static inline wxRect DeviceToLogical(wxDC& dc, const wxRect& r)
{
return wxRect(dc.DeviceToLogical(r.GetPosition()), dc.DeviceToLogicalRel(r.GetSize()));
}
static void NoTransform(wxDC& dc)
{
wxRect initClipBox;
dc.GetClippingBox(initClipBox);
{
const wxRect r(10, 20, 30, 40);
wxDCClipper clipper(dc, r);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(r == clipBox);
}
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(initClipBox == clipBox);
}
static void ExternalTransform(wxDC& dc, bool useTransformMatrix)
{
#if wxUSE_DC_TRANSFORM_MATRIX
if ( useTransformMatrix && !dc.CanUseTransformMatrix() )
return;
#endif // wxUSE_DC_TRANSFORM_MATRIX
#if wxUSE_DC_TRANSFORM_MATRIX
if ( useTransformMatrix )
{
wxAffineMatrix2D m;
m.Translate(40, 75);
m.Scale(2.0, 3.0);
dc.SetTransformMatrix(m);
}
else
#endif // wxUSE_DC_TRANSFORM_MATRIX
{
dc.SetDeviceOrigin(10, 15);
dc.SetUserScale(0.5, 1.5);
dc.SetLogicalScale(4.0, 2.0);
dc.SetLogicalOrigin(-15, -20);
}
wxRect initClipBox;
dc.GetClippingBox(initClipBox);
{
const wxRect r(10, 20, 30, 40);
wxDCClipper clipper(dc, r);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(r == clipBox);
}
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(initClipBox == clipBox);
}
static void InternalTransform(wxDC& dc, bool useTransformMatrix)
{
#if wxUSE_DC_TRANSFORM_MATRIX
if ( useTransformMatrix && !dc.CanUseTransformMatrix() )
return;
#endif // wxUSE_DC_TRANSFORM_MATRIX
wxRect initClipBox;
dc.GetClippingBox(initClipBox);
{
const wxRect r(10, 20, 30, 40);
wxDCClipper clipper(dc, r);
#if wxUSE_DC_TRANSFORM_MATRIX
if ( useTransformMatrix )
{
wxAffineMatrix2D m;
m.Translate(40, 75);
m.Scale(2.0, 3.0);
dc.SetTransformMatrix(m);
}
else
#endif // wxUSE_DC_TRANSFORM_MATRIX
{
dc.SetDeviceOrigin(10, 15);
dc.SetUserScale(0.5, 1.5);
dc.SetLogicalScale(4.0, 2.0);
dc.SetLogicalOrigin(-15, -20);
}
wxRect clipExpected = DeviceToLogical(dc, r);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(clipExpected == clipBox);
}
wxRect initClipExpected = DeviceToLogical(dc, initClipBox);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(initClipExpected == clipBox);
}
static void SpecificClipping(wxDC& dc)
{
wxRect initClipBox;
dc.GetClippingBox(initClipBox);
{
const wxRect r(10, 20, 30, 40);
wxDCClipper clipper(dc, r);
const wxRect r1(16, 25, 20, 30);
dc.SetClippingRegion(r1);
wxRect clipExpected = DeviceToLogical(dc, r1);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(clipExpected == clipBox);
}
wxRect initClipExpected = DeviceToLogical(dc, initClipBox);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(initClipExpected == clipBox);
}
static void InternalTransformSpecificClipping(wxDC& dc, bool useTransformMatrix)
{
#if wxUSE_DC_TRANSFORM_MATRIX
if ( useTransformMatrix && !dc.CanUseTransformMatrix() )
return;
#endif // wxUSE_DC_TRANSFORM_MATRIX
wxRect initClipBox;
dc.GetClippingBox(initClipBox);
{
const wxRect r(10, 20, 30, 40);
wxDCClipper clipper(dc, r);
const wxRect r1(16, 25, 20, 30);
dc.SetClippingRegion(r1);
#if wxUSE_DC_TRANSFORM_MATRIX
if ( useTransformMatrix )
{
wxAffineMatrix2D m;
m.Translate(40, 75);
m.Scale(2.0, 3.0);
dc.SetTransformMatrix(m);
}
else
#endif // wxUSE_DC_TRANSFORM_MATRIX
{
dc.SetDeviceOrigin(10, 15);
dc.SetUserScale(0.5, 1.5);
dc.SetLogicalScale(4.0, 2.0);
dc.SetLogicalOrigin(-15, -20);
}
wxRect clipExpected = DeviceToLogical(dc, r1);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(clipExpected == clipBox);
}
wxRect initClipExpected = DeviceToLogical(dc, initClipBox);
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(initClipExpected == clipBox);
}
static void NoTransformEmbeddedClip(wxDC& dc)
{
wxRect initClipBox;
dc.GetClippingBox(initClipBox);
{
const wxRect r1(10, 20, 30, 40);
wxDCClipper clipper1(dc, r1);
{
const wxRect r2(15, 25, 20, 30);
wxDCClipper clipper2(dc, r2);
wxRect clipBox2;
dc.GetClippingBox(clipBox2);
CHECK(r2 == clipBox2);
}
wxRect clipBox1;
dc.GetClippingBox(clipBox1);
CHECK(r1 == clipBox1);
}
wxRect clipBox;
dc.GetClippingBox(clipBox);
CHECK(initClipBox == clipBox);
}
static void DCAttributes(wxDC& dc)
{
// Check if wxDC atrributes left unchanged
wxFont font = dc.GetFont().Bold().Smaller();
wxPen pen(*wxYELLOW, 2);
wxBrush brush = *wxBLUE_BRUSH;
wxDCFontChanger fontChanger(dc, font);
wxDCPenChanger penChanger(dc,pen);
wxDCBrushChanger brushChanger(dc, brush);
wxCoord chWidth = dc.GetCharWidth();
wxCoord chHeight = dc.GetCharHeight();
wxFontMetrics fm = dc.GetFontMetrics();
{
wxDCClipper clipper(dc, 10, 20, 30, 40);
}
CHECK(dc.GetFont() == font);
CHECK(dc.GetPen() == pen);
CHECK(dc.GetBrush() == brush);
CHECK(dc.GetCharWidth() == chWidth);
CHECK(dc.GetCharHeight() == chHeight);
wxFontMetrics fm2 = dc.GetFontMetrics();
CHECK(fm2.ascent == fm.ascent);
CHECK(fm2.averageWidth == fm.averageWidth);
CHECK(fm2.descent == fm.descent);
CHECK(fm2.externalLeading == fm.externalLeading);
CHECK(fm2.height == fm.height);
CHECK(fm2.internalLeading == fm.internalLeading);
}
TEST_CASE("ClipperTestCase::wxDC", "[clipper][dc]")
{
wxBitmap bmp(s_dcSize);
wxMemoryDC dc(bmp);
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
}
#if wxUSE_GRAPHICS_CONTEXT
TEST_CASE("ClipperTestCase::wxGCDC", "[clipper][dc][gcdc]")
{
#ifdef __WXMSW__
int depth = GENERATE(24, 32);
wxBitmap bmp(s_dcSize, depth);
#else
wxBitmap bmp(s_dcSize);
#endif
wxMemoryDC mdc(bmp);
mdc.SetBackground(*wxWHITE_BRUSH);
mdc.Clear();
wxGCDC dc(mdc);
dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
dc.GetGraphicsContext()->DisableOffset();
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
}
#ifdef __WXMSW__
#if wxUSE_GRAPHICS_GDIPLUS
TEST_CASE("ClipperTestCase::wxGCDC(GDI+)", "[clipper][dc][gcdc][gdiplus]")
{
int depth = GENERATE(24, 32);
wxBitmap bmp(s_dcSize, depth);
wxMemoryDC mdc(bmp);
mdc.SetBackground(*wxWHITE_BRUSH);
mdc.Clear();
wxGraphicsRenderer* rend = wxGraphicsRenderer::GetGDIPlusRenderer();
REQUIRE(rend);
wxGraphicsContext* gc = rend->CreateContext(mdc);
gc->SetAntialiasMode(wxANTIALIAS_NONE);
gc->DisableOffset();
wxGCDC dc(gc);
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
}
#endif // wxUSE_GRAPHICS_GDIPLUS
#if wxUSE_GRAPHICS_DIRECT2D
TEST_CASE("ClipperTestCase::wxGCDC(Direct2D)", "[clipper][dc][gcdc][direct2d]")
{
if ( wxIsRunningUnderWine() )
{
WARN("Skipping tests known to fail in Wine");
}
else
{
int depth = GENERATE(24, 32);
wxBitmap bmp(s_dcSize, depth);
wxMemoryDC mdc(bmp);
mdc.SetBackground(*wxWHITE_BRUSH);
mdc.Clear();
wxGraphicsRenderer* rend = wxGraphicsRenderer::GetDirect2DRenderer();
REQUIRE(rend);
wxGraphicsContext* gc = rend->CreateContext(mdc);
gc->SetAntialiasMode(wxANTIALIAS_NONE);
gc->DisableOffset();
wxGCDC dc(gc);
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
}
}
#endif // wxUSE_GRAPHICS_DIRECT2D
#endif // __WXMSW__
#if wxUSE_CAIRO
TEST_CASE("ClipperTestCase::wxGCDC(Cairo)", "[clipper][dc][gcdc][cairo]")
{
#ifdef __WXMSW__
int depth = GENERATE(24, 32);
wxBitmap bmp(s_dcSize, depth);
#else
wxBitmap bmp(s_dcSize);
#endif
wxMemoryDC mdc(bmp);
mdc.SetBackground(*wxWHITE_BRUSH);
mdc.Clear();
wxGraphicsRenderer* rend = wxGraphicsRenderer::GetCairoRenderer();
REQUIRE(rend);
wxGraphicsContext* gc = rend->CreateContext(mdc);
gc->SetAntialiasMode(wxANTIALIAS_NONE);
gc->DisableOffset();
wxGCDC dc(gc);
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
}
#endif // wxUSE_CAIRO
#endif // wxUSE_GRAPHICS_CONTEXT
#if wxUSE_SVG
TEST_CASE("ClipperTestCase::wxSVGFileDC", "[clipper][dc][svgdc]")
{
TestFile tf;
wxSVGFileDC dc(tf.GetName(), s_dcSize.x, s_dcSize.y);
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
}
#endif // wxUSE_SVG
TEST_CASE("ClipperTestCase::wxPaintDC", "[clipper][dc][paintdc]")
{
// Ensure window is shown and large enough for testing
wxTheApp->GetTopWindow()->Raise();
REQUIRE(wxTheApp->GetTopWindow()->IsShown());
wxSize winSize = wxTheApp->GetTopWindow()->GetSize();
winSize.x = wxMax(winSize.x, s_dcSize.x + 50);
winSize.y = wxMax(winSize.y, s_dcSize.y + 50);
wxTheApp->GetTopWindow()->SetSize(winSize);
#if defined(__WXGTK__)
// Under wxGTK we need to have two children (at least) because if there
// is one child its paint area is set to fill the whole parent frame.
std::unique_ptr<wxWindow> w0(new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY));
#endif // wxGTK
std::unique_ptr<wxWindow> win(new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY, wxPoint(0, 0)));
win->SetClientSize(s_dcSize);
// Wait for the first paint event to be sure
// that window really has its final size.
wxWindow* testWin = win.get();
{
WaitForPaint waitForPaint(testWin);
testWin->Show();
waitForPaint.YieldUntilPainted();
}
bool paintExecuted = false;
testWin->Bind(wxEVT_PAINT, [=, &paintExecuted](wxPaintEvent&)
{
wxPaintDC dc(testWin);
REQUIRE(dc.GetSize() == s_dcSize);
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
SECTION("NoTransform")
{
NoTransform(dc);
}
SECTION("ExternalTransform 1")
{
ExternalTransform(dc, false);
}
SECTION("ExternalTransform 2")
{
ExternalTransform(dc, true);
}
SECTION("InternalTransform 1")
{
InternalTransform(dc, false);
}
SECTION("InternalTransform 2")
{
InternalTransform(dc, true);
}
SECTION("SpecificClipping")
{
SpecificClipping(dc);
}
SECTION("InternalTransformSpecificClipping 1")
{
InternalTransformSpecificClipping(dc, false);
}
SECTION("InternalTransformSpecificClipping 2")
{
InternalTransformSpecificClipping(dc, true);
}
SECTION("NoTransformEmbeddedClip")
{
NoTransformEmbeddedClip(dc);
}
SECTION("DCAttributes")
{
DCAttributes(dc);
}
paintExecuted = true;
});
testWin->Refresh();
testWin->Update();
// Wait for update to be done
YieldForAWhile();
CHECK(paintExecuted == true);
}