[Libreoffice-commits] core.git: vcl/qa vcl/skia
LuboÅ¡ LuÅák (via logerrit)
logerrit at kemper.freedesktop.org
Fri Oct 2 05:26:12 UTC 2020
vcl/qa/cppunit/skia/skia.cxx | 111 ++++++++++++++++++++++++++++++++++++++++++-
vcl/skia/gdiimpl.cxx | 30 +++++------
2 files changed, 125 insertions(+), 16 deletions(-)
New commits:
commit c1206e12eab237ffa7dde728da5bf1883a05ddb0
Author: Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Wed Sep 30 18:39:39 2020 +0200
Commit: Luboš Luňák <l.lunak at collabora.com>
CommitDate: Fri Oct 2 07:25:26 2020 +0200
SkCanvas::drawPaint() -> drawRect(), where applicable, and fix matrix
It makes the code a bit simpler. Also fix the matrix used
in SkiaSalGraphicsImpl::drawShader(), plus add asserts to verify
it's correct.
Change-Id: Ia6692ad90e822e6e44028b280dc2faaac06959a5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103743
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
diff --git a/vcl/qa/cppunit/skia/skia.cxx b/vcl/qa/cppunit/skia/skia.cxx
index 07f5a872ddbb..28591d807bb1 100644
--- a/vcl/qa/cppunit/skia/skia.cxx
+++ b/vcl/qa/cppunit/skia/skia.cxx
@@ -11,7 +11,11 @@
#include <vcl/skia/SkiaHelper.hxx>
#include <skia/salbmp.hxx>
-#include <vcl/bitmapaccess.hxx>
+#include <bitmapwriteaccess.hxx>
+#include <vcl/virdev.hxx>
+#include <tools/stream.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
// This tests backends that use Skia (i.e. intentionally not the svp one, which is the default.)
// Note that you still may need to actually set for Skia to be used (see vcl/README.vars).
@@ -27,10 +31,29 @@ public:
}
void testBitmapErase();
+ void testDrawShaders();
CPPUNIT_TEST_SUITE(SkiaTest);
CPPUNIT_TEST(testBitmapErase);
+ CPPUNIT_TEST(testDrawShaders);
CPPUNIT_TEST_SUITE_END();
+
+private:
+#if 0
+ template <class BitmapT> // handle both Bitmap and BitmapEx
+ void savePNG(const OUString& sWhere, const BitmapT& rBmp)
+ {
+ SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC);
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.compressAsPNG(BitmapEx(rBmp), aStream);
+ }
+ void savePNG(const OUString& sWhere, const ScopedVclPtr<VirtualDevice>& device)
+ {
+ SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC);
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ rFilter.compressAsPNG(device->GetBitmapEx(Point(), device->GetOutputSizePixel()), aStream);
+ }
+#endif
};
void SkiaTest::testBitmapErase()
@@ -62,6 +85,92 @@ void SkiaTest::testBitmapErase()
CPPUNIT_ASSERT(!skiaBitmap->unittestHasEraseColor());
}
+// Test that draw calls that internally result in SkShader calls work properly.
+void SkiaTest::testDrawShaders()
+{
+ if (!SkiaHelper::isVCLSkiaEnabled())
+ return;
+ ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
+ device->SetOutputSizePixel(Size(20, 20));
+ device->SetBackground(Wallpaper(COL_WHITE));
+ device->Erase();
+ Bitmap bitmap(Size(10, 10), 24);
+ bitmap.Erase(COL_RED);
+ SkiaSalBitmap* skiaBitmap = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+ CPPUNIT_ASSERT(skiaBitmap);
+ CPPUNIT_ASSERT(skiaBitmap->PreferSkShader());
+ AlphaMask alpha(Size(10, 10));
+ alpha.Erase(64);
+ SkiaSalBitmap* skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+ CPPUNIT_ASSERT(skiaAlpha);
+ CPPUNIT_ASSERT(skiaAlpha->PreferSkShader());
+
+ device->DrawBitmap(Point(5, 5), bitmap);
+ //savePNG("/tmp/a1.png", device);
+ // Check that the area is painted, but nothing else.
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(0, 0)));
+ CPPUNIT_ASSERT_EQUAL(COL_RED, device->GetPixel(Point(5, 5)));
+ CPPUNIT_ASSERT_EQUAL(COL_RED, device->GetPixel(Point(14, 14)));
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(15, 15)));
+ device->Erase();
+
+ device->DrawBitmapEx(Point(5, 5), BitmapEx(bitmap, alpha));
+ //savePNG("/tmp/a2.png", device);
+ Color resultRed(COL_RED.GetRed() * 3 / 4 + 64, 64, 64); // 3/4 red, 1/4 white
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(0, 0)));
+ CPPUNIT_ASSERT_EQUAL(resultRed, device->GetPixel(Point(5, 5)));
+ CPPUNIT_ASSERT_EQUAL(resultRed, device->GetPixel(Point(14, 14)));
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(15, 15)));
+ device->Erase();
+
+ basegfx::B2DHomMatrix matrix;
+ matrix.scale(10, 10);
+ matrix.rotate(M_PI / 4);
+ device->DrawTransformedBitmapEx(matrix, BitmapEx(bitmap, alpha));
+ //savePNG("/tmp/a3.png", device);
+ CPPUNIT_ASSERT_EQUAL(resultRed, device->GetPixel(Point(0, 1)));
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(1, 0)));
+ CPPUNIT_ASSERT_EQUAL(resultRed, device->GetPixel(Point(0, 10)));
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(10, 10)));
+ device->Erase();
+
+ // Test with scaling. Use everything 10x larger to reduce the impact of smoothscaling.
+ ScopedVclPtr<VirtualDevice> deviceLarge = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
+ deviceLarge->SetOutputSizePixel(Size(200, 200));
+ deviceLarge->SetBackground(Wallpaper(COL_WHITE));
+ deviceLarge->Erase();
+ Bitmap bitmapLarge(Size(100, 100), 24);
+ bitmapLarge.Erase(COL_RED);
+ SkiaSalBitmap* skiaBitmapLarge
+ = dynamic_cast<SkiaSalBitmap*>(bitmapLarge.ImplGetSalBitmap().get());
+ CPPUNIT_ASSERT(skiaBitmapLarge);
+ CPPUNIT_ASSERT(skiaBitmapLarge->PreferSkShader());
+ AlphaMask alphaLarge(Size(100, 100));
+ alphaLarge.Erase(64);
+ {
+ BitmapWriteAccess access(bitmapLarge);
+ access.SetFillColor(COL_BLUE);
+ access.FillRect(tools::Rectangle(Point(20, 40), Size(10, 10)));
+ }
+ // Using alpha will still lead to shaders being used.
+ deviceLarge->DrawBitmapEx(Point(50, 50), Size(60, 60), Point(20, 20), Size(30, 30),
+ BitmapEx(bitmapLarge, alphaLarge));
+ //savePNG("/tmp/a4.png", deviceLarge);
+ Color resultBlue(64, 64, COL_BLUE.GetBlue() * 3 / 4 + 64); // 3/4 blue, 1/4 white
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, deviceLarge->GetPixel(Point(40, 40)));
+ CPPUNIT_ASSERT_EQUAL(resultRed, deviceLarge->GetPixel(Point(50, 50)));
+ CPPUNIT_ASSERT_EQUAL(resultRed, deviceLarge->GetPixel(Point(100, 100)));
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, deviceLarge->GetPixel(Point(110, 110)));
+ // Don't test colors near the edge between the colors, smoothscaling affects them.
+ const int diff = 3;
+ CPPUNIT_ASSERT_EQUAL(resultRed, deviceLarge->GetPixel(Point(50, 89 - diff)));
+ CPPUNIT_ASSERT_EQUAL(resultBlue, deviceLarge->GetPixel(Point(50, 90 + diff)));
+ CPPUNIT_ASSERT_EQUAL(resultBlue, deviceLarge->GetPixel(Point(69 - diff, 100)));
+ CPPUNIT_ASSERT_EQUAL(resultRed, deviceLarge->GetPixel(Point(70 + diff, 100)));
+ CPPUNIT_ASSERT_EQUAL(resultBlue, deviceLarge->GetPixel(Point(50, 100)));
+ device->Erase();
+}
+
} // namespace
CPPUNIT_TEST_SUITE_REGISTRATION(SkiaTest);
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index ade34a6e8b01..b6ffda221424 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1655,17 +1655,21 @@ void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp<SkSh
if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight)
paint.setFilterQuality(kHigh_SkFilterQuality);
SkCanvas* canvas = getDrawCanvas();
- // SkCanvas::drawShader() cannot do rectangles, so clip to destination and use a matrix
- // to map from source.
- SkMatrix matrix;
+ // Scaling needs to be done explicitly using a matrix.
SkAutoCanvasRestore autoRestore(canvas, true);
- canvas->clipRect(destinationRect);
- matrix.set(SkMatrix::kMScaleX, 1.0 * rPosAry.mnDestWidth / rPosAry.mnSrcWidth);
- matrix.set(SkMatrix::kMScaleY, 1.0 * rPosAry.mnDestHeight / rPosAry.mnSrcHeight);
- matrix.set(SkMatrix::kMTransX, rPosAry.mnDestX - rPosAry.mnSrcX);
- matrix.set(SkMatrix::kMTransY, rPosAry.mnDestY - rPosAry.mnSrcY);
+ SkMatrix matrix = SkMatrix::Translate(rPosAry.mnDestX, rPosAry.mnDestY)
+ * SkMatrix::Scale(1.0 * rPosAry.mnDestWidth / rPosAry.mnSrcWidth,
+ 1.0 * rPosAry.mnDestHeight / rPosAry.mnSrcHeight)
+ * SkMatrix::Translate(-rPosAry.mnSrcX, -rPosAry.mnSrcY);
+ assert(matrix.mapXY(rPosAry.mnSrcX, rPosAry.mnSrcY)
+ == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY));
+ assert(matrix.mapXY(rPosAry.mnSrcX + rPosAry.mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight)
+ == SkPoint::Make(rPosAry.mnDestX + rPosAry.mnDestWidth,
+ rPosAry.mnDestY + rPosAry.mnDestHeight));
canvas->concat(matrix);
- canvas->drawPaint(paint);
+ SkRect sourceRect
+ = SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
+ canvas->drawRect(sourceRect, paint);
postDraw();
}
@@ -1737,19 +1741,15 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
paint.setFilterQuality(kHigh_SkFilterQuality);
if (pSkiaAlphaBitmap)
{
- // SkCanvas::drawPaint() cannot do rectangles, so clip (is transformed by the matrix too).
- canvas->clipRect(SkRect::MakeWH(aSize.Width(), aSize.Height()));
paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha.
rSkiaBitmap.GetSkShader(),
pSkiaAlphaBitmap->GetAlphaSkShader()));
- canvas->drawPaint(paint);
+ canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint);
}
else if (rSkiaBitmap.PreferSkShader())
{
- // SkCanvas::drawPaint() cannot do rectangles, so clip (is transformed by the matrix too).
- canvas->clipRect(SkRect::MakeWH(aSize.Width(), aSize.Height()));
paint.setShader(rSkiaBitmap.GetSkShader());
- canvas->drawPaint(paint);
+ canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint);
}
else
{
More information about the Libreoffice-commits
mailing list