1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <test/bootstrapfixture.hxx>
12 #include <tools/stream.hxx>
13 #include <basegfx/matrix/b2dhommatrix.hxx>
15 #include <vcl/graphicfilter.hxx>
16 #include <vcl/virdev.hxx>
17 #include <vcl/skia/SkiaHelper.hxx>
19 #include <skia/salbmp.hxx>
20 #include <skia/utils.hxx>
21 #include <vcl/BitmapWriteAccess.hxx>
23 using namespace SkiaHelper
;
25 // This tests backends that use Skia (i.e. intentionally not the svp one, which is the default.)
26 // Note that you still may need to actually set for Skia to be used (see vcl/README.vars).
27 // If Skia is not enabled, all tests will be silently skipped.
30 class SkiaTest
: public test::BootstrapFixture
34 : test::BootstrapFixture(true, false)
38 void testBitmapErase();
39 void testDrawShaders();
40 void testInterpretAs8Bit();
41 void testAlphaBlendWith();
42 void testBitmapCopyOnWrite();
43 void testMatrixQuality();
44 void testDelayedScale();
45 void testDelayedScaleAlphaImage();
46 void testDrawDelayedScaleImage();
52 CPPUNIT_TEST_SUITE(SkiaTest
);
53 CPPUNIT_TEST(testBitmapErase
);
54 CPPUNIT_TEST(testDrawShaders
);
55 CPPUNIT_TEST(testInterpretAs8Bit
);
56 CPPUNIT_TEST(testAlphaBlendWith
);
57 CPPUNIT_TEST(testBitmapCopyOnWrite
);
58 CPPUNIT_TEST(testMatrixQuality
);
59 CPPUNIT_TEST(testDelayedScale
);
60 CPPUNIT_TEST(testDelayedScaleAlphaImage
);
61 CPPUNIT_TEST(testDrawDelayedScaleImage
);
62 CPPUNIT_TEST(testChecksum
);
63 CPPUNIT_TEST(testTdf137329
);
64 CPPUNIT_TEST(testTdf140848
);
65 CPPUNIT_TEST(testTdf132367
);
66 CPPUNIT_TEST_SUITE_END();
70 template <class BitmapT
> // handle both Bitmap and BitmapEx
71 void savePNG(const OUString
& sWhere
, const BitmapT
& rBmp
)
73 SvFileStream
aStream(sWhere
, StreamMode::WRITE
| StreamMode::TRUNC
);
74 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
75 rFilter
.compressAsPNG(BitmapEx(rBmp
), aStream
);
77 void savePNG(const OUString
& sWhere
, const ScopedVclPtr
<VirtualDevice
>& device
)
79 SvFileStream
aStream(sWhere
, StreamMode::WRITE
| StreamMode::TRUNC
);
80 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
81 rFilter
.compressAsPNG(device
->GetBitmapEx(Point(), device
->GetOutputSizePixel()), aStream
);
86 void SkiaTest::testBitmapErase()
88 if (!SkiaHelper::isVCLSkiaEnabled())
90 Bitmap
bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
91 SkiaSalBitmap
* skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
92 CPPUNIT_ASSERT(skiaBitmap
);
93 // Uninitialized bitmap.
94 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasBuffer());
95 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasImage());
96 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasAlphaImage());
97 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasEraseColor());
98 // Test that Bitmap.Erase() just sets erase color and doesn't allocate pixels.
99 bitmap
.Erase(COL_RED
);
100 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
101 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasBuffer());
102 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasImage());
103 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasAlphaImage());
104 CPPUNIT_ASSERT(skiaBitmap
->unittestHasEraseColor());
105 // Reading a pixel will create pixel data.
106 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED
), BitmapReadAccess(bitmap
).GetColor(0, 0));
107 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
108 CPPUNIT_ASSERT(skiaBitmap
->unittestHasBuffer());
109 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasImage());
110 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasAlphaImage());
111 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasEraseColor());
114 // Test that draw calls that internally result in SkShader calls work properly.
115 void SkiaTest::testDrawShaders()
117 if (!SkiaHelper::isVCLSkiaEnabled())
119 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
120 device
->SetOutputSizePixel(Size(20, 20));
121 device
->SetBackground(Wallpaper(COL_WHITE
));
123 Bitmap
bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
124 bitmap
.Erase(COL_RED
);
125 SkiaSalBitmap
* skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
126 CPPUNIT_ASSERT(skiaBitmap
->PreferSkShader());
127 AlphaMask
alpha(Size(10, 10));
129 SkiaSalBitmap
* skiaAlpha
130 = dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
131 CPPUNIT_ASSERT(skiaAlpha
->PreferSkShader());
133 device
->DrawBitmap(Point(5, 5), bitmap
);
134 //savePNG("/tmp/a1.png", device);
135 // Check that the area is painted, but nothing else.
136 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(0, 0)));
137 CPPUNIT_ASSERT_EQUAL(COL_RED
, device
->GetPixel(Point(5, 5)));
138 CPPUNIT_ASSERT_EQUAL(COL_RED
, device
->GetPixel(Point(14, 14)));
139 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(15, 15)));
142 device
->DrawBitmapEx(Point(5, 5), BitmapEx(bitmap
, alpha
));
143 //savePNG("/tmp/a2.png", device);
144 Color
resultRed(COL_RED
.GetRed() * 3 / 4 + 64, 64, 64); // 3/4 red, 1/4 white
145 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(0, 0)));
146 CPPUNIT_ASSERT_EQUAL(resultRed
, device
->GetPixel(Point(5, 5)));
147 CPPUNIT_ASSERT_EQUAL(resultRed
, device
->GetPixel(Point(14, 14)));
148 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(15, 15)));
151 basegfx::B2DHomMatrix matrix
;
152 matrix
.scale(10, 10);
153 matrix
.rotate(M_PI
/ 4);
154 device
->DrawTransformedBitmapEx(matrix
, BitmapEx(bitmap
, alpha
));
155 //savePNG("/tmp/a3.png", device);
156 CPPUNIT_ASSERT_EQUAL(resultRed
, device
->GetPixel(Point(0, 1)));
157 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(1, 0)));
158 CPPUNIT_ASSERT_EQUAL(resultRed
, device
->GetPixel(Point(0, 10)));
159 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(10, 10)));
162 // Test with scaling. Use everything 10x larger to reduce the impact of smoothscaling.
163 ScopedVclPtr
<VirtualDevice
> deviceLarge
164 = VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
165 deviceLarge
->SetOutputSizePixel(Size(200, 200));
166 deviceLarge
->SetBackground(Wallpaper(COL_WHITE
));
167 deviceLarge
->Erase();
168 Bitmap
bitmapLarge(Size(100, 100), vcl::PixelFormat::N24_BPP
);
169 bitmapLarge
.Erase(COL_RED
);
170 SkiaSalBitmap
* skiaBitmapLarge
171 = dynamic_cast<SkiaSalBitmap
*>(bitmapLarge
.ImplGetSalBitmap().get());
172 CPPUNIT_ASSERT(skiaBitmapLarge
->PreferSkShader());
173 AlphaMask
alphaLarge(Size(100, 100));
174 alphaLarge
.Erase(64);
176 BitmapWriteAccess
access(bitmapLarge
);
177 access
.SetFillColor(COL_BLUE
);
178 access
.FillRect(tools::Rectangle(Point(20, 40), Size(10, 10)));
180 // Using alpha will still lead to shaders being used.
181 deviceLarge
->DrawBitmapEx(Point(50, 50), Size(60, 60), Point(20, 20), Size(30, 30),
182 BitmapEx(bitmapLarge
, alphaLarge
));
183 //savePNG("/tmp/a4.png", deviceLarge);
184 Color
resultBlue(64, 64, COL_BLUE
.GetBlue() * 3 / 4 + 64); // 3/4 blue, 1/4 white
185 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, deviceLarge
->GetPixel(Point(40, 40)));
186 CPPUNIT_ASSERT_EQUAL(resultRed
, deviceLarge
->GetPixel(Point(50, 50)));
187 CPPUNIT_ASSERT_EQUAL(resultRed
, deviceLarge
->GetPixel(Point(100, 100)));
188 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, deviceLarge
->GetPixel(Point(110, 110)));
189 // Don't test colors near the edge between the colors, smoothscaling affects them.
191 CPPUNIT_ASSERT_EQUAL(resultRed
, deviceLarge
->GetPixel(Point(50 + diff
, 89 - diff
)));
192 CPPUNIT_ASSERT_EQUAL(resultBlue
, deviceLarge
->GetPixel(Point(50 + diff
, 90 + diff
)));
193 CPPUNIT_ASSERT_EQUAL(resultBlue
, deviceLarge
->GetPixel(Point(69 - diff
, 100 - diff
)));
194 CPPUNIT_ASSERT_EQUAL(resultRed
, deviceLarge
->GetPixel(Point(70 + diff
, 100 - diff
)));
195 CPPUNIT_ASSERT_EQUAL(resultBlue
, deviceLarge
->GetPixel(Point(50 + diff
, 100 - diff
)));
199 void SkiaTest::testInterpretAs8Bit()
201 if (!SkiaHelper::isVCLSkiaEnabled())
203 Bitmap
bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
204 // Test with erase color.
205 bitmap
.Erase(Color(33, 33, 33));
206 SkiaSalBitmap
* skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
207 CPPUNIT_ASSERT(skiaBitmap
->unittestHasEraseColor());
208 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP
, bitmap
.getPixelFormat());
209 bitmap
.Convert(BmpConversion::N8BitNoConversion
);
210 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
211 CPPUNIT_ASSERT(skiaBitmap
->unittestHasEraseColor());
212 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, bitmap
.getPixelFormat());
213 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8
>(33), BitmapReadAccess(bitmap
).GetPixelIndex(0, 0));
216 bitmap
= Bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
217 bitmap
.Erase(Color(34, 34, 34));
218 BitmapReadAccess(bitmap
).GetColor(0, 0); // Create pixel data, reset erase color.
219 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
220 skiaBitmap
->GetSkImage();
221 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasEraseColor());
222 CPPUNIT_ASSERT(skiaBitmap
->unittestHasImage());
223 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP
, bitmap
.getPixelFormat());
224 bitmap
.Convert(BmpConversion::N8BitNoConversion
);
225 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
226 CPPUNIT_ASSERT(skiaBitmap
->unittestHasImage());
227 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, bitmap
.getPixelFormat());
228 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8
>(34), BitmapReadAccess(bitmap
).GetPixelIndex(0, 0));
231 void SkiaTest::testAlphaBlendWith()
233 if (!SkiaHelper::isVCLSkiaEnabled())
235 AlphaMask
alpha(Size(10, 10));
236 AlphaMask
bitmap(Size(10, 10));
237 // Test with erase colors set.
239 SkiaSalBitmap
* skiaAlpha
240 = dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
241 CPPUNIT_ASSERT(skiaAlpha
->unittestHasEraseColor());
243 SkiaSalBitmap
* skiaBitmap
244 = dynamic_cast<SkiaSalBitmap
*>(bitmap
.GetBitmap().ImplGetSalBitmap().get());
245 CPPUNIT_ASSERT(skiaBitmap
->unittestHasEraseColor());
246 alpha
.BlendWith(bitmap
);
247 skiaAlpha
= dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
248 CPPUNIT_ASSERT(skiaAlpha
->unittestHasEraseColor());
249 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, alpha
.getPixelFormat());
250 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8
>(255 - 112),
251 BitmapScopedReadAccess(alpha
)->GetPixelIndex(0, 0));
253 // Test with images set.
255 BitmapScopedReadAccess(alpha
)->GetColor(0, 0); // Reading a pixel will create pixel data.
256 skiaAlpha
= dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
257 skiaAlpha
->GetSkImage();
258 CPPUNIT_ASSERT(!skiaAlpha
->unittestHasEraseColor());
259 CPPUNIT_ASSERT(skiaAlpha
->unittestHasImage());
261 BitmapScopedReadAccess(bitmap
)->GetColor(0, 0); // Reading a pixel will create pixel data.
262 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.GetBitmap().ImplGetSalBitmap().get());
263 skiaBitmap
->GetSkImage();
264 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasEraseColor());
265 CPPUNIT_ASSERT(skiaBitmap
->unittestHasImage());
266 alpha
.BlendWith(bitmap
);
267 skiaAlpha
= dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
268 CPPUNIT_ASSERT(skiaAlpha
->unittestHasImage());
269 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, alpha
.getPixelFormat());
270 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8
>(255 - 112),
271 BitmapScopedReadAccess(alpha
)->GetPixelIndex(0, 0));
273 // Test with erase color for alpha and image for other bitmap.
275 skiaAlpha
= dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
276 CPPUNIT_ASSERT(skiaAlpha
->unittestHasEraseColor());
278 BitmapScopedReadAccess(bitmap
)->GetColor(0, 0); // Reading a pixel will create pixel data.
279 skiaBitmap
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.GetBitmap().ImplGetSalBitmap().get());
280 skiaBitmap
->GetSkImage();
281 CPPUNIT_ASSERT(!skiaBitmap
->unittestHasEraseColor());
282 CPPUNIT_ASSERT(skiaBitmap
->unittestHasImage());
283 alpha
.BlendWith(bitmap
);
284 skiaAlpha
= dynamic_cast<SkiaSalBitmap
*>(alpha
.GetBitmap().ImplGetSalBitmap().get());
285 CPPUNIT_ASSERT(skiaAlpha
->unittestHasImage());
286 CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP
, alpha
.getPixelFormat());
287 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8
>(255 - 112),
288 BitmapScopedReadAccess(alpha
)->GetPixelIndex(0, 0));
291 void SkiaTest::testBitmapCopyOnWrite()
293 if (!SkiaHelper::isVCLSkiaEnabled())
295 SkiaSalBitmap bitmap
;
296 CPPUNIT_ASSERT(bitmap
.Create(Size(10, 10), vcl::PixelFormat::N24_BPP
, BitmapPalette()));
298 bitmap
.GetAlphaSkImage();
299 CPPUNIT_ASSERT(bitmap
.unittestHasBuffer());
300 CPPUNIT_ASSERT(bitmap
.unittestHasImage());
301 CPPUNIT_ASSERT(bitmap
.unittestHasAlphaImage());
302 SkiaSalBitmap bitmap2
;
303 CPPUNIT_ASSERT(bitmap2
.Create(bitmap
));
304 // Data should be shared.
305 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetBuffer(), bitmap2
.unittestGetBuffer());
306 CPPUNIT_ASSERT(bitmap2
.unittestHasImage());
307 CPPUNIT_ASSERT(bitmap2
.unittestHasAlphaImage());
308 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetImage(), bitmap2
.unittestGetImage());
309 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetAlphaImage(), bitmap2
.unittestGetAlphaImage());
310 // Reading still should keep the data shared.
311 const SkImage
* oldImage
= bitmap
.unittestGetImage();
312 const SkImage
* oldAlphaImage
= bitmap
.unittestGetAlphaImage();
313 BitmapBuffer
* buffer
= bitmap
.AcquireBuffer(BitmapAccessMode::Read
);
314 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetBuffer(), bitmap2
.unittestGetBuffer());
315 bitmap
.ReleaseBuffer(buffer
, BitmapAccessMode::Read
);
316 // Images get possibly updated only after releasing the buffer.
317 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetImage(), bitmap2
.unittestGetImage());
318 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetAlphaImage(), bitmap2
.unittestGetAlphaImage());
319 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetImage(), oldImage
);
320 CPPUNIT_ASSERT_EQUAL(bitmap
.unittestGetAlphaImage(), oldAlphaImage
);
321 // Writing should unshare.
322 buffer
= bitmap
.AcquireBuffer(BitmapAccessMode::Write
);
323 CPPUNIT_ASSERT(bitmap
.unittestGetBuffer() != bitmap2
.unittestGetBuffer());
324 bitmap
.ReleaseBuffer(buffer
, BitmapAccessMode::Write
);
325 CPPUNIT_ASSERT(bitmap
.unittestGetImage() != bitmap2
.unittestGetImage());
326 CPPUNIT_ASSERT(bitmap
.unittestGetAlphaImage() != bitmap2
.unittestGetAlphaImage());
327 CPPUNIT_ASSERT(bitmap
.unittestGetImage() != oldImage
);
328 CPPUNIT_ASSERT(bitmap
.unittestGetAlphaImage() != oldAlphaImage
);
331 void SkiaTest::testMatrixQuality()
333 if (!SkiaHelper::isVCLSkiaEnabled())
335 // Not changing the size (but possibly rotated/flipped) does not need high quality transformations.
336 CPPUNIT_ASSERT(!SkiaTests::matrixNeedsHighQuality(SkMatrix()));
337 CPPUNIT_ASSERT(!SkiaTests::matrixNeedsHighQuality(SkMatrix::RotateDeg(90)));
338 CPPUNIT_ASSERT(!SkiaTests::matrixNeedsHighQuality(SkMatrix::RotateDeg(180)));
339 CPPUNIT_ASSERT(!SkiaTests::matrixNeedsHighQuality(SkMatrix::RotateDeg(270)));
340 CPPUNIT_ASSERT(!SkiaTests::matrixNeedsHighQuality(SkMatrix::Scale(1, -1)));
341 CPPUNIT_ASSERT(SkiaTests::matrixNeedsHighQuality(SkMatrix::Scale(0, -1)));
342 CPPUNIT_ASSERT(SkiaTests::matrixNeedsHighQuality(SkMatrix::Scale(2, 1)));
343 CPPUNIT_ASSERT(SkiaTests::matrixNeedsHighQuality(SkMatrix::RotateDeg(89)));
346 void SkiaTest::testDelayedScale()
348 if (!SkiaHelper::isVCLSkiaEnabled())
350 Bitmap
bitmap1(Size(10, 10), vcl::PixelFormat::N24_BPP
);
351 SkiaSalBitmap
* skiaBitmap1
= dynamic_cast<SkiaSalBitmap
*>(bitmap1
.ImplGetSalBitmap().get());
352 CPPUNIT_ASSERT(skiaBitmap1
);
353 // Do scaling based on mBuffer.
354 (void)BitmapReadAccess(bitmap1
); // allocates mBuffer
355 CPPUNIT_ASSERT(skiaBitmap1
->unittestHasBuffer());
356 CPPUNIT_ASSERT(!skiaBitmap1
->unittestHasImage());
357 CPPUNIT_ASSERT(bitmap1
.Scale(2, 2, BmpScaleFlag::Default
));
358 skiaBitmap1
= dynamic_cast<SkiaSalBitmap
*>(bitmap1
.ImplGetSalBitmap().get());
359 CPPUNIT_ASSERT(skiaBitmap1
);
360 CPPUNIT_ASSERT(skiaBitmap1
->unittestHasBuffer());
361 CPPUNIT_ASSERT(!skiaBitmap1
->unittestHasImage());
362 CPPUNIT_ASSERT_EQUAL(Size(20, 20), bitmap1
.GetSizePixel());
363 CPPUNIT_ASSERT_EQUAL(Size(20, 20), imageSize(skiaBitmap1
->GetSkImage()));
364 BitmapBuffer
* buffer1
= skiaBitmap1
->AcquireBuffer(BitmapAccessMode::Read
);
365 CPPUNIT_ASSERT(buffer1
);
366 CPPUNIT_ASSERT_EQUAL(tools::Long(20), buffer1
->mnWidth
);
367 CPPUNIT_ASSERT_EQUAL(tools::Long(20), buffer1
->mnHeight
);
368 skiaBitmap1
->ReleaseBuffer(buffer1
, BitmapAccessMode::Read
);
369 // Do scaling based on mImage.
370 SkiaSalBitmap
skiaBitmap2(skiaBitmap1
->GetSkImage());
371 CPPUNIT_ASSERT(!skiaBitmap2
.unittestHasBuffer());
372 CPPUNIT_ASSERT(skiaBitmap2
.unittestHasImage());
373 CPPUNIT_ASSERT(skiaBitmap2
.Scale(2, 3, BmpScaleFlag::Default
));
374 CPPUNIT_ASSERT(!skiaBitmap2
.unittestHasBuffer());
375 CPPUNIT_ASSERT(skiaBitmap2
.unittestHasImage());
376 CPPUNIT_ASSERT_EQUAL(Size(40, 60), skiaBitmap2
.GetSize());
377 CPPUNIT_ASSERT_EQUAL(Size(40, 60), imageSize(skiaBitmap2
.GetSkImage()));
378 BitmapBuffer
* buffer2
= skiaBitmap2
.AcquireBuffer(BitmapAccessMode::Read
);
379 CPPUNIT_ASSERT(buffer2
);
380 CPPUNIT_ASSERT_EQUAL(tools::Long(40), buffer2
->mnWidth
);
381 CPPUNIT_ASSERT_EQUAL(tools::Long(60), buffer2
->mnHeight
);
382 skiaBitmap2
.ReleaseBuffer(buffer2
, BitmapAccessMode::Read
);
385 void SkiaTest::testDelayedScaleAlphaImage()
387 if (!SkiaHelper::isVCLSkiaEnabled())
389 auto bitmapTmp
= std::make_unique
<SkiaSalBitmap
>();
390 CPPUNIT_ASSERT(bitmapTmp
->Create(Size(10, 10), vcl::PixelFormat::N24_BPP
, BitmapPalette()));
391 bitmapTmp
->Erase(COL_RED
);
392 // Create a bitmap that has only an image, not a pixel buffer.
393 SkiaSalBitmap
bitmap(bitmapTmp
->GetSkImage());
395 CPPUNIT_ASSERT(!bitmap
.unittestHasBuffer());
396 CPPUNIT_ASSERT(bitmap
.unittestHasImage());
397 CPPUNIT_ASSERT(!bitmap
.unittestHasAlphaImage());
398 // Set up pending scale.
399 CPPUNIT_ASSERT(bitmap
.Scale(2.0, 2.0, BmpScaleFlag::Fast
));
400 CPPUNIT_ASSERT(bitmap
.unittestHasPendingScale());
401 CPPUNIT_ASSERT(bitmap
.InterpretAs8Bit());
402 // Ask for SkImage and make sure it's scaled up.
403 sk_sp
<SkImage
> image
= bitmap
.GetSkImage();
404 CPPUNIT_ASSERT_EQUAL(20, image
->width());
405 // Ask again, this time it should be cached.
406 sk_sp
<SkImage
> image2
= bitmap
.GetSkImage();
407 CPPUNIT_ASSERT_EQUAL(image
.get(), image2
.get());
408 // Add another scale.
409 CPPUNIT_ASSERT(bitmap
.Scale(3.0, 3.0, BmpScaleFlag::Fast
));
410 // Ask for alpha SkImage and make sure it's scaled up.
411 sk_sp
<SkImage
> alphaImage
= bitmap
.GetAlphaSkImage();
412 CPPUNIT_ASSERT_EQUAL(60, alphaImage
->width());
413 // Ask again, this time it should be cached.
414 sk_sp
<SkImage
> alphaImage2
= bitmap
.GetAlphaSkImage();
415 CPPUNIT_ASSERT_EQUAL(alphaImage
.get(), alphaImage2
.get());
416 // Ask again for non-alpha image, it should be scaled again.
417 sk_sp
<SkImage
> image3
= bitmap
.GetSkImage();
418 CPPUNIT_ASSERT_EQUAL(60, image3
->width());
419 CPPUNIT_ASSERT(image3
.get() != image2
.get());
420 CPPUNIT_ASSERT(image3
.get() != image
.get());
421 // Create pixel buffer from the image (it should convert from alpha image because the bitmap is 8bpp
422 // and the alpha image size matches).
423 SkiaSalBitmap bitmapCopy
;
424 bitmapCopy
.Create(bitmap
);
425 CPPUNIT_ASSERT(!bitmap
.unittestHasBuffer());
426 BitmapBuffer
* buffer1
= bitmap
.AcquireBuffer(BitmapAccessMode::Read
);
427 CPPUNIT_ASSERT(bitmap
.unittestHasBuffer());
428 bitmap
.ReleaseBuffer(buffer1
, BitmapAccessMode::Read
);
429 CPPUNIT_ASSERT_EQUAL(Size(60, 60), bitmap
.GetSize());
430 // Scale the copy before the buffer was created (this time it should convert from non-alpha image
431 // because of the different size).
432 CPPUNIT_ASSERT(!bitmapCopy
.unittestHasBuffer());
433 CPPUNIT_ASSERT(bitmapCopy
.Scale(4.0, 4.0, BmpScaleFlag::Fast
));
434 BitmapBuffer
* buffer2
= bitmapCopy
.AcquireBuffer(BitmapAccessMode::Read
);
435 CPPUNIT_ASSERT(bitmapCopy
.unittestHasBuffer());
436 bitmapCopy
.ReleaseBuffer(buffer2
, BitmapAccessMode::Read
);
437 CPPUNIT_ASSERT_EQUAL(Size(240, 240), bitmapCopy
.GetSize());
440 void SkiaTest::testDrawDelayedScaleImage()
442 if (!SkiaHelper::isVCLSkiaEnabled())
444 if (SkiaHelper::renderMethodToUse() != SkiaHelper::RenderRaster
)
445 return; // This test tests caching that's done only in raster mode.
446 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
447 device
->SetOutputSizePixel(Size(10, 10));
448 device
->SetBackground(Wallpaper(COL_WHITE
));
450 Bitmap
bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
451 bitmap
.Erase(COL_RED
);
452 // Set a pixel to create pixel data.
453 BitmapWriteAccess(bitmap
).SetPixel(0, 0, COL_BLUE
);
454 SkiaSalBitmap
* skiaBitmap1
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
455 // Force creating of image.
456 sk_sp
<SkImage
> image1
= skiaBitmap1
->GetSkImage();
457 CPPUNIT_ASSERT(skiaBitmap1
->unittestHasImage());
458 CPPUNIT_ASSERT(bitmap
.Scale(Size(5, 5)));
459 // Make sure delayed scaling has not changed the image.
460 SkiaSalBitmap
* skiaBitmap2
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
461 CPPUNIT_ASSERT(skiaBitmap2
->unittestHasImage());
462 sk_sp
<SkImage
> image2
= skiaBitmap2
->GetSkImage(SkiaHelper::DirectImage::Yes
);
463 CPPUNIT_ASSERT_EQUAL(image1
, image2
);
464 CPPUNIT_ASSERT_EQUAL(Size(5, 5), bitmap
.GetSizePixel());
465 CPPUNIT_ASSERT_EQUAL(Size(10, 10), SkiaHelper::imageSize(image2
));
466 // Draw the bitmap scaled to size 10x10 and check that the 10x10 image was used (and kept),
467 // even though technically the bitmap is 5x5.
468 device
->DrawBitmap(Point(0, 0), Size(10, 10), bitmap
);
469 SkiaSalBitmap
* skiaBitmap3
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
470 CPPUNIT_ASSERT(skiaBitmap3
->unittestHasImage());
471 sk_sp
<SkImage
> image3
= skiaBitmap3
->GetSkImage(SkiaHelper::DirectImage::Yes
);
472 CPPUNIT_ASSERT_EQUAL(image1
, image3
);
473 CPPUNIT_ASSERT_EQUAL(Size(5, 5), bitmap
.GetSizePixel());
474 CPPUNIT_ASSERT_EQUAL(Size(10, 10), SkiaHelper::imageSize(image3
));
477 void SkiaTest::testChecksum()
479 if (!SkiaHelper::isVCLSkiaEnabled())
481 Bitmap
bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
482 bitmap
.Erase(COL_RED
);
483 BitmapChecksum checksum1
= bitmap
.GetChecksum();
484 // Set a pixel to create pixel data, that should change checksum.
485 BitmapWriteAccess(bitmap
).SetPixel(0, 0, COL_BLUE
);
486 BitmapChecksum checksum2
= bitmap
.GetChecksum();
487 CPPUNIT_ASSERT(checksum2
!= checksum1
);
488 SkiaSalBitmap
* skiaBitmap1
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
489 // Creating an image should not change the checksum.
490 sk_sp
<SkImage
> image1
= skiaBitmap1
->GetSkImage();
491 BitmapChecksum checksum3
= bitmap
.GetChecksum();
492 CPPUNIT_ASSERT_EQUAL(checksum2
, checksum3
);
493 // Delayed scaling should change checksum even if the scaling has not taken place.
494 bitmap
.Scale(Size(20, 20));
495 BitmapChecksum checksum4
= bitmap
.GetChecksum();
496 CPPUNIT_ASSERT(checksum4
!= checksum3
);
497 // Setting back to the original red content should have the original checksum.
498 // (This also makes sure this next step is not affected by the delayed scaling
499 // above possibly taking place now.)
500 bitmap
= Bitmap(Size(10, 10), vcl::PixelFormat::N24_BPP
);
501 bitmap
.Erase(COL_RED
);
502 BitmapChecksum checksum5
= bitmap
.GetChecksum();
503 CPPUNIT_ASSERT_EQUAL(checksum1
, checksum5
);
504 // The optimized changing of images to greyscale should change the checksum.
505 SkiaSalBitmap
* skiaBitmap2
= dynamic_cast<SkiaSalBitmap
*>(bitmap
.ImplGetSalBitmap().get());
506 skiaBitmap2
->unittestResetToImage();
507 BitmapChecksum checksum6
= skiaBitmap2
->GetChecksum();
508 CPPUNIT_ASSERT_EQUAL(checksum5
, checksum6
);
509 CPPUNIT_ASSERT(skiaBitmap2
->ConvertToGreyscale());
510 BitmapChecksum checksum7
= skiaBitmap2
->GetChecksum();
511 CPPUNIT_ASSERT(checksum7
!= checksum6
);
514 void SkiaTest::testTdf137329()
516 if (!SkiaHelper::isVCLSkiaEnabled())
518 // Draw a filled polygon in the entire device, with AA enabled.
519 // All pixels in the device should be black, even those at edges (i.e. not affected by AA).
520 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
521 device
->SetOutputSizePixel(Size(10, 10));
522 device
->SetBackground(Wallpaper(COL_WHITE
));
523 device
->SetAntialiasing(AntialiasingFlags::Enable
);
525 device
->SetLineColor();
526 device
->SetFillColor(COL_BLACK
);
527 device
->DrawPolyPolygon(
528 basegfx::B2DPolyPolygon(basegfx::B2DPolygon
{ { 0, 0 }, { 10, 0 }, { 10, 10 }, { 0, 10 } }));
529 // savePNG("/tmp/tdf137329.png", device);
530 CPPUNIT_ASSERT_EQUAL(COL_BLACK
, device
->GetPixel(Point(0, 0)));
531 CPPUNIT_ASSERT_EQUAL(COL_BLACK
, device
->GetPixel(Point(9, 0)));
532 CPPUNIT_ASSERT_EQUAL(COL_BLACK
, device
->GetPixel(Point(9, 9)));
533 CPPUNIT_ASSERT_EQUAL(COL_BLACK
, device
->GetPixel(Point(0, 9)));
534 CPPUNIT_ASSERT_EQUAL(COL_BLACK
, device
->GetPixel(Point(4, 4)));
537 void SkiaTest::testTdf140848()
539 if (!SkiaHelper::isVCLSkiaEnabled())
541 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
542 device
->SetOutputSizePixel(Size(1300, 400));
543 device
->SetBackground(Wallpaper(COL_BLACK
));
544 device
->SetAntialiasing(AntialiasingFlags::Enable
);
546 device
->SetLineColor();
547 device
->SetFillColor(COL_WHITE
);
548 basegfx::B2DPolygon p1
= { { 952.73121259842514519, 102.4599685039370911 },
549 { 952.73121259842514519, 66.55445669291347599 },
550 { 1239.9753070866140661, 66.554456692913390725 },
551 { 1239.9753070866140661, 138.36548031496062094 },
552 { 952.73121259842514519, 138.36548031496070621 } };
553 basegfx::B2DPolygon p2
= { { 1168.1642834645670064, 210.17650393700790801 },
554 { 1168.1642834645670064, 66.554456692913404936 },
555 { 1239.9753070866140661, 66.554456692913390725 },
556 { 1239.9753070866142934, 353.79855118110236845 },
557 { 1168.1642834645670064, 353.79855118110236845 } };
558 device
->DrawPolyPolygon(basegfx::B2DPolyPolygon(p1
));
559 device
->DrawPolyPolygon(basegfx::B2DPolyPolygon(p2
));
560 //savePNG("/tmp/tdf140848.png", device);
561 // Rounding errors caused the overlapping part not to be drawn.
562 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, device
->GetPixel(Point(1200, 100)));
565 void SkiaTest::testTdf132367()
567 if (!SkiaHelper::isVCLSkiaEnabled())
569 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
570 device
->SetOutputSizePixel(Size(2, 2));
571 device
->SetBackground(Wallpaper(COL_BLACK
));
573 device
->DrawPixel(Point(1, 1), COL_WHITE
);
574 // This will make the bitmap store data in SkImage.
575 Bitmap bitmap
= device
->GetBitmap(Point(0, 0), Size(2, 2));
576 // Scaling will only set up delayed scaling of the SkImage.
577 bitmap
.Scale(Size(4, 4), BmpScaleFlag::NearestNeighbor
);
578 // Now it will need to be converted to pixel buffer, check it's converted properly
580 BitmapReadAccess
access(bitmap
);
581 CPPUNIT_ASSERT_EQUAL(tools::Long(4), access
.Width());
582 CPPUNIT_ASSERT_EQUAL(tools::Long(4), access
.Height());
583 CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE
), access
.GetColor(3, 3));
588 CPPUNIT_TEST_SUITE_REGISTRATION(SkiaTest
);
590 CPPUNIT_PLUGIN_IMPLEMENT();
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */