1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 */ 10 11 #include <test/bootstrapfixture.hxx> 12 13 #include <vcl/virdev.hxx> 14 #include <vcl/BitmapReadAccess.hxx> 15 #include <vcl/canvastools.hxx> 16 #include <vcl/graphicfilter.hxx> 17 #include <tools/stream.hxx> 18 19 #include <com/sun/star/rendering/XBitmap.hpp> 20 #include <com/sun/star/rendering/XCanvas.hpp> 21 #include <com/sun/star/rendering/XBitmapCanvas.hpp> 22 #include <com/sun/star/rendering/CompositeOperation.hpp> 23 #include <com/sun/star/rendering/PathCapType.hpp> 24 #include <com/sun/star/rendering/PathJoinType.hpp> 25 26 using namespace ::com::sun::star; 27 28 class CanvasTest : public test::BootstrapFixture 29 { 30 VclPtr<VirtualDevice> mVclDevice; 31 uno::Reference<rendering::XCanvas> mCanvas; 32 uno::Reference<rendering::XGraphicDevice> mDevice; 33 rendering::ViewState mViewState; 34 rendering::RenderState mRenderState; 35 uno::Sequence<double> mColorBlack; 36 uno::Sequence<double> mColorBlue; 37 38 // if enabled - check the result images with: 39 // "xdg-open ./workdir/CppunitTest/canvas_test.test.core/" 40 static constexpr const bool mbExportBitmap = false; 41 exportDevice(const OUString & filename,const VclPtr<VirtualDevice> & device)42 void exportDevice(const OUString& filename, const VclPtr<VirtualDevice>& device) 43 { 44 if (mbExportBitmap) 45 { 46 BitmapEx aBitmapEx(device->GetBitmapEx(Point(0, 0), device->GetOutputSizePixel())); 47 SvFileStream aStream(filename, StreamMode::WRITE | StreamMode::TRUNC); 48 GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream); 49 } 50 } 51 52 public: CanvasTest()53 CanvasTest() 54 : BootstrapFixture(true, false) 55 { 56 } 57 setUp()58 virtual void setUp() override 59 { 60 BootstrapFixture::setUp(); 61 mColorBlack = vcl::unotools::colorToStdColorSpaceSequence(COL_BLACK); 62 mColorBlue = vcl::unotools::colorToStdColorSpaceSequence(COL_BLUE); 63 // Geometry init 64 geometry::AffineMatrix2D aUnit(1, 0, 0, 0, 1, 0); 65 mViewState.AffineTransform = aUnit; 66 mRenderState.AffineTransform = aUnit; 67 mRenderState.DeviceColor = mColorBlack; 68 mRenderState.CompositeOperation = rendering::CompositeOperation::OVER; 69 } 70 tearDown()71 virtual void tearDown() override 72 { 73 mVclDevice.disposeAndClear(); 74 mCanvas = uno::Reference<rendering::XCanvas>(); 75 mDevice = uno::Reference<rendering::XGraphicDevice>(); 76 BootstrapFixture::tearDown(); 77 } 78 setupCanvas(const Size & size,Color backgroundColor=COL_WHITE,bool alpha=false)79 void setupCanvas(const Size& size, Color backgroundColor = COL_WHITE, bool alpha = false) 80 { 81 mVclDevice 82 = alpha ? VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT) 83 : VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT); 84 mVclDevice->SetOutputSizePixel(size); 85 mVclDevice->SetBackground(Wallpaper(backgroundColor)); 86 mVclDevice->Erase(); 87 mCanvas = mVclDevice->GetCanvas(); 88 CPPUNIT_ASSERT(mCanvas.is()); 89 mDevice 90 = uno::Reference<rendering::XGraphicDevice>(mCanvas->getDevice(), uno::UNO_SET_THROW); 91 CPPUNIT_ASSERT(mDevice.is()); 92 } 93 testDrawLine()94 void testDrawLine() 95 { 96 setupCanvas(Size(10, 10)); 97 mCanvas->drawLine(geometry::RealPoint2D(1, 1), geometry::RealPoint2D(9, 1), mViewState, 98 mRenderState); 99 exportDevice("test-draw-line.png", mVclDevice); 100 Bitmap bitmap = mVclDevice->GetBitmap(Point(), mVclDevice->GetOutputSizePixel()); 101 Bitmap::ScopedReadAccess access(bitmap); 102 // Canvas uses AA, which blurs the line, and it cannot be turned off, 103 // so do not check the end points. 104 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetPixel(0, 0)); 105 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), access->GetPixel(1, 2)); 106 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), access->GetPixel(1, 8)); 107 } 108 109 // Draw a dashed line scaled, make sure the dashing is scaled properly. testTdf134053()110 void testTdf134053() 111 { 112 setupCanvas(Size(1000, 100)); 113 // Scale everything up by 10 (2 in render state, 5 in view state). 114 mRenderState.AffineTransform = geometry::AffineMatrix2D(2, 0, 0, 0, 2, 0); 115 mViewState.AffineTransform = geometry::AffineMatrix2D(5, 0, 0, 0, 5, 0); 116 117 uno::Sequence<uno::Sequence<geometry::RealPoint2D>> polygonPoints{ { { 10, 5 }, 118 { 88, 5 } } }; 119 uno::Reference<rendering::XLinePolyPolygon2D> polygon 120 = mDevice->createCompatibleLinePolyPolygon(polygonPoints); 121 polygon->setClosed(0, false); 122 123 mRenderState.DeviceColor = mColorBlue; 124 rendering::StrokeAttributes strokeAttributes; 125 strokeAttributes.StrokeWidth = 2.0; 126 strokeAttributes.MiterLimit = 2.0; // ? 127 strokeAttributes.StartCapType = rendering::PathCapType::ROUND; 128 strokeAttributes.EndCapType = rendering::PathCapType::ROUND; 129 strokeAttributes.JoinType = rendering::PathJoinType::MITER; 130 strokeAttributes.DashArray = { 10, 5, 0.1, 5 }; 131 132 mCanvas->strokePolyPolygon(polygon, mViewState, mRenderState, strokeAttributes); 133 134 exportDevice("test-tdf134053.png", mVclDevice); 135 Bitmap bitmap = mVclDevice->GetBitmap(Point(), mVclDevice->GetOutputSizePixel()); 136 Bitmap::ScopedReadAccess access(bitmap); 137 struct Check 138 { 139 tools::Long start; 140 tools::Long end; 141 Color color; 142 }; 143 // There should be a long dash at X 100-200, a dot at 250, long one at 300-400, a dot at 450, etc. 144 // until a dot at 850. Add -5/+5 to account for round caps. 145 const Check checks[] = { { 0, 85, COL_WHITE }, // empty start 146 // dash, space, dot, space 147 { 95, 205, COL_BLUE }, 148 { 215, 235, COL_WHITE }, 149 { 245, 255, COL_BLUE }, 150 { 265, 285, COL_WHITE }, 151 { 295, 405, COL_BLUE }, 152 { 415, 435, COL_WHITE }, 153 { 445, 455, COL_BLUE }, 154 { 465, 485, COL_WHITE }, 155 { 495, 605, COL_BLUE }, 156 { 615, 635, COL_WHITE }, 157 { 645, 655, COL_BLUE }, 158 { 665, 685, COL_WHITE }, 159 { 695, 805, COL_BLUE }, 160 { 815, 835, COL_WHITE }, 161 { 845, 855, COL_BLUE }, 162 { 865, 999, COL_WHITE } }; // empty end 163 for (const Check& check : checks) 164 { 165 for (tools::Long x = check.start; x <= check.end; ++x) 166 { 167 if (access->GetColor(50, x) != check.color) 168 { 169 std::ostringstream str; 170 str << "X: " << x; 171 CPPUNIT_ASSERT_EQUAL_MESSAGE(str.str(), BitmapColor(check.color), 172 access->GetColor(50, x)); 173 } 174 } 175 } 176 } 177 178 CPPUNIT_TEST_SUITE(CanvasTest); 179 CPPUNIT_TEST(testDrawLine); 180 CPPUNIT_TEST(testTdf134053); 181 CPPUNIT_TEST_SUITE_END(); 182 }; 183 184 CPPUNIT_TEST_SUITE_REGISTRATION(CanvasTest); 185 186 CPPUNIT_PLUGIN_IMPLEMENT(); 187 188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 189