[Libreoffice-commits] core.git: vcl/qa vcl/source

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Wed Sep 30 09:39:20 UTC 2020


 vcl/qa/cppunit/BackendTest.cxx                   |   59 +++++++++++++++++++++++
 vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx |   38 +++++++-------
 vcl/source/outdev/bitmap.cxx                     |   47 ++++++++++++------
 3 files changed, 112 insertions(+), 32 deletions(-)

New commits:
commit 6b709ad5d46dc33f29ec28183cea40cf9e77e2af
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Tue Sep 29 09:42:14 2020 +0200
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Wed Sep 30 11:38:37 2020 +0200

    fix DrawDeviceAlphaBitmap() with mirroring (tdf#136223)
    
    It turns out even the slow path was broken, so make it work (a hack,
    but it's already slow anyway, and apparently not used often).
    Also make the fast paths work directly, even with manual mirroring
    it should be still faster.
    
    Change-Id: Id798351f349e9906e85c1685f269df98a1b833b4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103595
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx
index cb2dca9cfe91..1342c3a5ade9 100644
--- a/vcl/qa/cppunit/BackendTest.cxx
+++ b/vcl/qa/cppunit/BackendTest.cxx
@@ -711,6 +711,64 @@ public:
         CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(6, 6)));
     }
 
+    void testDrawAlphaBitmapMirrored()
+    {
+        // Normal virtual device.
+        ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
+        // Virtual device with alpha.
+        ScopedVclPtr<VirtualDevice> alphaDevice
+            = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+        device->SetOutputSizePixel(Size(20, 20));
+        device->SetBackground(Wallpaper(COL_BLACK));
+        device->Erase();
+        alphaDevice->SetOutputSizePixel(Size(20, 20));
+        alphaDevice->SetBackground(Wallpaper(COL_BLACK));
+        alphaDevice->Erase();
+        Bitmap bitmap(Size(4, 4), 24);
+        AlphaMask alpha(Size(4, 4));
+        bitmap.Erase(COL_LIGHTBLUE);
+        {
+            BitmapScopedWriteAccess writeAccess(bitmap);
+            writeAccess->SetPixel(3, 3, COL_LIGHTRED);
+        }
+        // alpha 127 will make COL_LIGHTRED -> COL_RED and the same for blue
+        alpha.Erase(127);
+        // Normal device.
+        device->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap));
+        device->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap));
+        exportDevice("/tmp/draw_alpha_bitmap_mirrored_01.png", device);
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, device->GetPixel(Point(18, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, device->GetPixel(Point(17, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, device->GetPixel(Point(2, 2)));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, device->GetPixel(Point(3, 2)));
+        device->Erase();
+        device->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap, alpha));
+        device->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap, alpha));
+        exportDevice("/tmp/draw_alpha_bitmap_mirrored_02.png", device);
+        CPPUNIT_ASSERT_EQUAL(COL_RED, device->GetPixel(Point(18, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(17, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_RED, device->GetPixel(Point(2, 2)));
+        CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(3, 2)));
+        device->Erase();
+        // Now with alpha device.
+        alphaDevice->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap));
+        alphaDevice->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap));
+        exportDevice("/tmp/draw_alpha_bitmap_mirrored_03.png", alphaDevice);
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, alphaDevice->GetPixel(Point(18, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, alphaDevice->GetPixel(Point(17, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, alphaDevice->GetPixel(Point(2, 2)));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, alphaDevice->GetPixel(Point(3, 2)));
+        alphaDevice->Erase();
+        alphaDevice->DrawBitmapEx(Point(5, 5), Size(-4, -4), BitmapEx(bitmap, alpha));
+        alphaDevice->DrawBitmapEx(Point(15, 15), Size(4, 4), BitmapEx(bitmap, alpha));
+        exportDevice("/tmp/draw_alpha_bitmap_mirrored_04.png", alphaDevice);
+        CPPUNIT_ASSERT_EQUAL(COL_RED, alphaDevice->GetPixel(Point(18, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_BLUE, alphaDevice->GetPixel(Point(17, 18)));
+        CPPUNIT_ASSERT_EQUAL(COL_RED, alphaDevice->GetPixel(Point(2, 2)));
+        CPPUNIT_ASSERT_EQUAL(COL_BLUE, alphaDevice->GetPixel(Point(3, 2)));
+        alphaDevice->Erase();
+    }
+
     void testTdf124848()
     {
         ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT);
@@ -832,6 +890,7 @@ public:
     CPPUNIT_TEST(testRadialGradientOfs);
 
     CPPUNIT_TEST(testDrawBlendExtended);
+    CPPUNIT_TEST(testDrawAlphaBitmapMirrored);
 
     CPPUNIT_TEST(testTdf124848);
     CPPUNIT_TEST(testTdf136171);
diff --git a/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx
index d13696571a9e..b6bd724910b8 100644
--- a/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx
+++ b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx
@@ -101,6 +101,22 @@ void BitmapRenderTest::testTdf113918()
     CPPUNIT_ASSERT(aColor.GetGreen() > 100);
 }
 
+#if defined(_WIN32) || defined(MACOSX) || defined(IOS)
+
+namespace
+{
+int deltaColor(BitmapColor aColor1, BitmapColor aColor2)
+{
+    int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed());
+    int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen());
+    int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue());
+
+    return std::max(std::max(deltaR, deltaG), deltaB);
+}
+}
+
+#endif
+
 void BitmapRenderTest::testDrawAlphaBitmapEx()
 {
     ScopedVclPtrInstance<VirtualDevice> pVDev;
@@ -141,28 +157,14 @@ void BitmapRenderTest::testDrawAlphaBitmapEx()
     CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0xFF), pVDev->GetPixel(Point(0, 0)));
     CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0x00), pVDev->GetPixel(Point(1, 1)));
 
-// sometimes on Windows we get rounding error in blending so let's ignore this on Windows for now.
-#if !defined(_WIN32)
+#if defined(_WIN32) || defined(MACOSX) || defined(IOS)
+    // sometimes on Windows we get rounding error in blending so let's ignore this on Windows for now.
+    CPPUNIT_ASSERT_LESS(2, deltaColor(Color(0x00, 0x7F, 0xFF, 0x7F), pVDev->GetPixel(Point(2, 2))));
+#else
     CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x7F, 0xFF, 0x7F), pVDev->GetPixel(Point(2, 2)));
 #endif
 }
 
-#ifdef _WIN32
-
-namespace
-{
-int deltaColor(BitmapColor aColor1, BitmapColor aColor2)
-{
-    int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed());
-    int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen());
-    int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue());
-
-    return std::max(std::max(deltaR, deltaG), deltaB);
-}
-}
-
-#endif
-
 void BitmapRenderTest::testAlphaVirtualDevice()
 {
     // Create an alpha virtual device
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index a9f264fa2854..bcab1a4d7793 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -632,23 +632,34 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
 
     ClipToPaintRegion(aDstRect);
 
+    BmpMirrorFlags mirrorFlags = BmpMirrorFlags::NONE;
     if (bHMirr)
     {
         aOutSz.setWidth( -aOutSz.Width() );
         aOutPt.AdjustX( -(aOutSz.Width() - 1) );
+        mirrorFlags |= BmpMirrorFlags::Horizontal;
     }
 
     if (bVMirr)
     {
         aOutSz.setHeight( -aOutSz.Height() );
         aOutPt.AdjustY( -(aOutSz.Height() - 1) );
+        mirrorFlags |= BmpMirrorFlags::Vertical;
     }
 
     if (aDstRect.Intersection(tools::Rectangle(aOutPt, aOutSz)).IsEmpty())
         return;
 
+    bool bTryDirectPaint = false;
+    if(SkiaHelper::isVCLSkiaEnabled())
+        bTryDirectPaint = true;
+#if HAVE_FEATURE_OPENGL
+    if(OpenGLHelper::isVCLOpenGLEnabled())
+        bTryDirectPaint = true;
+#endif
     static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
-    bool bTryDirectPaint(!pDisableNative && !bHMirr && !bVMirr);
+    if(pDisableNative)
+        bTryDirectPaint = false;
 
     if (bTryDirectPaint)
     {
@@ -659,8 +670,15 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
             aRelPt.X(), aRelPt.Y(),
             aOutSz.Width(), aOutSz.Height());
 
-        SalBitmap* pSalSrcBmp = rBmp.ImplGetSalBitmap().get();
-        SalBitmap* pSalAlphaBmp = rAlpha.ImplGetSalBitmap().get();
+        Bitmap bitmap(rBmp);
+        AlphaMask alpha(rAlpha);
+        if(bHMirr || bVMirr)
+        {
+            bitmap.Mirror(mirrorFlags);
+            alpha.Mirror(mirrorFlags);
+        }
+        SalBitmap* pSalSrcBmp = bitmap.ImplGetSalBitmap().get();
+        SalBitmap* pSalAlphaBmp = alpha.ImplGetSalBitmap().get();
 
         // #i83087# Naturally, system alpha blending (SalGraphics::DrawAlphaBitmap) cannot work
         // with separate alpha VDev
@@ -683,25 +701,26 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r
             if (mpGraphics->DrawAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, this))
                 return;
         }
+        assert(false);
     }
 
-    // we need to make sure OpenGL never reaches this slow code path
-    // tdf#136223: The slow code path will be obviously also reached if mirroring
-    // is used, which makes the block above be skipped, as the blend bitmap calls
-    // do not handle that case. Given that this seems to be rather rare, just
-    // disable the assert, until faster mirroring is actually needed.
-
-    assert(!SkiaHelper::isVCLSkiaEnabled() || !bTryDirectPaint);
-#if HAVE_FEATURE_OPENGL
-    assert(!OpenGLHelper::isVCLOpenGLEnabled() || !bTryDirectPaint);
-#endif
     tools::Rectangle aBmpRect(Point(), rBmp.GetSizePixel());
     if (!aBmpRect.Intersection(tools::Rectangle(rSrcPtPixel, rSrcSizePixel)).IsEmpty())
     {
         Point     auxOutPt(LogicToPixel(rDestPt));
         Size      auxOutSz(LogicToPixel(rDestSize));
 
-        DrawDeviceAlphaBitmapSlowPath(rBmp, rAlpha, aDstRect, aBmpRect, auxOutSz, auxOutPt);
+        // HACK: The function is broken with alpha vdev and mirroring, mirror here.
+        Bitmap bitmap(rBmp);
+        AlphaMask alpha(rAlpha);
+        if(mpAlphaVDev && (bHMirr || bVMirr))
+        {
+            bitmap.Mirror(mirrorFlags);
+            alpha.Mirror(mirrorFlags);
+            auxOutPt = aOutPt;
+            auxOutSz = aOutSz;
+        }
+        DrawDeviceAlphaBitmapSlowPath(bitmap, alpha, aDstRect, aBmpRect, auxOutSz, auxOutPt);
     }
 }
 


More information about the Libreoffice-commits mailing list