summaryrefslogtreecommitdiff
path: root/vcl/headless
diff options
context:
space:
mode:
authorAshod Nakashian <ashod.nakashian@collabora.co.uk>2017-12-03 23:35:26 -0500
committerAshod Nakashian <ashnakash@gmail.com>2017-12-26 21:48:22 +0100
commit33761c69e9d3fa16e7a5b176200d183dc3236627 (patch)
tree17712283c453b34a593ffb9040c338bb98348e23 /vcl/headless
parent6723728ae206cfbe68c18475bbdc18072d24e620 (diff)
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. Unit tests updated since the bitmap memory bytes are crc-ed, which obviously are different in size if not in content. (cherry picked from commit 354ad875092fd0c3b12f232950375206ec5d66a6) Reviewed-on: https://gerrit.libreoffice.org/46679 Reviewed-by: Jan Holesovsky <kendy@collabora.com> Tested-by: Jan Holesovsky <kendy@collabora.com> (cherry picked from commit 11adb51f2553dc4a838c8668d94909771d70e1ab) Change-Id: I3919f7c56d14d09e67f163f035b4c7683b49087c Reviewed-on: https://gerrit.libreoffice.org/47009 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Diffstat (limited to 'vcl/headless')
-rw-r--r--vcl/headless/svpbmp.cxx5
-rw-r--r--vcl/headless/svpgdi.cxx95
2 files changed, 94 insertions, 6 deletions
diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx
index cb7a8654798a..0ba815998d8f 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 bcb0e46e8bec..6a5409e7f2e9 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -24,6 +24,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>
@@ -124,25 +125,110 @@ 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;
+ const 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 (long y = 0; y < nHeight; ++y)
+ {
+ sal_uInt8* pS = pSrc->mpBits + y * pSrc->mnScanlineSize;
+ sal_uInt8* pD = pDst->mpBits + y * pDst->mnScanlineSize;
+ for (long x = 0; x < nWidth; ++x)
+ {
+#if defined ANDROID
+ static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcRgba, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra");
+ static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb");
+ pD[0] = pS[0];
+ pD[1] = pS[1];
+ pD[2] = pS[2];
+ pD[3] = 0xff; // Alpha
+#elif defined OSL_BIGENDIAN
+ static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcArgb, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra");
+ static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb");
+ pD[0] = 0xff; // Alpha
+ pD[1] = pS[0];
+ pD[2] = pS[1];
+ pD[3] = pS[2];
+#else
+ static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcBgra, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra");
+ static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcBgr, "Expected SVP_24BIT_FORMAT set to N24BitTcBgr");
+ pD[0] = pS[0];
+ pD[1] = pS[1];
+ pD[2] = pS[2];
+ pD[3] = 0xff; // Alpha
+#endif
+
+ 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());
@@ -1351,6 +1437,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;