vcl/backendtest/VisualBackendTest.cxx | 72 ++++++++++++++++++++++-- vcl/backendtest/outputdevice/common.cxx | 94 ++++++++++++++++++++++++++++++++ vcl/backendtest/outputdevice/line.cxx | 51 +++++++++++++++++ vcl/inc/test/outputdevice.hxx | 24 ++++++++ vcl/qa/cppunit/BackendTest.cxx | 78 ++++++++++++++++++++++++++ 5 files changed, 314 insertions(+), 5 deletions(-)
New commits: commit 38ed3b8064e76c0a6de077cb535cdb573737b26a Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Apr 21 20:16:29 2021 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Sat Apr 24 17:31:52 2021 +0200 backend tests for linecap and linejoin types Change-Id: Id481feb25ce938b4382f970f2e1082a3594c9eca Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114560 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/vcl/backendtest/VisualBackendTest.cxx b/vcl/backendtest/VisualBackendTest.cxx index 441588aa611c..55ec308fb226 100644 --- a/vcl/backendtest/VisualBackendTest.cxx +++ b/vcl/backendtest/VisualBackendTest.cxx @@ -91,7 +91,7 @@ class VisualBackendTestWindow : public WorkWindow private: Timer maUpdateTimer; std::vector<std::chrono::high_resolution_clock::time_point> mTimePoints; - static constexpr unsigned char gnNumberOfTests = 11; + static constexpr unsigned char gnNumberOfTests = 12; unsigned char mnTest; bool mbAnimate; ScopedVclPtr<VirtualDevice> mpVDev; @@ -409,6 +409,64 @@ public: } } + static void testLineTypes(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector<tools::Rectangle> aRegions = setupRegions(4, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinBevel(); + assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkLineJoinBevel(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinRound(); + assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkLineJoinRound(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinMiter(); + assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkLineJoinMiter(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinNone(); + assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkLineJoinNone(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineCapRound(); + assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkLineCapRound(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineCapSquare(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkLineCapSquare(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineCapButt(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkLineCapButt(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + static void testBitmaps(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) { tools::Rectangle aRectangle; @@ -685,21 +743,25 @@ public: } else if (mnTest % gnNumberOfTests == 5) { - testBitmaps(rRenderContext, nWidth, nHeight); + testLineTypes(rRenderContext, nWidth, nHeight); } else if (mnTest % gnNumberOfTests == 6) { - testInvert(rRenderContext, nWidth, nHeight); + testBitmaps(rRenderContext, nWidth, nHeight); } else if (mnTest % gnNumberOfTests == 7) { - testClip(rRenderContext, nWidth, nHeight); + testInvert(rRenderContext, nWidth, nHeight); } else if (mnTest % gnNumberOfTests == 8) { - testGradients(rRenderContext, nWidth, nHeight); + testClip(rRenderContext, nWidth, nHeight); } else if (mnTest % gnNumberOfTests == 9) + { + testGradients(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 10) { std::vector<tools::Rectangle> aRegions = setupRegions(2, 1, nWidth, nHeight); size_t index = 0; diff --git a/vcl/backendtest/outputdevice/common.cxx b/vcl/backendtest/outputdevice/common.cxx index 2ccd1085ec02..40d20ea3568d 100644 --- a/vcl/backendtest/outputdevice/common.cxx +++ b/vcl/backendtest/outputdevice/common.cxx @@ -53,6 +53,12 @@ void checkValue(BitmapScopedWriteAccess& pAccess, int x, int y, Color aExpected, } } +void checkValue(BitmapScopedWriteAccess& pAccess, const Point& point, Color aExpected, + int& nNumberOfQuirks, int& nNumberOfErrors, bool bQuirkMode, int nColorDeltaThresh = 0) +{ + checkValue(pAccess, point.getX(), point.getY(), aExpected, nNumberOfQuirks, nNumberOfErrors, bQuirkMode, nColorDeltaThresh); +} + void checkValue(BitmapScopedWriteAccess& pAccess, int x, int y, Color aExpected, int& nNumberOfQuirks, int& nNumberOfErrors, int nColorDeltaThresh, int nColorDeltaThreshQuirk = 0) { @@ -715,6 +721,94 @@ TestResult OutputDeviceTestCommon::checkRadialGradientOfs(Bitmap& bitmap) return aResult; } +constexpr int CAPSHRINK = 25; +constexpr int CAPWIDTH = 20; +TestResult OutputDeviceTestCommon::checkLineCap(Bitmap& rBitmap, css::drawing::LineCap lineCap) +{ + BitmapScopedWriteAccess access(rBitmap); + tools::Rectangle rectangle( Point( 0, 0 ), Size( 101, 101 )); + rectangle.shrink(CAPSHRINK); + rectangle = tools::Rectangle( Point(rectangle.LeftCenter().getX(), rectangle.LeftCenter().getY() - CAPWIDTH / 2), + Point(rectangle.RightCenter().getX(), rectangle.RightCenter().getY() + CAPWIDTH / 2)); + rectangle.shrink(1); + TestResult aResult = TestResult::Passed; + int nNumberOfQuirks = 0; + int nNumberOfErrors = 0; + + // the line itself + checkValue(access, rectangle.TopLeft(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.TopRight(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.BottomLeft(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.BottomRight(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + + // the cap in the middle + Color color = ( lineCap == css::drawing::LineCap_BUTT ) ? constBackgroundColor : constLineColor; + checkValue(access, rectangle.LeftCenter() - Point(CAPWIDTH/2, 0), color, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.RightCenter() + Point(CAPWIDTH/2, 0), color, nNumberOfQuirks, nNumberOfErrors, false); + + // the cap corners + color = ( lineCap == css::drawing::LineCap_SQUARE ) ? constLineColor : constBackgroundColor; + checkValue(access, rectangle.TopLeft() - Point(CAPWIDTH/2, 0), color, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.TopRight() + Point(CAPWIDTH/2, 0), color, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.BottomLeft() - Point(CAPWIDTH/2, 0), color, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle.BottomRight() + Point(CAPWIDTH/2, 0), color, nNumberOfQuirks, nNumberOfErrors, false); + + if (nNumberOfQuirks > 0) + checkResult(TestResult::PassedWithQuirks, aResult); + if (nNumberOfErrors > 0) + checkResult(TestResult::Failed, aResult); + return aResult; +} + +TestResult OutputDeviceTestCommon::checkLineJoin(Bitmap& rBitmap, basegfx::B2DLineJoin lineJoin) +{ + BitmapScopedWriteAccess access(rBitmap); + tools::Rectangle rectangle( Point( 0, 0 ), Size( 101, 101 )); + rectangle.shrink(CAPSHRINK); + tools::Rectangle rectangle1( Point(rectangle.TopLeft().getX(), rectangle.TopLeft().getY() - CAPWIDTH / 2), + Point(rectangle.TopRight().getX(), rectangle.TopRight().getY() + CAPWIDTH / 2)); + tools::Rectangle rectangle2( Point(rectangle.TopRight().getX() - CAPWIDTH / 2, rectangle.TopRight().getY()), + Point(rectangle.BottomRight().getX() + CAPWIDTH / 2, rectangle.BottomRight().getY())); + rectangle1.shrink(1); + rectangle2.shrink(1); + TestResult aResult = TestResult::Passed; + int nNumberOfQuirks = 0; + int nNumberOfErrors = 0; + + // the lines themselves + checkValue(access, rectangle1.TopLeft(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle1.TopRight(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle1.BottomLeft(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle1.BottomRight(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle2.TopLeft(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle2.TopRight(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle2.BottomLeft(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(access, rectangle2.BottomRight(), constLineColor, nNumberOfQuirks, nNumberOfErrors, false); + + // Only miter has the corner point. + Color color = ( lineJoin == basegfx::B2DLineJoin::Miter ) ? constLineColor : constBackgroundColor; + checkValue(access, rectangle2.Right(), rectangle1.Top(), color, nNumberOfQuirks, nNumberOfErrors, false); + + // Round reaches a bit past the diagonal. + Point midDiagonal = (Point( rectangle2.Right(), rectangle1.Top()) + rectangle.TopRight()) / 2; + if( lineJoin == basegfx::B2DLineJoin::Round) + color = constLineColor; + checkValue(access, midDiagonal + Point( 2, -2 ), color, nNumberOfQuirks, nNumberOfErrors, false); + // Bevel is the diagonal. + if( lineJoin == basegfx::B2DLineJoin::Bevel) + color = constLineColor; + checkValue(access, midDiagonal + Point( -1, 1 ), color, nNumberOfQuirks, nNumberOfErrors, false); + // Everything except None has at least some line join. + checkValue(access, rectangle.TopRight() + Point( 1, -1 ), color, nNumberOfQuirks, nNumberOfErrors, false); + + if (nNumberOfQuirks > 0) + checkResult(TestResult::PassedWithQuirks, aResult); + if (nNumberOfErrors > 0) + checkResult(TestResult::Failed, aResult); + return aResult; +} + + } // end namespace vcl::test /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/line.cxx b/vcl/backendtest/outputdevice/line.cxx index 73505c0ef43d..48526bde6fca 100644 --- a/vcl/backendtest/outputdevice/line.cxx +++ b/vcl/backendtest/outputdevice/line.cxx @@ -195,6 +195,57 @@ TestResult OutputDeviceTestLine::checkDashedLine(Bitmap& rBitmap) return returnValue; } +constexpr int CAPSHRINK = 25; +constexpr int CAPWIDTH = 20; +Bitmap OutputDeviceTestLine::setupLineCap( css::drawing::LineCap lineCap ) +{ + initialSetup(101, 101, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(CAPSHRINK); + + const basegfx::B2DPolygon poly{ + basegfx::B2DPoint(rectangle.LeftCenter().getX(), rectangle.LeftCenter().getY()), + basegfx::B2DPoint(rectangle.RightCenter().getX(), rectangle.RightCenter().getY())}; + + mpVirtualDevice->DrawPolyLineDirect( basegfx::B2DHomMatrix(),poly, + CAPWIDTH, 0, nullptr, basegfx::B2DLineJoin::NONE, lineCap ); + + mpVirtualDevice->SetLineColor(constFillColor); + mpVirtualDevice->DrawPolyLineDirect( basegfx::B2DHomMatrix(), poly, + 0, 0, nullptr, basegfx::B2DLineJoin::NONE ); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestLine::setupLineJoin( basegfx::B2DLineJoin lineJoin ) +{ + initialSetup(101, 101, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(CAPSHRINK); + + const basegfx::B2DPolygon poly{ + basegfx::B2DPoint(rectangle.TopLeft().getX(), rectangle.TopLeft().getY()), + basegfx::B2DPoint(rectangle.TopRight().getX(), rectangle.TopRight().getY()), + basegfx::B2DPoint(rectangle.BottomRight().getX(), rectangle.BottomRight().getY())}; + + mpVirtualDevice->DrawPolyLineDirect( basegfx::B2DHomMatrix(), poly, + CAPWIDTH, 0, nullptr, lineJoin ); + + mpVirtualDevice->SetLineColor(constFillColor); + mpVirtualDevice->DrawPolyLineDirect( basegfx::B2DHomMatrix(), poly, + 0, 0, nullptr, lineJoin ); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + } // end namespace vcl::test /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/test/outputdevice.hxx b/vcl/inc/test/outputdevice.hxx index 6bfed04bc358..706cbce67ec9 100644 --- a/vcl/inc/test/outputdevice.hxx +++ b/vcl/inc/test/outputdevice.hxx @@ -86,6 +86,18 @@ public: static tools::Rectangle alignToCenter(tools::Rectangle aRect1, tools::Rectangle aRect2); static TestResult checkBezier(Bitmap& rBitmap); + + static TestResult checkLineCapRound(Bitmap& rBitmap) { return checkLineCap(rBitmap, css::drawing::LineCap_ROUND); } + static TestResult checkLineCapSquare(Bitmap& rBitmap) { return checkLineCap(rBitmap, css::drawing::LineCap_SQUARE); } + static TestResult checkLineCapButt(Bitmap& rBitmap) { return checkLineCap(rBitmap, css::drawing::LineCap_BUTT); } + + static TestResult checkLineJoinBevel(Bitmap& rBitmap) { return checkLineJoin(rBitmap, basegfx::B2DLineJoin::Bevel); } + static TestResult checkLineJoinRound(Bitmap& rBitmap) { return checkLineJoin(rBitmap, basegfx::B2DLineJoin::Round); } + static TestResult checkLineJoinMiter(Bitmap& rBitmap) { return checkLineJoin(rBitmap, basegfx::B2DLineJoin::Miter); } + static TestResult checkLineJoinNone(Bitmap& rBitmap) { return checkLineJoin(rBitmap, basegfx::B2DLineJoin::NONE); } +private: + static TestResult checkLineCap(Bitmap& rBitmap, css::drawing::LineCap lineCap); + static TestResult checkLineJoin(Bitmap& rBitmap, basegfx::B2DLineJoin lineJoin); }; class VCL_DLLPUBLIC OutputDeviceTestBitmap : public OutputDeviceTestCommon @@ -137,6 +149,18 @@ public: Bitmap setupDashedLine(); static TestResult checkDashedLine(Bitmap& rBitmap); + + Bitmap setupLineCapRound() { return setupLineCap(css::drawing::LineCap_ROUND); } + Bitmap setupLineCapSquare() { return setupLineCap(css::drawing::LineCap_SQUARE); } + Bitmap setupLineCapButt() { return setupLineCap(css::drawing::LineCap_BUTT); } + + Bitmap setupLineJoinBevel() { return setupLineJoin(basegfx::B2DLineJoin::Bevel); } + Bitmap setupLineJoinRound() { return setupLineJoin(basegfx::B2DLineJoin::Round); } + Bitmap setupLineJoinMiter() { return setupLineJoin(basegfx::B2DLineJoin::Miter); } + Bitmap setupLineJoinNone() { return setupLineJoin(basegfx::B2DLineJoin::NONE); } +private: + Bitmap setupLineCap( css::drawing::LineCap lineCap ); + Bitmap setupLineJoin( basegfx::B2DLineJoin lineJoin ); }; class VCL_DLLPUBLIC OutputDeviceTestPolyLine : public OutputDeviceTestCommon diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx index 43b7bc1b2e13..e9aeaad8f588 100644 --- a/vcl/qa/cppunit/BackendTest.cxx +++ b/vcl/qa/cppunit/BackendTest.cxx @@ -792,6 +792,76 @@ public: CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } + void testLineJoinBevel() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinBevel(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinBevel(aBitmap); + exportImage("14-01_line_join_bevel_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testLineJoinRound() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinRound(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinRound(aBitmap); + exportImage("14-02_line_join_round_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testLineJoinMiter() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinMiter(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinMiter(aBitmap); + exportImage("14-03_line_join_miter_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testLineJoinNone() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineJoinNone(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinNone(aBitmap); + exportImage("14-04_line_join_none_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testLineCapRound() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineCapRound(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineCapRound(aBitmap); + exportImage("14-05_line_cap_round_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testLineCapSquare() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineCapSquare(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineCapSquare(aBitmap); + exportImage("14-06_line_cap_square_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testLineCapButt() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLineCapButt(); + auto eResult = vcl::test::OutputDeviceTestLine::checkLineCapButt(aBitmap); + exportImage("14-07_line_cap_butt_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + // Test SalGraphics::blendBitmap() and blendAlphaBitmap() calls. void testDrawBlendExtended() { @@ -1040,6 +1110,14 @@ public: CPPUNIT_TEST(testRadialGradient); CPPUNIT_TEST(testRadialGradientOfs); + CPPUNIT_TEST(testLineCapRound); + CPPUNIT_TEST(testLineCapSquare); + CPPUNIT_TEST(testLineCapButt); + CPPUNIT_TEST(testLineJoinBevel); + CPPUNIT_TEST(testLineJoinRound); + CPPUNIT_TEST(testLineJoinMiter); + CPPUNIT_TEST(testLineJoinNone); + CPPUNIT_TEST(testDrawBlendExtended); CPPUNIT_TEST(testDrawAlphaBitmapMirrored); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits