summaryrefslogtreecommitdiff
path: root/vcl/skia/salbmp.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/skia/salbmp.cxx')
-rw-r--r--vcl/skia/salbmp.cxx153
1 files changed, 109 insertions, 44 deletions
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index a4d183c50515..9eba386e6b95 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -26,21 +26,23 @@
#include <SkCanvas.h>
#include <SkImage.h>
+#include <SkPixelRef.h>
#ifdef DBG_UTIL
#include <fstream>
+#define CANARY "skia-canary"
#endif
SkiaSalBitmap::SkiaSalBitmap() {}
SkiaSalBitmap::~SkiaSalBitmap() {}
-static SkColorType getSkColorType(int bitCount, const BitmapPalette& palette)
+static SkColorType getSkColorType(int bitCount)
{
switch (bitCount)
{
case 8:
- return palette.IsGreyPalette() ? kGray_8_SkColorType : kAlpha_8_SkColorType;
+ return kGray_8_SkColorType; // see GetAlphaSkBitmap()
case 16:
return kRGB_565_SkColorType;
case 24:
@@ -74,18 +76,18 @@ bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const Bitmap
Destroy();
if (!isValidBitCount(nBitCount))
return false;
- if (nBitCount >= 8)
+ // Skia does not support paletted images, so convert only types Skia supports.
+ if (nBitCount > 8 || (nBitCount == 8 && (!rPal || rPal.IsGreyPalette())))
{
- if (!mBitmap.tryAllocPixels(
- SkImageInfo::Make(rSize.Width(), rSize.Height(), getSkColorType(nBitCount, rPal),
- nBitCount == 32 ? kPremul_SkAlphaType : kOpaque_SkAlphaType)))
+ if (!mBitmap.tryAllocPixels(SkImageInfo::Make(
+ rSize.Width(), rSize.Height(), getSkColorType(nBitCount), kPremul_SkAlphaType)))
{
return false;
}
}
else
{
- // Skia doesn't support the (ancient) low bpp bit counts, so handle them manually
+ // Paletted images are stored in a buffer and converted as necessary.
int bitScanlineWidth;
if (o3tl::checked_multiply<int>(rSize.Width(), nBitCount, bitScanlineWidth))
{
@@ -95,7 +97,16 @@ bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const Bitmap
mScanlineSize = AlignedWidth4Bytes(bitScanlineWidth);
sal_uInt8* buffer = nullptr;
if (mScanlineSize != 0 && rSize.Height() != 0)
- buffer = new sal_uInt8[mScanlineSize * rSize.Height()];
+ {
+ size_t allocate = mScanlineSize * rSize.Height();
+#ifdef DBG_UTIL
+ allocate += sizeof(CANARY);
+#endif
+ buffer = new sal_uInt8[allocate];
+#if OSL_DEBUG_LEVEL > 0
+ memcpy(buffer + allocate - sizeof(CANARY), CANARY, sizeof(CANARY));
+#endif
+ }
mBuffer.reset(buffer);
}
mPalette = rPal;
@@ -125,9 +136,13 @@ bool SkiaSalBitmap::Create(const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount)
mSize = src.mSize;
if (mBuffer != nullptr)
{
- sal_uInt32 dataSize = src.mScanlineSize * src.mSize.Height();
- sal_uInt8* newBuffer = new sal_uInt8[dataSize];
- memcpy(newBuffer, src.mBuffer.get(), dataSize);
+ sal_uInt32 allocate = src.mScanlineSize * src.mSize.Height();
+#ifdef DBG_UTIL
+ assert(memcmp(src.mBuffer.get() + allocate, CANARY, sizeof(CANARY)) == 0);
+ allocate += sizeof(CANARY);
+#endif
+ sal_uInt8* newBuffer = new sal_uInt8[allocate];
+ memcpy(newBuffer, src.mBuffer.get(), allocate);
mBuffer.reset(newBuffer);
mScanlineSize = src.mScanlineSize;
}
@@ -169,69 +184,70 @@ BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
buffer->mnHeight = mSize.Height();
buffer->mnBitCount = mBitCount;
buffer->maPalette = mPalette;
- if (mBitCount >= 8)
+ if (mBuffer)
{
- buffer->mpBits = static_cast<sal_uInt8*>(mBitmap.getPixels());
- buffer->mnScanlineSize = mBitmap.rowBytes();
+ buffer->mpBits = mBuffer.get();
+ buffer->mnScanlineSize = mScanlineSize;
}
else
{
- buffer->mpBits = mBuffer.get();
- buffer->mnScanlineSize = mScanlineSize;
+ buffer->mpBits = static_cast<sal_uInt8*>(mBitmap.getPixels());
+ buffer->mnScanlineSize = mBitmap.rowBytes();
}
switch (mBitCount)
{
case 1:
-#ifdef OSL_BIGENDIAN
- buffer->mnFormat = ScanlineFormat::N1BitMsbPal | ScanlineFormat::TopDown;
-#else
- buffer->mnFormat = ScanlineFormat::N1BitLsbPal | ScanlineFormat::TopDown;
-#endif
+ buffer->mnFormat = ScanlineFormat::N1BitMsbPal;
break;
case 4:
-#ifdef OSL_BIGENDIAN
- buffer->mnFormat = ScanlineFormat::N4BitMsnPal | ScanlineFormat::TopDown;
-#else
- buffer->mnFormat = ScanlineFormat::N4BitLsnPal | ScanlineFormat::TopDown;
-#endif
+ buffer->mnFormat = ScanlineFormat::N4BitMsnPal;
break;
case 8:
- buffer->mnFormat = ScanlineFormat::N8BitPal | ScanlineFormat::TopDown;
+ // TODO or always N8BitPal?
+ // buffer->mnFormat = !mPalette ? ScanlineFormat::N8BitTcMask : ScanlineFormat::N8BitPal;
+ buffer->mnFormat = ScanlineFormat::N8BitPal;
break;
case 16:
-#ifdef OSL_BIGENDIAN
- buffer->mnFormat = ScanlineFormat::N16BitTcMsbMask | ScanlineFormat::TopDown;
-#else
- buffer->mnFormat = ScanlineFormat::N16BitTcLsbMask | ScanlineFormat::TopDown;
-#endif
- // TODO maColorMask?
+ {
+ buffer->mnFormat = ScanlineFormat::N16BitTcMsbMask;
+ ColorMaskElement aRedMask(0x0000f800);
+ aRedMask.CalcMaskShift();
+ ColorMaskElement aGreenMask(0x000007e0);
+ aGreenMask.CalcMaskShift();
+ ColorMaskElement aBlueMask(0x0000001f);
+ aBlueMask.CalcMaskShift();
+ buffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
break;
+ }
case 24:
- buffer->mnFormat = ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown;
+ buffer->mnFormat = ScanlineFormat::N24BitTcRgb;
break;
case 32:
// TODO are these correct?
buffer->mnFormat = mBitmap.colorType() == kRGBA_8888_SkColorType
- ? ScanlineFormat::N32BitTcBgra
- : ScanlineFormat::N32BitTcArgb;
- buffer->mnFormat |= ScanlineFormat::TopDown;
+ ? ScanlineFormat::N32BitTcRgba
+ : ScanlineFormat::N32BitTcBgra;
break;
default:
abort();
}
+ buffer->mnFormat |= ScanlineFormat::TopDown;
return buffer;
}
void SkiaSalBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode)
{
- mPalette = pBuffer->maPalette;
+ if (nMode == BitmapAccessMode::Write) // TODO something more?
+ {
+ mPalette = pBuffer->maPalette;
+ ResetCachedBitmap();
+ }
// Are there any more ground movements underneath us ?
assert(pBuffer->mnWidth == mSize.Width());
assert(pBuffer->mnHeight == mSize.Height());
assert(pBuffer->mnBitCount == mBitCount);
+ verify();
delete pBuffer;
- if (nMode == BitmapAccessMode::Write) // TODO something more?
- ResetCachedBitmap();
}
bool SkiaSalBitmap::GetSystemData(BitmapSystemData& rData)
@@ -264,10 +280,10 @@ const SkBitmap& SkiaSalBitmap::GetSkBitmap() const
{
if (mBuffer && mBitmap.drawsNothing())
{
- assert(mBitCount == 1 || mBitCount == 2 || mBitCount == 4);
- std::unique_ptr<sal_uInt8[]> data = convertDataTo32Bpp(
+ std::unique_ptr<sal_uInt8[]> data = convertDataBitCount(
mBuffer.get(), mSize.Width(), mSize.Height(), mBitCount, mScanlineSize, mPalette,
- kN32_SkColorType == kBGRA_8888_SkColorType); // TODO
+ kN32_SkColorType == kBGRA_8888_SkColorType ? BitConvert::BGRA
+ : BitConvert::RGBA); // TODO
if (!const_cast<SkBitmap&>(mBitmap).installPixels(
SkImageInfo::MakeS32(mSize.Width(), mSize.Height(), kOpaque_SkAlphaType),
data.release(), mSize.Width() * 4,
@@ -277,9 +293,49 @@ const SkBitmap& SkiaSalBitmap::GetSkBitmap() const
return mBitmap;
}
-// Reset the cached bitmap allocatd in GetSkBitmap().
+const SkBitmap& SkiaSalBitmap::GetAlphaSkBitmap() const
+{
+ assert(mBitCount <= 8);
+ if (mAlphaBitmap.drawsNothing())
+ {
+ if (mBuffer)
+ {
+ assert(mBuffer.get());
+ verify();
+ std::unique_ptr<sal_uInt8[]> data
+ = convertDataBitCount(mBuffer.get(), mSize.Width(), mSize.Height(), mBitCount,
+ mScanlineSize, mPalette, BitConvert::A8);
+ if (!const_cast<SkBitmap&>(mAlphaBitmap)
+ .installPixels(
+ SkImageInfo::MakeA8(mSize.Width(), mSize.Height()), data.release(),
+ mSize.Width(),
+ [](void* addr, void*) { delete[] static_cast<sal_uInt8*>(addr); },
+ nullptr))
+ abort();
+ }
+ else
+ {
+ assert(mBitmap.colorType() == kGray_8_SkColorType);
+ // Skia uses a bitmap as an alpha channel only if it's set as kAlpha_8_SkColorType.
+ // But in SalBitmap::Create() it's not quite clear if the 8-bit image will be used
+ // as a mask or as a real bitmap. So mBitmap is always kGray_8_SkColorType
+ // and mAlphaBitmap is kAlpha_8_SkColorType that can be used as a mask.
+ // Make mAlphaBitmap share mBitmap's data.
+ const_cast<SkBitmap&>(mAlphaBitmap)
+ .setInfo(mBitmap.info().makeColorType(kAlpha_8_SkColorType), mBitmap.rowBytes());
+ const_cast<SkBitmap&>(mAlphaBitmap)
+ .setPixelRef(sk_ref_sp(mBitmap.pixelRef()), mBitmap.pixelRefOrigin().x(),
+ mBitmap.pixelRefOrigin().y());
+ return mAlphaBitmap;
+ }
+ }
+ return mAlphaBitmap;
+}
+
+// Reset the cached bitmap allocated in GetSkBitmap().
void SkiaSalBitmap::ResetCachedBitmap()
{
+ mAlphaBitmap.reset();
if (mBuffer)
mBitmap.reset();
}
@@ -292,6 +348,15 @@ void SkiaSalBitmap::dump(const char* file) const
std::ofstream ostream(file, std::ios::binary);
ostream.write(static_cast<const char*>(data->data()), data->size());
}
+
+void SkiaSalBitmap::verify() const
+{
+ if (!mBuffer)
+ return;
+ size_t canary = mScanlineSize * mSize.Height();
+ assert(memcmp(mBuffer.get() + canary, CANARY, sizeof(CANARY)) == 0);
+}
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */