[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.3' - vcl/headless vcl/inc vcl/qa

Ashod Nakashian ashod.nakashian at collabora.co.uk
Mon Dec 18 10:02:24 UTC 2017


 vcl/headless/svpbmp.cxx       |    5 +-
 vcl/headless/svpgdi.cxx       |   98 ++++++++++++++++++++++++++++++++++++++++--
 vcl/inc/headless/svpgdi.hxx   |    3 +
 vcl/qa/cppunit/BitmapTest.cxx |   22 ++-------
 4 files changed, 105 insertions(+), 23 deletions(-)

New commits:
commit 11adb51f2553dc4a838c8668d94909771d70e1ab
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Sun Dec 3 23:35:26 2017 -0500

    vcl-svp: Store 24-bit images in 3-byte pixels
    
    This adds support in headless rendering for more
    compact 24-bit RGB image storage in 3-byte pixels
    instead of 4 bytes.
    
    There is a conversion necessary to accomodate Cairo,
    which requires 4-byte pixels, but that is relatively.
    
    Early tests show no loss of performance at runtime.
    
    Change-Id: I3919f7c56d14d09e67f163f035b4c7683b49087c
    (cherry picked from commit 354ad875092fd0c3b12f232950375206ec5d66a6)
    Reviewed-on: https://gerrit.libreoffice.org/46679
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>

diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx
index c3ba02f57528..63d0ee047046 100644
--- a/vcl/headless/svpbmp.cxx
+++ b/vcl/headless/svpbmp.cxx
@@ -96,14 +96,15 @@ BitmapBuffer* ImplCreateDIB(
             pDIB->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
             break;
         }
+        case 24:
+            pDIB->mnFormat = SVP_24BIT_FORMAT;
+            break;
         default:
             nBitCount = 32;
             SAL_FALLTHROUGH;
         case 32:
-        {
             pDIB->mnFormat = SVP_CAIRO_FORMAT;
             break;
-        }
     }
 
     pDIB->mnFormat |= ScanlineFormat::TopDown;
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 8f09939df899..cd546ab5fdb1 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -23,6 +23,7 @@
 #include "headless/svpcairotextrender.hxx"
 #include "saldatabasic.hxx"
 
+#include <o3tl/safeint.hxx>
 #include <vcl/sysdata.hxx>
 #include <config_cairo_canvas.h>
 #include <basegfx/numeric/ftools.hxx>
@@ -123,25 +124,113 @@ namespace
         }
     }
 
+    BitmapBuffer* FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* pSrc)
+    {
+        if (pSrc == nullptr)
+            return nullptr;
+
+        assert(pSrc->mnFormat == SVP_24BIT_FORMAT);
+        const long nWidth = pSrc->mnWidth;
+        const long nHeight = pSrc->mnHeight;
+        BitmapBuffer* pDst = new BitmapBuffer;
+        pDst->mnFormat = (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown);
+        pDst->mnWidth = nWidth;
+        pDst->mnHeight = nHeight;
+        pDst->mnBitCount = 32;
+        pDst->maColorMask = pSrc->maColorMask;
+        pDst->maPalette = pSrc->maPalette;
+
+        long nScanlineBase;
+        bool bFail = o3tl::checked_multiply<long>(pDst->mnBitCount, nWidth, nScanlineBase);
+        if (bFail)
+        {
+            SAL_WARN("vcl.gdi", "checked multiply failed");
+            pDst->mpBits = nullptr;
+            delete pDst;
+            return nullptr;
+        }
+
+        pDst->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase);
+        if (pDst->mnScanlineSize < nScanlineBase/8)
+        {
+            SAL_WARN("vcl.gdi", "scanline calculation wraparound");
+            pDst->mpBits = nullptr;
+            delete pDst;
+            return nullptr;
+        }
+
+        try
+        {
+            pDst->mpBits = new sal_uInt8[ pDst->mnScanlineSize * nHeight ];
+        }
+        catch( const std::bad_alloc& )
+        {
+            // memory exception, clean up
+            pDst->mpBits = nullptr;
+            delete pDst;
+            return nullptr;
+        }
+
+        for (int y = 0; y < nHeight; ++y)
+        {
+            sal_uInt8* pS = pSrc->mpBits + y * pSrc->mnScanlineSize;
+            sal_uInt8* pD = pDst->mpBits + y * pDst->mnScanlineSize;
+            for (int x = 0; x < nWidth; ++x)
+            {
+                if ((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcRgba)
+                {
+                    pD[0] = pS[0];
+                    pD[1] = pS[1];
+                    pD[2] = pS[2];
+                    pD[3] = 0xff; // Alpha
+                }
+                else if ((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcArgb)
+                {
+                    pD[0] = 0xff; // Alpha
+                    pD[1] = pS[0];
+                    pD[2] = pS[1];
+                    pD[3] = pS[2];
+                }
+                else if ((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcBgra)
+                {
+                    pD[0] = pS[2];
+                    pD[1] = pS[1];
+                    pD[2] = pS[0];
+                    pD[3] = 0xff; // Alpha
+                }
+                else
+                {
+                    assert(!"Unsupported SVP_CAIRO_FORMAT!");
+                }
+
+                pS += 3;
+                pD += 4;
+            }
+        }
+
+        return pDst;
+    }
+
     class SourceHelper
     {
     public:
         explicit SourceHelper(const SalBitmap& rSourceBitmap)
         {
             const SvpSalBitmap& rSrcBmp = static_cast<const SvpSalBitmap&>(rSourceBitmap);
-
             if (rSrcBmp.GetBitCount() != 32)
             {
                 //big stupid copy here
-                static bool bWarnedOnce;
+                static bool bWarnedOnce = false;
                 SAL_WARN_IF(!bWarnedOnce, "vcl.gdi", "non default depth bitmap, slow convert, upscale the input");
                 bWarnedOnce = true;
 
                 const BitmapBuffer* pSrc = rSrcBmp.GetBuffer();
                 const SalTwoRect aTwoRect = { 0, 0, pSrc->mnWidth, pSrc->mnHeight,
                                               0, 0, pSrc->mnWidth, pSrc->mnHeight };
-                aTmpBmp.Create(StretchAndConvert(*pSrc, aTwoRect, SVP_CAIRO_FORMAT));
-
+                BitmapBuffer* pTmp = (pSrc->mnFormat == SVP_24BIT_FORMAT
+                                   ? FastConvert24BitRgbTo32BitCairo(pSrc)
+                                   : StretchAndConvert(*pSrc, aTwoRect, SVP_CAIRO_FORMAT));
+                aTmpBmp.Create(pTmp);
 
                 assert(aTmpBmp.GetBitCount() == 32);
                 source = SvpSalGraphics::createCairoSurface(aTmpBmp.GetBuffer());
@@ -1350,6 +1439,7 @@ namespace
         if (!pBuffer)
             return false;
 
+        // Cairo doesn't support 24-bit RGB; only ARGB with the alpha ignored.
         if (pBuffer->mnBitCount != 32 && pBuffer->mnBitCount != 1)
             return false;
 
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 488cb51868e0..f092b0375822 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -58,6 +58,9 @@
 #   define SVP_CAIRO_ALPHA 3
 #endif
 
+// Used to store 24-bit images in 3-byte pixels to conserve memory.
+#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
+
 struct BitmapBuffer;
 class GlyphCache;
 class FreetypeFont;
diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx
index fe76f51e5232..3cdea8fdd928 100644
--- a/vcl/qa/cppunit/BitmapTest.cxx
+++ b/vcl/qa/cppunit/BitmapTest.cxx
@@ -75,24 +75,12 @@ void BitmapTest::testConvert()
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmap.GetBitCount());
     {
         Bitmap::ScopedReadAccess pReadAccess(aBitmap);
-#if defined LINUX || defined FREEBSD
-        // 24 bit Bitmap on SVP backend uses 32bit BGRA format
-        CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(32), pReadAccess->GetBitCount());
-        CPPUNIT_ASSERT_EQUAL(sal_uLong(40), pReadAccess->GetScanlineSize());
-#else
+        // 24 bit Bitmap on SVP backend can now use 24bit RGB instad of  32bit BGRA format.
         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), pReadAccess->GetBitCount());
-#if defined(_WIN32)
-        if (!OpenGLHelper::isVCLOpenGLEnabled())
-        {
-            // GDI Scanlines padded to DWORD multiples, it seems
-            CPPUNIT_ASSERT_EQUAL(sal_uLong(32), pReadAccess->GetScanlineSize());
-        }
-        else
-#endif
-        {
-            CPPUNIT_ASSERT_EQUAL(sal_uLong(30), pReadAccess->GetScanlineSize());
-        }
-#endif
+
+        // Scanlines padded to DWORD multiples, it seems
+        CPPUNIT_ASSERT_EQUAL(sal_uLong(32), pReadAccess->GetScanlineSize());
+
         CPPUNIT_ASSERT(!pReadAccess->HasPalette());
         Color aColor = pReadAccess->GetPixel(0, 0);
         CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetRed()));


More information about the Libreoffice-commits mailing list