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/bitmap.hxx>
14 #include <tools/stream.hxx>
15 #include <vcl/graphicfilter.hxx>
16 #include <basegfx/matrix/b2dhommatrix.hxx>
17 #include <bitmap/BitmapWriteAccess.hxx>
18 
19 #include <test/outputdevice.hxx>
20 
21 // Run tests from visualbackendtest ('bin/run visualbackendtest').
22 class BackendTest : public test::BootstrapFixture
23 {
24     // if enabled - check the result images with:
25     // "xdg-open ./workdir/CppunitTest/vcl_backend_test.test.core/"
26     static constexpr const bool mbExportBitmap = false;
27 
exportImage(OUString const & rsFilename,BitmapEx const & rBitmapEx)28     void exportImage(OUString const& rsFilename, BitmapEx const& rBitmapEx)
29     {
30         if (mbExportBitmap)
31         {
32             BitmapEx aBitmapEx(rBitmapEx);
33             aBitmapEx.Scale(Size(128, 128), BmpScaleFlag::Fast);
34             SvFileStream aStream(rsFilename, StreamMode::WRITE | StreamMode::TRUNC);
35             GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream);
36         }
37     }
38 
exportImage(OUString const & rsFilename,Bitmap const & rBitmap)39     void exportImage(OUString const& rsFilename, Bitmap const& rBitmap)
40     {
41         if (mbExportBitmap)
42         {
43             Bitmap aBitmap(rBitmap);
44             aBitmap.Scale(Size(128, 128), BmpScaleFlag::Fast);
45             SvFileStream aStream(rsFilename, StreamMode::WRITE | StreamMode::TRUNC);
46             GraphicFilter::GetGraphicFilter().compressAsPNG(BitmapEx(aBitmap), aStream);
47         }
48     }
49 
exportDevice(const OUString & filename,const VclPtr<VirtualDevice> & device)50     void exportDevice(const OUString& filename, const VclPtr<VirtualDevice>& device)
51     {
52         if (mbExportBitmap)
53         {
54             BitmapEx aBitmapEx(device->GetBitmapEx(Point(0, 0), device->GetOutputSizePixel()));
55             SvFileStream aStream(filename, StreamMode::WRITE | StreamMode::TRUNC);
56             GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream);
57         }
58     }
59 
60 public:
BackendTest()61     BackendTest()
62         : BootstrapFixture(true, false)
63     {
64     }
65 
66     // We need to enable tests ONE BY ONE as they fail because of backend bugs
67     // it is still important to have the test defined so we know the issues
68     // exist and we need to fix them. Consistent behaviour of our backends
69     // is of highest priority.
70 
assertBackendNameNotEmpty(const OUString & name)71     static bool assertBackendNameNotEmpty(const OUString& name)
72     {
73         // This ensures that all backends return a valid name.
74         assert(!name.isEmpty());
75         (void)name;
76         return true;
77     }
78 
79 // Check whether tests should fail depending on which backend is used
80 // (not all work). If you want to disable just a specific test
81 // for a specific backend, use something like
82 // 'if(SHOULD_ASSERT && aOutDevTest.getRenderBackendName() != "skia")'.
83 // The macro uses opt-out rather than opt-in so that this doesn't "pass"
84 // silently in case a new backend is added.
85 #define SHOULD_ASSERT                                                                              \
86     (assertBackendNameNotEmpty(aOutDevTest.getRenderBackendName())                                 \
87      && aOutDevTest.getRenderBackendName() != "qt5"                                                \
88      && aOutDevTest.getRenderBackendName() != "qt5svp"                                             \
89      && aOutDevTest.getRenderBackendName() != "gtk3svp"                                            \
90      && aOutDevTest.getRenderBackendName() != "aqua"                                               \
91      && aOutDevTest.getRenderBackendName() != "gen"                                                \
92      && aOutDevTest.getRenderBackendName() != "genpsp"                                             \
93      && aOutDevTest.getRenderBackendName() != "win")
94 
testDrawRectWithRectangle()95     void testDrawRectWithRectangle()
96     {
97         if (getDefaultDeviceBitCount() < 24)
98             return;
99         vcl::test::OutputDeviceTestRect aOutDevTest;
100         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
101         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
102         exportImage("01-01_rectangle_test-rectangle.png", aBitmap);
103 
104         if (SHOULD_ASSERT)
105             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
106     }
107 
testDrawRectWithPixel()108     void testDrawRectWithPixel()
109     {
110         if (getDefaultDeviceBitCount() < 24)
111             return;
112         vcl::test::OutputDeviceTestPixel aOutDevTest;
113         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
114         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
115         exportImage("01-02_rectangle_test-pixel.png", aBitmap);
116 
117         if (SHOULD_ASSERT)
118             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
119     }
120 
testDrawRectWithLine()121     void testDrawRectWithLine()
122     {
123         if (getDefaultDeviceBitCount() < 24)
124             return;
125         vcl::test::OutputDeviceTestLine aOutDevTest;
126         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
127         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
128         exportImage("01-03_rectangle_test-line.png", aBitmap);
129 
130         if (SHOULD_ASSERT)
131             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
132     }
133 
testDrawRectWithPolygon()134     void testDrawRectWithPolygon()
135     {
136         if (getDefaultDeviceBitCount() < 24)
137             return;
138         vcl::test::OutputDeviceTestPolygon aOutDevTest;
139         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
140         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
141         exportImage("01-04_rectangle_test-polygon.png", aBitmap);
142         if (SHOULD_ASSERT)
143             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
144     }
145 
testDrawRectWithPolyLine()146     void testDrawRectWithPolyLine()
147     {
148         if (getDefaultDeviceBitCount() < 24)
149             return;
150         vcl::test::OutputDeviceTestPolyLine aOutDevTest;
151         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
152         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
153         exportImage("01-05_rectangle_test-polyline.png", aBitmap);
154         if (SHOULD_ASSERT)
155             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
156     }
157 
testDrawRectWithPolyLineB2D()158     void testDrawRectWithPolyLineB2D()
159     {
160         if (getDefaultDeviceBitCount() < 24)
161             return;
162         vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest;
163         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
164         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
165         exportImage("01-06_rectangle_test-polyline_b2d.png", aBitmap);
166         if (SHOULD_ASSERT)
167             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
168     }
169 
testDrawRectWithPolyPolygon()170     void testDrawRectWithPolyPolygon()
171     {
172         if (getDefaultDeviceBitCount() < 24)
173             return;
174         vcl::test::OutputDeviceTestPolyPolygon aOutDevTest;
175         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
176         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
177         exportImage("01-07_rectangle_test-polypolygon.png", aBitmap);
178         if (SHOULD_ASSERT)
179             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
180     }
181 
testDrawRectWithPolyPolygonB2D()182     void testDrawRectWithPolyPolygonB2D()
183     {
184         if (getDefaultDeviceBitCount() < 24)
185             return;
186         vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest;
187         Bitmap aBitmap = aOutDevTest.setupRectangle(false);
188         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap);
189         exportImage("01-08_rectangle_test-polypolygon_b2d.png", aBitmap);
190         if (SHOULD_ASSERT)
191             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
192     }
193 
testDrawRectAAWithRectangle()194     void testDrawRectAAWithRectangle()
195     {
196         if (getDefaultDeviceBitCount() < 24)
197             return;
198         vcl::test::OutputDeviceTestRect aOutDevTest;
199         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
200         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
201         exportImage("02-01_rectangle_AA_test-rectangle.png", aBitmap);
202         if (SHOULD_ASSERT)
203             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
204     }
205 
testDrawRectAAWithPixel()206     void testDrawRectAAWithPixel()
207     {
208         if (getDefaultDeviceBitCount() < 24)
209             return;
210         vcl::test::OutputDeviceTestPixel aOutDevTest;
211         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
212         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
213         exportImage("02-02_rectangle_AA_test-pixel.png", aBitmap);
214         if (SHOULD_ASSERT)
215             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
216     }
217 
testDrawRectAAWithLine()218     void testDrawRectAAWithLine()
219     {
220         if (getDefaultDeviceBitCount() < 24)
221             return;
222         vcl::test::OutputDeviceTestLine aOutDevTest;
223         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
224         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
225         exportImage("02-03_rectangle_AA_test-line.png", aBitmap);
226         if (SHOULD_ASSERT)
227             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
228     }
229 
testDrawRectAAWithPolygon()230     void testDrawRectAAWithPolygon()
231     {
232         if (getDefaultDeviceBitCount() < 24)
233             return;
234         vcl::test::OutputDeviceTestPolygon aOutDevTest;
235         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
236         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
237         exportImage("02-04_rectangle_AA_test-polygon.png", aBitmap);
238         if (SHOULD_ASSERT)
239             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
240     }
241 
testDrawRectAAWithPolyLine()242     void testDrawRectAAWithPolyLine()
243     {
244         if (getDefaultDeviceBitCount() < 24)
245             return;
246         vcl::test::OutputDeviceTestPolyLine aOutDevTest;
247         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
248         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
249         exportImage("02-05_rectangle_AA_test-polyline.png", aBitmap);
250         if (SHOULD_ASSERT)
251             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
252     }
253 
testDrawRectAAWithPolyLineB2D()254     void testDrawRectAAWithPolyLineB2D()
255     {
256         if (getDefaultDeviceBitCount() < 24)
257             return;
258         vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest;
259         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
260         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
261         exportImage("02-06_rectangle_AA_test-polyline_b2d.png", aBitmap);
262         if (SHOULD_ASSERT)
263             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
264     }
265 
testDrawRectAAWithPolyPolygon()266     void testDrawRectAAWithPolyPolygon()
267     {
268         if (getDefaultDeviceBitCount() < 24)
269             return;
270         vcl::test::OutputDeviceTestPolyPolygon aOutDevTest;
271         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
272         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
273         exportImage("02-07_rectangle_AA_test-polypolygon.png", aBitmap);
274         if (SHOULD_ASSERT)
275             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
276     }
277 
testDrawRectAAWithPolyPolygonB2D()278     void testDrawRectAAWithPolyPolygonB2D()
279     {
280         if (getDefaultDeviceBitCount() < 24)
281             return;
282         vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest;
283         Bitmap aBitmap = aOutDevTest.setupRectangle(true);
284         auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap);
285         exportImage("02-08_rectangle_AA_test-polypolygon_b2d.png", aBitmap);
286         if (SHOULD_ASSERT)
287             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
288     }
289 
testDrawFilledRectWithRectangle()290     void testDrawFilledRectWithRectangle()
291     {
292         if (getDefaultDeviceBitCount() < 24)
293             return;
294         vcl::test::OutputDeviceTestRect aOutDevTest;
295         Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false);
296         auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false);
297         exportImage("03-01_filled_rectangle_test-rectangle_noline.png", aBitmap);
298         if (SHOULD_ASSERT)
299             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
300         aBitmap = aOutDevTest.setupFilledRectangle(true);
301         eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true);
302         exportImage("03-01_filled_rectangle_test-rectangle_line.png", aBitmap);
303         if (SHOULD_ASSERT)
304             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
305     }
306 
testDrawFilledRectWithPolygon()307     void testDrawFilledRectWithPolygon()
308     {
309         if (getDefaultDeviceBitCount() < 24)
310             return;
311         vcl::test::OutputDeviceTestPolygon aOutDevTest;
312         Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false);
313         auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false);
314         exportImage("03-02_filled_rectangle_test-polygon_noline.png", aBitmap);
315         if (SHOULD_ASSERT)
316             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
317         aBitmap = aOutDevTest.setupFilledRectangle(true);
318         eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true);
319         exportImage("03-02_filled_rectangle_test-polygon_line.png", aBitmap);
320         if (SHOULD_ASSERT)
321             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
322     }
323 
testDrawFilledRectWithPolyPolygon()324     void testDrawFilledRectWithPolyPolygon()
325     {
326         if (getDefaultDeviceBitCount() < 24)
327             return;
328         vcl::test::OutputDeviceTestPolyPolygon aOutDevTest;
329         Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false);
330         auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false);
331         exportImage("03-03_filled_rectangle_test-polypolygon_noline.png", aBitmap);
332         if (SHOULD_ASSERT)
333             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
334         aBitmap = aOutDevTest.setupFilledRectangle(true);
335         eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true);
336         exportImage("03-03_filled_rectangle_test-polypolygon_line.png", aBitmap);
337         if (SHOULD_ASSERT)
338             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
339     }
340 
testDrawFilledRectWithPolyPolygon2D()341     void testDrawFilledRectWithPolyPolygon2D()
342     {
343         if (getDefaultDeviceBitCount() < 24)
344             return;
345         vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest;
346         Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false);
347         auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false);
348         exportImage("03-04_filled_rectangle_test-polypolygon_b2d_noline.png", aBitmap);
349         if (SHOULD_ASSERT)
350             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
351         aBitmap = aOutDevTest.setupFilledRectangle(true);
352         eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true);
353         exportImage("03-04_filled_rectangle_test-polypolygon_b2d_line.png", aBitmap);
354         if (SHOULD_ASSERT)
355             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
356     }
357 
testDrawDiamondWithPolygon()358     void testDrawDiamondWithPolygon()
359     {
360         vcl::test::OutputDeviceTestPolygon aOutDevTest;
361         Bitmap aBitmap = aOutDevTest.setupDiamond();
362         auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap);
363         exportImage("04-01_diamond_test-polygon.png", aBitmap);
364         if (SHOULD_ASSERT)
365             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
366     }
367 
testDrawDiamondWithLine()368     void testDrawDiamondWithLine()
369     {
370         vcl::test::OutputDeviceTestLine aOutDevTest;
371         Bitmap aBitmap = aOutDevTest.setupDiamond();
372         auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap);
373         exportImage("04-02_diamond_test-line.png", aBitmap);
374         if (SHOULD_ASSERT)
375             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
376     }
377 
testDrawDiamondWithPolyline()378     void testDrawDiamondWithPolyline()
379     {
380         vcl::test::OutputDeviceTestPolyLine aOutDevTest;
381         Bitmap aBitmap = aOutDevTest.setupDiamond();
382         auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap);
383         exportImage("04-03_diamond_test-polyline.png", aBitmap);
384         if (SHOULD_ASSERT)
385             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
386     }
387 
testDrawDiamondWithPolylineB2D()388     void testDrawDiamondWithPolylineB2D()
389     {
390         vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest;
391         Bitmap aBitmap = aOutDevTest.setupDiamond();
392         auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap);
393         exportImage("04-04_diamond_test-polyline_b2d.png", aBitmap);
394         if (SHOULD_ASSERT)
395             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
396     }
397 
testDrawInvertWithRectangle()398     void testDrawInvertWithRectangle()
399     {
400         vcl::test::OutputDeviceTestRect aOutDevTest;
401         Bitmap aBitmap = aOutDevTest.setupInvert_NONE();
402         auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertRectangle(aBitmap);
403         exportImage("05-01_invert_test-rectangle.png", aBitmap);
404         if (SHOULD_ASSERT)
405             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
406     }
407 
testDrawInvertN50WithRectangle()408     void testDrawInvertN50WithRectangle()
409     {
410         vcl::test::OutputDeviceTestRect aOutDevTest;
411         Bitmap aBitmap = aOutDevTest.setupInvert_N50();
412         auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertN50Rectangle(aBitmap);
413         exportImage("05-02_invert_N50_test-rectangle.png", aBitmap);
414         if (SHOULD_ASSERT && aOutDevTest.getRenderBackendName() != "svp")
415             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
416     }
417 
testDrawInvertTrackFrameWithRectangle()418     void testDrawInvertTrackFrameWithRectangle()
419     {
420         vcl::test::OutputDeviceTestRect aOutDevTest;
421         Bitmap aBitmap = aOutDevTest.setupInvert_TrackFrame();
422         auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertTrackFrameRectangle(aBitmap);
423         exportImage("05-03_invert_TrackFrame_test-rectangle.png", aBitmap);
424         if (SHOULD_ASSERT && aOutDevTest.getRenderBackendName() != "svp")
425             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
426     }
427 
testDrawBezierWithPolylineB2D()428     void testDrawBezierWithPolylineB2D()
429     {
430         if (getDefaultDeviceBitCount() < 24)
431             return;
432         vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest;
433         Bitmap aBitmap = aOutDevTest.setupBezier();
434         auto eResult = vcl::test::OutputDeviceTestCommon::checkBezier(aBitmap);
435         exportImage("06-01_bezier_test-polyline_b2d.png", aBitmap);
436         if (SHOULD_ASSERT)
437             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
438     }
439 
testDrawBezierAAWithPolylineB2D()440     void testDrawBezierAAWithPolylineB2D()
441     {
442         if (getDefaultDeviceBitCount() < 24)
443             return;
444         vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest;
445         Bitmap aBitmap = aOutDevTest.setupAABezier();
446         auto eResult = vcl::test::OutputDeviceTestCommon::checkBezier(aBitmap);
447         exportImage("07-01_bezier_AA_test-polyline_b2d.png", aBitmap);
448         if (SHOULD_ASSERT)
449             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
450     }
451 
testDrawBitmap()452     void testDrawBitmap()
453     {
454         if (getDefaultDeviceBitCount() < 24)
455             return;
456         vcl::test::OutputDeviceTestBitmap aOutDevTest;
457         Bitmap aBitmap = aOutDevTest.setupDrawBitmap();
458         exportImage("08-01_bitmap_test.png", aBitmap);
459         auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap);
460         if (SHOULD_ASSERT)
461             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
462     }
463 
testDrawTransformedBitmap()464     void testDrawTransformedBitmap()
465     {
466         if (getDefaultDeviceBitCount() < 24)
467             return;
468         vcl::test::OutputDeviceTestBitmap aOutDevTest;
469         Bitmap aBitmap = aOutDevTest.setupDrawTransformedBitmap();
470         auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap);
471         exportImage("08-02_transformed_bitmap_test.png", aBitmap);
472         if (SHOULD_ASSERT)
473             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
474     }
475 
testDrawBitmapExWithAlpha()476     void testDrawBitmapExWithAlpha()
477     {
478         if (getDefaultDeviceBitCount() < 24)
479             return;
480         vcl::test::OutputDeviceTestBitmap aOutDevTest;
481         Bitmap aBitmap = aOutDevTest.setupDrawBitmapExWithAlpha();
482         auto eResult = vcl::test::OutputDeviceTestBitmap::checkBitmapExWithAlpha(aBitmap);
483         exportImage("08-03_bitmapex_with_alpha_test.png", aBitmap);
484         if (SHOULD_ASSERT)
485             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
486     }
487 
testDrawMask()488     void testDrawMask()
489     {
490         if (getDefaultDeviceBitCount() < 24)
491             return;
492         vcl::test::OutputDeviceTestBitmap aOutDevTest;
493         Bitmap aBitmap = aOutDevTest.setupDrawMask();
494         auto eResult = vcl::test::OutputDeviceTestBitmap::checkMask(aBitmap);
495         exportImage("08-04_mask_test.png", aBitmap);
496         if (SHOULD_ASSERT)
497             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
498     }
499 
testDrawBlend()500     void testDrawBlend()
501     {
502         if (getDefaultDeviceBitCount() < 24)
503             return;
504         vcl::test::OutputDeviceTestBitmap aOutDevTest;
505         BitmapEx aBitmapEx = aOutDevTest.setupDrawBlend();
506         auto eResult = vcl::test::OutputDeviceTestBitmap::checkBlend(aBitmapEx);
507         exportImage("08-05_blend_test.png", aBitmapEx);
508         if (SHOULD_ASSERT)
509             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
510     }
511 
testDrawXor()512     void testDrawXor()
513     {
514         if (getDefaultDeviceBitCount() < 24)
515             return;
516         vcl::test::OutputDeviceTestAnotherOutDev aOutDevTest;
517         Bitmap aBitmap = aOutDevTest.setupXOR();
518         auto eResult = vcl::test::OutputDeviceTestAnotherOutDev::checkXOR(aBitmap);
519         exportImage("08-06_xor_test.png", aBitmap);
520         if (SHOULD_ASSERT)
521             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
522     }
523 
testDrawTransformedBitmapExAlpha()524     void testDrawTransformedBitmapExAlpha()
525     {
526 // TODO: This unit test is not executed for macOS unless bitmap scaling is implemented
527 #ifndef MACOSX
528         if (getDefaultDeviceBitCount() < 24)
529             return;
530         ScopedVclPtrInstance<VirtualDevice> device;
531         device->SetOutputSizePixel(Size(16, 16));
532         device->SetBackground(Wallpaper(COL_WHITE));
533         device->Erase();
534         Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP);
535         {
536             // Fill the top left quarter with black.
537             BitmapScopedWriteAccess pWriteAccess(aBitmap);
538             pWriteAccess->Erase(COL_WHITE);
539             for (int i = 0; i < 8; ++i)
540                 for (int j = 0; j < 8; ++j)
541                     pWriteAccess->SetPixel(j, i, COL_BLACK);
542         }
543         BitmapEx aBitmapEx(aBitmap);
544         basegfx::B2DHomMatrix aMatrix;
545         // Draw with no transformation, only alpha change.
546         aMatrix.scale(16, 16);
547         device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5);
548         BitmapEx result = device->GetBitmapEx(Point(0, 0), Size(16, 16));
549         CPPUNIT_ASSERT_EQUAL(Color(0x80, 0x80, 0x80), result.GetPixelColor(0, 0));
550         CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(15, 15));
551         // Draw rotated and move to the bottom-left corner.
552         device->Erase();
553         aMatrix.identity();
554         aMatrix.scale(16, 16);
555         aMatrix.rotate(M_PI / 2);
556         aMatrix.translate(8, 8);
557         device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5);
558         result = device->GetBitmap(Point(0, 0), Size(16, 16));
559         CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(0, 0));
560         CPPUNIT_ASSERT_EQUAL(Color(0x80, 0x80, 0x80), result.GetPixelColor(0, 15));
561 #endif
562     }
563 
testClipRectangle()564     void testClipRectangle()
565     {
566         if (getDefaultDeviceBitCount() < 24)
567             return;
568         vcl::test::OutputDeviceTestClip aOutDevTest;
569         Bitmap aBitmap = aOutDevTest.setupClipRectangle();
570         auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap);
571         exportImage("09-01_clip_rectangle_test.png", aBitmap);
572         if (SHOULD_ASSERT)
573             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
574     }
575 
testClipPolygon()576     void testClipPolygon()
577     {
578         if (getDefaultDeviceBitCount() < 24)
579             return;
580         vcl::test::OutputDeviceTestClip aOutDevTest;
581         Bitmap aBitmap = aOutDevTest.setupClipPolygon();
582         auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap);
583         exportImage("09-02_clip_polygon_test.png", aBitmap);
584         if (SHOULD_ASSERT)
585             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
586     }
587 
testClipPolyPolygon()588     void testClipPolyPolygon()
589     {
590         if (getDefaultDeviceBitCount() < 24)
591             return;
592         vcl::test::OutputDeviceTestClip aOutDevTest;
593         Bitmap aBitmap = aOutDevTest.setupClipPolyPolygon();
594         auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap);
595         exportImage("09-03_clip_polypolygon_test.png", aBitmap);
596         if (SHOULD_ASSERT)
597             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
598     }
599 
testClipB2DPolyPolygon()600     void testClipB2DPolyPolygon()
601     {
602         if (getDefaultDeviceBitCount() < 24)
603             return;
604         vcl::test::OutputDeviceTestClip aOutDevTest;
605         Bitmap aBitmap = aOutDevTest.setupClipB2DPolyPolygon();
606         auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap);
607         exportImage("09-04_clip_b2dpolypolygon_test.png", aBitmap);
608         if (SHOULD_ASSERT)
609             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
610     }
611 
testDrawOutDev()612     void testDrawOutDev()
613     {
614         if (getDefaultDeviceBitCount() < 24)
615             return;
616         vcl::test::OutputDeviceTestAnotherOutDev aOutDevTest;
617         Bitmap aBitmap = aOutDevTest.setupDrawOutDev();
618         auto eResult = vcl::test::OutputDeviceTestAnotherOutDev::checkDrawOutDev(aBitmap);
619         exportImage("10-01_draw_out_dev_test.png", aBitmap);
620         if (SHOULD_ASSERT)
621             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
622     }
623 
testDashedLine()624     void testDashedLine()
625     {
626         if (getDefaultDeviceBitCount() < 24)
627             return;
628         vcl::test::OutputDeviceTestLine aOutDevTest;
629         Bitmap aBitmap = aOutDevTest.setupDashedLine();
630         auto eResult = vcl::test::OutputDeviceTestLine::checkDashedLine(aBitmap);
631         exportImage("11-01_dashed_line_test.png", aBitmap);
632         if (SHOULD_ASSERT)
633             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
634     }
635 
testErase()636     void testErase()
637     {
638         if (getDefaultDeviceBitCount() < 24)
639             return;
640         {
641             // Create normal virtual device (no alpha).
642             ScopedVclPtr<VirtualDevice> device
643                 = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
644             device->SetOutputSizePixel(Size(10, 10));
645             // Erase with white, check it's white.
646             device->SetBackground(Wallpaper(COL_WHITE));
647             device->Erase();
648             exportDevice("/tmp/12-01_erase.png", device);
649             CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(0, 0)));
650             CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(9, 9)));
651             CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(5, 5)));
652             // Erase with black, check it's black.
653             device->SetBackground(Wallpaper(COL_BLACK));
654             device->Erase();
655             exportDevice("/tmp/12-02_erase.png", device);
656             CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(0, 0)));
657             CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(9, 9)));
658             CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(5, 5)));
659             // Erase with cyan, check it's cyan.
660             device->SetBackground(Wallpaper(COL_CYAN));
661             device->Erase();
662             exportDevice("/tmp/12-03_erase.png", device);
663             CPPUNIT_ASSERT_EQUAL(COL_CYAN, device->GetPixel(Point(0, 0)));
664             CPPUNIT_ASSERT_EQUAL(COL_CYAN, device->GetPixel(Point(9, 9)));
665             CPPUNIT_ASSERT_EQUAL(COL_CYAN, device->GetPixel(Point(5, 5)));
666         }
667         {
668             // Create virtual device with alpha.
669             ScopedVclPtr<VirtualDevice> device
670                 = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
671             device->SetOutputSizePixel(Size(10, 10));
672             // Erase with white, check it's white.
673             device->SetBackground(Wallpaper(COL_WHITE));
674             device->Erase();
675             exportDevice("/tmp/12-04_erase.png", device);
676             CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(0, 0)));
677             CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(9, 9)));
678             CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(5, 5)));
679             // Erase with black, check it's black.
680             device->SetBackground(Wallpaper(COL_BLACK));
681             device->Erase();
682             exportDevice("/tmp/12-05_erase.png", device);
683             CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(0, 0)));
684             CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(9, 9)));
685             CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(5, 5)));
686             // Erase with cyan, check it's cyan.
687             device->SetBackground(Wallpaper(COL_CYAN));
688             device->Erase();
689             exportDevice("/tmp/12-06_erase.png", device);
690             CPPUNIT_ASSERT_EQUAL(COL_CYAN, device->GetPixel(Point(0, 0)));
691             CPPUNIT_ASSERT_EQUAL(COL_CYAN, device->GetPixel(Point(9, 9)));
692             CPPUNIT_ASSERT_EQUAL(COL_CYAN, device->GetPixel(Point(5, 5)));
693             // Erase with transparent, check it's transparent.
694             device->SetBackground(Wallpaper(COL_TRANSPARENT));
695             device->Erase();
696             exportDevice("/tmp/12-07_erase.png", device);
697             CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), device->GetPixel(Point(0, 0)).GetAlpha());
698             CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), device->GetPixel(Point(9, 9)).GetAlpha());
699             CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), device->GetPixel(Point(5, 5)).GetAlpha());
700         }
701     }
702 
testLinearGradient()703     void testLinearGradient()
704     {
705         if (getDefaultDeviceBitCount() < 24)
706             return;
707         vcl::test::OutputDeviceTestGradient aOutDevTest;
708         Bitmap aBitmap = aOutDevTest.setupLinearGradient();
709         auto eResult = vcl::test::OutputDeviceTestGradient::checkLinearGradient(aBitmap);
710         exportImage("13-01_linear_gradient_test.png", aBitmap);
711         if (SHOULD_ASSERT)
712             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
713     }
714 
testLinearGradientAngled()715     void testLinearGradientAngled()
716     {
717         if (getDefaultDeviceBitCount() < 24)
718             return;
719         vcl::test::OutputDeviceTestGradient aOutDevTest;
720         Bitmap aBitmap = aOutDevTest.setupLinearGradientAngled();
721         auto eResult = vcl::test::OutputDeviceTestGradient::checkLinearGradientAngled(aBitmap);
722         exportImage("13-02_linear_gradient_angled_test.png", aBitmap);
723         if (SHOULD_ASSERT)
724             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
725     }
726 
testLinearGradientBorder()727     void testLinearGradientBorder()
728     {
729         vcl::test::OutputDeviceTestGradient aOutDevTest;
730         Bitmap aBitmap = aOutDevTest.setupLinearGradientBorder();
731         auto eResult = vcl::test::OutputDeviceTestGradient::checkLinearGradientBorder(aBitmap);
732         exportImage("13-03_linear_gradient_border_test.png", aBitmap);
733         if (SHOULD_ASSERT)
734             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
735     }
736 
testLinearGradientIntensity()737     void testLinearGradientIntensity()
738     {
739         if (getDefaultDeviceBitCount() < 24)
740             return;
741         vcl::test::OutputDeviceTestGradient aOutDevTest;
742         Bitmap aBitmap = aOutDevTest.setupLinearGradientIntensity();
743         auto eResult = vcl::test::OutputDeviceTestGradient::checkLinearGradientIntensity(aBitmap);
744         exportImage("13-04_linear_gradient_intensity_test.png", aBitmap);
745         if (SHOULD_ASSERT)
746             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
747     }
748 
testLinearGradientSteps()749     void testLinearGradientSteps()
750     {
751         if (getDefaultDeviceBitCount() < 24)
752             return;
753         vcl::test::OutputDeviceTestGradient aOutDevTest;
754         Bitmap aBitmap = aOutDevTest.setupLinearGradientSteps();
755         auto eResult = vcl::test::OutputDeviceTestGradient::checkLinearGradientSteps(aBitmap);
756         exportImage("13-05_linear_gradient_steps_test.png", aBitmap);
757         if (SHOULD_ASSERT)
758             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
759     }
760 
testAxialGradient()761     void testAxialGradient()
762     {
763         if (getDefaultDeviceBitCount() < 24)
764             return;
765         vcl::test::OutputDeviceTestGradient aOutDevTest;
766         Bitmap aBitmap = aOutDevTest.setupAxialGradient();
767         auto eResult = vcl::test::OutputDeviceTestGradient::checkAxialGradient(aBitmap);
768         exportImage("13-06_axial_gradient_test.png", aBitmap);
769         if (SHOULD_ASSERT)
770             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
771     }
772 
testRadialGradient()773     void testRadialGradient()
774     {
775         if (getDefaultDeviceBitCount() < 24)
776             return;
777         vcl::test::OutputDeviceTestGradient aOutDevTest;
778         Bitmap aBitmap = aOutDevTest.setupRadialGradient();
779         auto eResult = vcl::test::OutputDeviceTestGradient::checkRadialGradient(aBitmap);
780         exportImage("13-07_radial_gradient_test.png", aBitmap);
781         if (SHOULD_ASSERT)
782             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
783     }
784 
testRadialGradientOfs()785     void testRadialGradientOfs()
786     {
787         vcl::test::OutputDeviceTestGradient aOutDevTest;
788         Bitmap aBitmap = aOutDevTest.setupRadialGradientOfs();
789         auto eResult = vcl::test::OutputDeviceTestGradient::checkRadialGradientOfs(aBitmap);
790         exportImage("13-08_radial_gradient_ofs_test.png", aBitmap);
791         if (SHOULD_ASSERT)
792             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
793     }
794 
testLineJoinBevel()795     void testLineJoinBevel()
796     {
797         vcl::test::OutputDeviceTestLine aOutDevTest;
798         Bitmap aBitmap = aOutDevTest.setupLineJoinBevel();
799         auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinBevel(aBitmap);
800         exportImage("14-01_line_join_bevel_test.png", aBitmap);
801         if (SHOULD_ASSERT)
802             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
803     }
804 
testLineJoinRound()805     void testLineJoinRound()
806     {
807         vcl::test::OutputDeviceTestLine aOutDevTest;
808         Bitmap aBitmap = aOutDevTest.setupLineJoinRound();
809         auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinRound(aBitmap);
810         exportImage("14-02_line_join_round_test.png", aBitmap);
811         if (SHOULD_ASSERT)
812             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
813     }
814 
testLineJoinMiter()815     void testLineJoinMiter()
816     {
817         vcl::test::OutputDeviceTestLine aOutDevTest;
818         Bitmap aBitmap = aOutDevTest.setupLineJoinMiter();
819         auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinMiter(aBitmap);
820         exportImage("14-03_line_join_miter_test.png", aBitmap);
821         if (SHOULD_ASSERT)
822             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
823     }
824 
testLineJoinNone()825     void testLineJoinNone()
826     {
827         vcl::test::OutputDeviceTestLine aOutDevTest;
828         Bitmap aBitmap = aOutDevTest.setupLineJoinNone();
829         auto eResult = vcl::test::OutputDeviceTestLine::checkLineJoinNone(aBitmap);
830         exportImage("14-04_line_join_none_test.png", aBitmap);
831         if (SHOULD_ASSERT)
832             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
833     }
834 
testLineCapRound()835     void testLineCapRound()
836     {
837         vcl::test::OutputDeviceTestLine aOutDevTest;
838         Bitmap aBitmap = aOutDevTest.setupLineCapRound();
839         auto eResult = vcl::test::OutputDeviceTestLine::checkLineCapRound(aBitmap);
840         exportImage("14-05_line_cap_round_test.png", aBitmap);
841         if (SHOULD_ASSERT)
842             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
843     }
844 
testLineCapSquare()845     void testLineCapSquare()
846     {
847         vcl::test::OutputDeviceTestLine aOutDevTest;
848         Bitmap aBitmap = aOutDevTest.setupLineCapSquare();
849         auto eResult = vcl::test::OutputDeviceTestLine::checkLineCapSquare(aBitmap);
850         exportImage("14-06_line_cap_square_test.png", aBitmap);
851         if (SHOULD_ASSERT)
852             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
853     }
854 
testLineCapButt()855     void testLineCapButt()
856     {
857         vcl::test::OutputDeviceTestLine aOutDevTest;
858         Bitmap aBitmap = aOutDevTest.setupLineCapButt();
859         auto eResult = vcl::test::OutputDeviceTestLine::checkLineCapButt(aBitmap);
860         exportImage("14-07_line_cap_butt_test.png", aBitmap);
861         if (SHOULD_ASSERT)
862             CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed);
863     }
864 
865     // Test SalGraphics::blendBitmap() and blendAlphaBitmap() calls.
testDrawBlendExtended()866     void testDrawBlendExtended()
867     {
868 // TODO: This unit test is not executed for macOS unless bitmap scaling is implemented
869 #ifndef MACOSX
870         if (getDefaultDeviceBitCount() < 24)
871             return;
872         // Create virtual device with alpha.
873         ScopedVclPtr<VirtualDevice> device
874             = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
875         device->SetOutputSizePixel(Size(10, 10));
876         device->SetBackground(Wallpaper(COL_WHITE));
877         device->Erase();
878         Bitmap bitmap(Size(5, 5), vcl::PixelFormat::N24_BPP);
879         bitmap.Erase(COL_BLUE);
880         // No alpha, this will actually call SalGraphics::DrawBitmap(), but still check
881         // the alpha of the device is handled correctly.
882         device->DrawBitmapEx(Point(2, 2), BitmapEx(bitmap));
883         exportDevice("/tmp/blend_extended_01.png", device);
884         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(2, 2)));
885         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(6, 6)));
886         // Check pixels outside of the bitmap aren't affected.
887         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(1, 1)));
888         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(7, 7)));
889 
890         device->Erase();
891         AlphaMask alpha(Size(5, 5));
892         alpha.Erase(0); // opaque
893         device->DrawBitmapEx(Point(2, 2), BitmapEx(bitmap, alpha));
894         exportDevice("/tmp/blend_extended_02.png", device);
895         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(2, 2)));
896         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(6, 6)));
897 
898         device->Erase();
899         alpha.Erase(255); // transparent
900         device->DrawBitmapEx(Point(2, 2), BitmapEx(bitmap, alpha));
901         exportDevice("/tmp/blend_extended_03.png", device);
902         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(2, 2)));
903         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(6, 6)));
904 
905         // Skia optimizes bitmaps that have just been Erase()-ed, so explicitly
906         // set some pixels in the alpha to avoid this and have an actual bitmap
907         // as the alpha mask.
908         device->Erase();
909         alpha.Erase(255); // transparent
910         BitmapWriteAccess* alphaWrite = alpha.AcquireAlphaWriteAccess();
911         alphaWrite->SetPixelIndex(0, 0, 0); // opaque
912         alpha.ReleaseAccess(alphaWrite);
913         device->DrawBitmapEx(Point(2, 2), BitmapEx(bitmap, alpha));
914         exportDevice("/tmp/blend_extended_04.png", device);
915         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(2, 2)));
916         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(6, 6)));
917 #endif
918     }
919 
testDrawAlphaBitmapMirrored()920     void testDrawAlphaBitmapMirrored()
921     {
922 // TODO: This unit test is not executed for macOS unless bitmap scaling is implemented
923 #ifndef MACOSX
924         if (getDefaultDeviceBitCount() < 24)
925             return;
926         // Normal virtual device.
927         ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
928         // Virtual device with alpha.
929         ScopedVclPtr<VirtualDevice> alphaDevice
930             = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
931         device->SetOutputSizePixel(Size(20, 20));
932         device->SetBackground(Wallpaper(COL_BLACK));
933         device->Erase();
934         alphaDevice->SetOutputSizePixel(Size(20, 20));
935         alphaDevice->SetBackground(Wallpaper(COL_BLACK));
936         alphaDevice->Erase();
937         Bitmap bitmap(Size(4, 4), vcl::PixelFormat::N24_BPP);
938         AlphaMask alpha(Size(4, 4));
939         bitmap.Erase(COL_LIGHTBLUE);
940         {
941             BitmapScopedWriteAccess writeAccess(bitmap);
942             writeAccess->SetPixel(3, 3, COL_LIGHTRED);
943         }
944         // alpha 127 will make COL_LIGHTRED -> COL_RED and the same for blue
945         alpha.Erase(127);
946         // Normal device.
947         device->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap));
948         device->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap));
949         exportDevice("/tmp/draw_alpha_bitmap_mirrored_01.png", device);
950         CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, device->GetPixel(Point(18, 18)));
951         CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, device->GetPixel(Point(17, 18)));
952         CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, device->GetPixel(Point(2, 2)));
953         CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, device->GetPixel(Point(3, 2)));
954         device->Erase();
955         device->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap, alpha));
956         device->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap, alpha));
957         exportDevice("/tmp/draw_alpha_bitmap_mirrored_02.png", device);
958         CPPUNIT_ASSERT_EQUAL(COL_RED, device->GetPixel(Point(18, 18)));
959         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(17, 18)));
960         CPPUNIT_ASSERT_EQUAL(COL_RED, device->GetPixel(Point(2, 2)));
961         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(3, 2)));
962         device->Erase();
963         // Now with alpha device.
964         alphaDevice->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap));
965         alphaDevice->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap));
966         exportDevice("/tmp/draw_alpha_bitmap_mirrored_03.png", alphaDevice);
967         CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, alphaDevice->GetPixel(Point(18, 18)));
968         CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, alphaDevice->GetPixel(Point(17, 18)));
969         CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, alphaDevice->GetPixel(Point(2, 2)));
970         CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, alphaDevice->GetPixel(Point(3, 2)));
971         alphaDevice->Erase();
972         alphaDevice->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap, alpha));
973         alphaDevice->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap, alpha));
974         exportDevice("/tmp/draw_alpha_bitmap_mirrored_04.png", alphaDevice);
975         CPPUNIT_ASSERT_EQUAL(COL_RED, alphaDevice->GetPixel(Point(18, 18)));
976         CPPUNIT_ASSERT_EQUAL(COL_BLUE, alphaDevice->GetPixel(Point(17, 18)));
977         CPPUNIT_ASSERT_EQUAL(COL_RED, alphaDevice->GetPixel(Point(2, 2)));
978         CPPUNIT_ASSERT_EQUAL(COL_BLUE, alphaDevice->GetPixel(Point(3, 2)));
979         alphaDevice->Erase();
980 #endif
981     }
982 
testTdf124848()983     void testTdf124848()
984     {
985 // TODO: This unit test is not executed for macOS unless bitmap scaling is implemented
986 #ifndef MACOSX
987         ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
988         device->SetOutputSizePixel(Size(100, 100));
989         device->SetBackground(Wallpaper(COL_WHITE));
990         device->Erase();
991         device->SetAntialiasing(AntialiasingFlags::Enable);
992         device->SetLineColor(COL_BLACK);
993         basegfx::B2DHomMatrix matrix;
994         // DrawPolyLine() would apply the whole matrix to the line width, making it negative
995         // in case of a larger rotation.
996         matrix.rotate(M_PI); //180 degrees
997         matrix.translate(100, 100);
998         CPPUNIT_ASSERT(device->DrawPolyLineDirect(matrix,
999                                                   basegfx::B2DPolygon{ { 50, 50 }, { 50, 100 } },
1000                                                   100, 0, nullptr, basegfx::B2DLineJoin::Miter));
1001         exportDevice("/tmp/tdf124848-1.png", device);
1002         // 100px wide line should fill the entire width of the upper half
1003         CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(2, 2)));
1004 
1005         // Also check hairline.
1006         device->Erase();
1007         CPPUNIT_ASSERT(device->DrawPolyLineDirect(matrix,
1008                                                   basegfx::B2DPolygon{ { 50, 50 }, { 50, 100 } }, 0,
1009                                                   0, nullptr, basegfx::B2DLineJoin::Miter));
1010         exportDevice("/tmp/tdf124848-2.png", device);
1011         // 1px wide
1012         CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(50, 20)));
1013         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(49, 20)));
1014         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(51, 20)));
1015 #endif
1016     }
1017 
testTdf136171()1018     void testTdf136171()
1019     {
1020 // TODO: Following unit tests are not executed for macOS unless bitmap scaling is implemented
1021 #ifndef MACOSX
1022         if (getDefaultDeviceBitCount() < 24)
1023             return;
1024         // Create virtual device with alpha.
1025         ScopedVclPtr<VirtualDevice> device
1026             = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
1027         device->SetOutputSizePixel(Size(10, 10));
1028         device->SetBackground(Wallpaper(COL_WHITE));
1029         device->Erase();
1030         Bitmap bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP);
1031         bitmap.Erase(COL_BLUE);
1032         basegfx::B2DHomMatrix matrix;
1033         matrix.scale(bitmap.GetSizePixel().Width(),
1034                      bitmap.GetSizePixel().Height()); // draw as 10x10
1035         // Draw a blue bitmap to the device. The bug was that there was no alpha, but OutputDevice::DrawTransformBitmapExDirect()
1036         // supplied a fully opaque alpha done with Erase() on the alpha bitmap, and Skia backend didn't handle such alpha correctly.
1037         device->DrawTransformedBitmapEx(matrix, BitmapEx(bitmap));
1038         exportDevice("/tmp/tdf136171.png", device);
1039         // The whole virtual device content now should be blue.
1040         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(0, 0)));
1041         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(9, 0)));
1042         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(0, 9)));
1043         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(9, 9)));
1044         CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(4, 4)));
1045 #endif
1046     }
1047 
1048     CPPUNIT_TEST_SUITE(BackendTest);
1049     CPPUNIT_TEST(testDrawRectWithRectangle);
1050     CPPUNIT_TEST(testDrawRectWithPixel);
1051     CPPUNIT_TEST(testDrawRectWithLine);
1052     CPPUNIT_TEST(testDrawRectWithPolygon);
1053     CPPUNIT_TEST(testDrawRectWithPolyLine);
1054     CPPUNIT_TEST(testDrawRectWithPolyLineB2D);
1055     CPPUNIT_TEST(testDrawRectWithPolyPolygon);
1056     CPPUNIT_TEST(testDrawRectWithPolyPolygonB2D);
1057 
1058     CPPUNIT_TEST(testDrawRectAAWithRectangle);
1059     CPPUNIT_TEST(testDrawRectAAWithPixel);
1060     CPPUNIT_TEST(testDrawRectAAWithLine);
1061     CPPUNIT_TEST(testDrawRectAAWithPolygon);
1062     CPPUNIT_TEST(testDrawRectAAWithPolyLine);
1063     CPPUNIT_TEST(testDrawRectAAWithPolyLineB2D);
1064     CPPUNIT_TEST(testDrawRectAAWithPolyPolygon);
1065     CPPUNIT_TEST(testDrawRectAAWithPolyPolygonB2D);
1066 
1067     CPPUNIT_TEST(testDrawFilledRectWithRectangle);
1068     CPPUNIT_TEST(testDrawFilledRectWithPolygon);
1069     CPPUNIT_TEST(testDrawFilledRectWithPolyPolygon);
1070     CPPUNIT_TEST(testDrawFilledRectWithPolyPolygon2D);
1071 
1072     CPPUNIT_TEST(testDrawDiamondWithPolygon);
1073     CPPUNIT_TEST(testDrawDiamondWithLine);
1074     CPPUNIT_TEST(testDrawDiamondWithPolyline);
1075     CPPUNIT_TEST(testDrawDiamondWithPolylineB2D);
1076 
1077     CPPUNIT_TEST(testDrawInvertWithRectangle);
1078     CPPUNIT_TEST(testDrawInvertN50WithRectangle);
1079     CPPUNIT_TEST(testDrawInvertTrackFrameWithRectangle);
1080 
1081     CPPUNIT_TEST(testDrawBezierWithPolylineB2D);
1082     CPPUNIT_TEST(testDrawBezierAAWithPolylineB2D);
1083 
1084     CPPUNIT_TEST(testDrawBitmap);
1085     CPPUNIT_TEST(testDrawTransformedBitmap);
1086     CPPUNIT_TEST(testDrawBitmapExWithAlpha);
1087     CPPUNIT_TEST(testDrawMask);
1088     CPPUNIT_TEST(testDrawBlend);
1089     CPPUNIT_TEST(testDrawXor);
1090 
1091     CPPUNIT_TEST(testDrawTransformedBitmapExAlpha);
1092 
1093     CPPUNIT_TEST(testClipRectangle);
1094     CPPUNIT_TEST(testClipPolygon);
1095     CPPUNIT_TEST(testClipPolyPolygon);
1096     CPPUNIT_TEST(testClipB2DPolyPolygon);
1097 
1098     CPPUNIT_TEST(testDrawOutDev);
1099 
1100     CPPUNIT_TEST(testDashedLine);
1101 
1102     CPPUNIT_TEST(testErase);
1103 
1104     CPPUNIT_TEST(testLinearGradient);
1105     CPPUNIT_TEST(testLinearGradientAngled);
1106     CPPUNIT_TEST(testLinearGradientBorder);
1107     CPPUNIT_TEST(testLinearGradientIntensity);
1108     CPPUNIT_TEST(testLinearGradientSteps);
1109     CPPUNIT_TEST(testAxialGradient);
1110     CPPUNIT_TEST(testRadialGradient);
1111     CPPUNIT_TEST(testRadialGradientOfs);
1112 
1113     CPPUNIT_TEST(testLineCapRound);
1114     CPPUNIT_TEST(testLineCapSquare);
1115     CPPUNIT_TEST(testLineCapButt);
1116     CPPUNIT_TEST(testLineJoinBevel);
1117     CPPUNIT_TEST(testLineJoinRound);
1118     CPPUNIT_TEST(testLineJoinMiter);
1119     CPPUNIT_TEST(testLineJoinNone);
1120 
1121     CPPUNIT_TEST(testDrawBlendExtended);
1122     CPPUNIT_TEST(testDrawAlphaBitmapMirrored);
1123 
1124     CPPUNIT_TEST(testTdf124848);
1125     CPPUNIT_TEST(testTdf136171);
1126 
1127     CPPUNIT_TEST_SUITE_END();
1128 };
1129 
1130 CPPUNIT_TEST_SUITE_REGISTRATION(BackendTest);
1131 
1132 CPPUNIT_PLUGIN_IMPLEMENT();
1133 
1134 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1135