summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
authorNoel Grandin <noelgrandin@gmail.com>2025-01-22 20:12:41 +0200
committerNoel Grandin <noelgrandin@gmail.com>2025-01-23 08:28:14 +0100
commit18df81e1568f4944a8fd79fd81e85d263dc0325b (patch)
tree78b09ab5085257cc33f6f99605f6369271ef9b75 /vcl/source
parente4271c596d33b2e864e86517a15694967f05fa33 (diff)
Revert "ScanlineDirection is unnecessary"
This reverts commit a525438eb62f59801899c5ea45e451963b2ec248 Author: Noel Grandin <noelgrandin@collabora.co.uk> Date: Wed Jan 22 09:50:43 2025 +0200 fix GDI and Quartz backends and commit 828a0dcdf6fd1600baaf3103583633006a90d9f9 Author: Noel Grandin <noel.grandin@collabora.co.uk> Date: Thu Jan 16 08:23:19 2025 +0200 ScanlineDirection is unnecessary because macOS uses bottom-up coordinate system, and I could not find a way to make the bitmaps stored top-down. Change-Id: Idc05b7473eca5fae0e33d634117de810146da3b5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180603 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/bitmap/bmpfast.cxx36
-rw-r--r--vcl/source/bitmap/dibtools.cxx111
-rw-r--r--vcl/source/bitmap/salbmp.cxx16
-rw-r--r--vcl/source/filter/webp/reader.cxx16
-rw-r--r--vcl/source/filter/webp/writer.cxx2
-rw-r--r--vcl/source/gdi/salmisc.cxx27
-rw-r--r--vcl/source/helper/canvasbitmap.cxx5
-rw-r--r--vcl/source/opengl/OpenGLHelper.cxx4
8 files changed, 167 insertions, 50 deletions
diff --git a/vcl/source/bitmap/bmpfast.cxx b/vcl/source/bitmap/bmpfast.cxx
index bae0ed1f5b3f..74da808b96cb 100644
--- a/vcl/source/bitmap/bmpfast.cxx
+++ b/vcl/source/bitmap/bmpfast.cxx
@@ -268,7 +268,13 @@ static bool ImplCopyImage( BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuf
const PIXBYTE* pRawSrc = rSrcBuffer.mpBits;
PIXBYTE* pRawDst = rDstBuffer.mpBits;
- if( nSrcLinestep == nDstLinestep )
+ // source and destination don't match upside down
+ if (rSrcBuffer.meDirection != rDstBuffer.meDirection)
+ {
+ pRawDst += (rSrcBuffer.mnHeight - 1) * nDstLinestep;
+ nDstLinestep = -rDstBuffer.mnScanlineSize;
+ }
+ else if( nSrcLinestep == nDstLinestep )
{
memcpy( pRawDst, pRawSrc, rSrcBuffer.mnHeight * nDstLinestep );
return true;
@@ -302,6 +308,13 @@ static bool ImplConvertToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
TrueColorPixelPtr<DSTFMT> aDstLine; aDstLine.SetRawPtr( rDstBuffer.mpBits );
+ // source and destination don't match upside down
+ if (rSrcBuffer.meDirection != rDstBuffer.meDirection)
+ {
+ aDstLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nDstLinestep );
+ nDstLinestep = -nDstLinestep;
+ }
+
for( int y = rSrcBuffer.mnHeight; --y >= 0; )
{
ImplConvertLine( aDstLine, rSrcLine, rSrcBuffer.mnWidth );
@@ -366,6 +379,7 @@ bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc,
return false;
// vertical mirroring
if( rTR.mnDestHeight < 0 )
+ // TODO: rDst.meDirection != ScanlineDirection::TopDown;
return false;
// offsetted conversion is not implemented yet
@@ -449,7 +463,10 @@ bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc,
static inline ConstScanline ImplGetScanline( const BitmapBuffer& rBuf, tools::Long nY )
{
- return rBuf.mpBits + nY * rBuf.mnScanlineSize;
+ if (rBuf.meDirection == ScanlineDirection::TopDown)
+ return rBuf.mpBits + nY * rBuf.mnScanlineSize;
+ else
+ return rBuf.mpBits + (rBuf.mnHeight - 1 - nY) * rBuf.mnScanlineSize;
}
static inline Scanline ImplGetScanline( BitmapBuffer& rBuf, tools::Long nY )
@@ -567,6 +584,20 @@ static bool ImplBlendToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
if( rMskBuffer.mnHeight == 1 )
nMskLinestep = 0;
+ // source and mask don't match: upside down
+ if (rSrcBuffer.meDirection != rMskBuffer.meDirection)
+ {
+ aMskLine.AddByteOffset( (rSrcBuffer.mnHeight - 1) * nMskLinestep );
+ nMskLinestep = -nMskLinestep;
+ }
+
+ // source and destination don't match: upside down
+ if (rSrcBuffer.meDirection != rDstBuffer.meDirection)
+ {
+ aDstLine.AddByteOffset( (rDstBuffer.mnHeight - 1) * nDstLinestep );
+ nDstLinestep = -nDstLinestep;
+ }
+
assert(rDstBuffer.mnHeight <= rSrcBuffer.mnHeight && "not sure about that?");
for (int y = rDstBuffer.mnHeight; --y >= 0;)
{
@@ -669,6 +700,7 @@ bool ImplFastBitmapBlending( BitmapWriteAccess const & rDstWA,
return false;
// vertical mirroring
if( rTR.mnDestHeight < 0 )
+ // TODO: rDst.meDirection != ScanlineDirection::TopDown;
return false;
// offsetted blending is not implemented yet
diff --git a/vcl/source/bitmap/dibtools.cxx b/vcl/source/bitmap/dibtools.cxx
index cd7155e47935..97bcb86b0feb 100644
--- a/vcl/source/bitmap/dibtools.cxx
+++ b/vcl/source/bitmap/dibtools.cxx
@@ -499,7 +499,7 @@ bool ImplReadDIBBits(SvStream& rIStm, DIBV5Header& rHeader, BitmapWriteAccess& r
{
// we can't trust arbitrary-sourced index based formats to have correct indexes, so we exclude the pal formats
// from raw read and force checking their colormap indexes
- bNative = bTopDown && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth );
+ bNative = ( ( rAcc.IsBottomUp() != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) );
break;
}
@@ -1246,8 +1246,13 @@ bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess const & rAcc, sal_uLong
rImageSize = rOStm.Tell();
- for( tools::Long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0; nY-- )
- rOStm.WriteBytes( rAcc.GetScanline(nY), nScanlineSize );
+ if( rAcc.IsBottomUp() )
+ rOStm.WriteBytes(rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize());
+ else
+ {
+ for( tools::Long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0; nY-- )
+ rOStm.WriteBytes( rAcc.GetScanline(nY), nScanlineSize );
+ }
}
else if((RLE_4 == nCompression) || (RLE_8 == nCompression))
{
@@ -1266,60 +1271,88 @@ bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess const & rAcc, sal_uLong
// (other cases are not written below)
const auto ePixelFormat(convertToBPP(rAcc.GetBitCount()));
const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * sal_Int32(ePixelFormat)));
+ bool bNative(false);
- rImageSize = rOStm.Tell();
-
- const tools::Long nWidth(rAcc.Width());
- const tools::Long nHeight(rAcc.Height());
- std::vector<sal_uInt8> aBuf(nAlignedWidth);
- switch(ePixelFormat)
+ switch(rAcc.GetScanlineFormat())
{
- case vcl::PixelFormat::N8_BPP:
+ case ScanlineFormat::N1BitMsbPal:
+ case ScanlineFormat::N8BitPal:
+ case ScanlineFormat::N24BitTcBgr:
{
- for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
+ if(rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth))
{
- sal_uInt8* pTmp = aBuf.data();
- Scanline pScanline = rAcc.GetScanline( nY );
-
- for( tools::Long nX = 0; nX < nWidth; nX++ )
- *pTmp++ = rAcc.GetIndexFromData( pScanline, nX );
-
- rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
+ bNative = true;
}
+
+ break;
}
- break;
- case vcl::PixelFormat::N24_BPP:
+ default:
{
- //valgrind, zero out the trailing unused alignment bytes
- size_t nUnusedBytes = nAlignedWidth - nWidth * 3;
- memset(aBuf.data() + nAlignedWidth - nUnusedBytes, 0, nUnusedBytes);
+ break;
}
- [[fallthrough]];
- // #i59239# fallback to 24 bit format, if bitcount is non-default
- default:
+ }
+
+ rImageSize = rOStm.Tell();
+
+ if(bNative)
+ {
+ rOStm.WriteBytes(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height());
+ }
+ else
+ {
+ const tools::Long nWidth(rAcc.Width());
+ const tools::Long nHeight(rAcc.Height());
+ std::vector<sal_uInt8> aBuf(nAlignedWidth);
+ switch(ePixelFormat)
{
- BitmapColor aPixelColor;
+ case vcl::PixelFormat::N8_BPP:
+ {
+ for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
+ {
+ sal_uInt8* pTmp = aBuf.data();
+ Scanline pScanline = rAcc.GetScanline( nY );
- for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
+ for( tools::Long nX = 0; nX < nWidth; nX++ )
+ *pTmp++ = rAcc.GetIndexFromData( pScanline, nX );
+
+ rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
+ }
+ }
+ break;
+
+ case vcl::PixelFormat::N24_BPP:
+ {
+ //valgrind, zero out the trailing unused alignment bytes
+ size_t nUnusedBytes = nAlignedWidth - nWidth * 3;
+ memset(aBuf.data() + nAlignedWidth - nUnusedBytes, 0, nUnusedBytes);
+ }
+ [[fallthrough]];
+ // #i59239# fallback to 24 bit format, if bitcount is non-default
+ default:
{
- sal_uInt8* pTmp = aBuf.data();
+ BitmapColor aPixelColor;
- for( tools::Long nX = 0; nX < nWidth; nX++ )
+ for( tools::Long nY = nHeight - 1; nY >= 0; nY-- )
{
- // when alpha is used, this may be non-24bit main bitmap, so use GetColor
- // instead of GetPixel to ensure RGB value
- aPixelColor = rAcc.GetColor( nY, nX );
+ sal_uInt8* pTmp = aBuf.data();
- *pTmp++ = aPixelColor.GetBlue();
- *pTmp++ = aPixelColor.GetGreen();
- *pTmp++ = aPixelColor.GetRed();
- }
+ for( tools::Long nX = 0; nX < nWidth; nX++ )
+ {
+ // when alpha is used, this may be non-24bit main bitmap, so use GetColor
+ // instead of GetPixel to ensure RGB value
+ aPixelColor = rAcc.GetColor( nY, nX );
- rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
+ *pTmp++ = aPixelColor.GetBlue();
+ *pTmp++ = aPixelColor.GetGreen();
+ *pTmp++ = aPixelColor.GetRed();
+ }
+
+ rOStm.WriteBytes(aBuf.data(), nAlignedWidth);
+ }
}
+ break;
}
- break;
}
}
diff --git a/vcl/source/bitmap/salbmp.cxx b/vcl/source/bitmap/salbmp.cxx
index a84fc63f4042..3e8f0b255d2d 100644
--- a/vcl/source/bitmap/salbmp.cxx
+++ b/vcl/source/bitmap/salbmp.cxx
@@ -62,11 +62,19 @@ void SalBitmap::updateChecksum() const
break;
}
}
- if( pBuf->mnScanlineSize == lineBitsCount / 8 )
- nCrc = rtl_crc32(nCrc, pBuf->mpBits, pBuf->mnScanlineSize * pBuf->mnHeight);
- else // Do not include padding with undefined content in the checksum.
- for( tools::Long y = 0; y < pBuf->mnHeight; ++y )
+ if (pBuf->meDirection == ScanlineDirection::TopDown)
+ {
+ if( pBuf->mnScanlineSize == lineBitsCount / 8 )
+ nCrc = rtl_crc32(nCrc, pBuf->mpBits, pBuf->mnScanlineSize * pBuf->mnHeight);
+ else // Do not include padding with undefined content in the checksum.
+ for( tools::Long y = 0; y < pBuf->mnHeight; ++y )
+ nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
+ }
+ else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
+ {
+ for( tools::Long y = pBuf->mnHeight - 1; y >= 0; --y )
nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
+ }
pThis->ReleaseBuffer(pBuf, BitmapAccessMode::Read);
pThis->mnChecksum = nCrc;
pThis->mbChecksumValid = true;
diff --git a/vcl/source/filter/webp/reader.cxx b/vcl/source/filter/webp/reader.cxx
index 2cc3f8c6a08e..cfc28a18440b 100644
--- a/vcl/source/filter/webp/reader.cxx
+++ b/vcl/source/filter/webp/reader.cxx
@@ -215,7 +215,23 @@ static bool readWebp(SvStream& stream, Graphic& graphic)
switch (pixelMode)
{
case PixelMode::DirectRead:
+ {
+ // Adjust for IsBottomUp() if necessary.
+ if (access->IsBottomUp())
+ {
+ std::vector<char> tmp;
+ const sal_uInt32 lineSize = access->GetScanlineSize();
+ tmp.resize(lineSize);
+ for (tools::Long y = 0; y < access->Height() / 2; ++y)
+ {
+ tools::Long otherY = access->Height() - 1 - y;
+ memcpy(tmp.data(), access->GetScanline(y), lineSize);
+ memcpy(access->GetScanline(y), access->GetScanline(otherY), lineSize);
+ memcpy(access->GetScanline(otherY), tmp.data(), lineSize);
+ }
+ }
break;
+ }
case PixelMode::Split:
{
// Split to normal and alpha bitmaps.
diff --git a/vcl/source/filter/webp/writer.cxx b/vcl/source/filter/webp/writer.cxx
index 6a4e772eafd4..cd63cd2d2786 100644
--- a/vcl/source/filter/webp/writer.cxx
+++ b/vcl/source/filter/webp/writer.cxx
@@ -99,7 +99,7 @@ static bool writeWebp(SvStream& rStream, const BitmapEx& bitmapEx, bool lossless
BitmapScopedReadAccess access(bitmap);
BitmapScopedReadAccess accessAlpha(bitmapAlpha);
bool dataDone = false;
- if (bitmapAlpha.IsEmpty())
+ if (!access->IsBottomUp() && bitmapAlpha.IsEmpty())
{
// Try to directly copy the bitmap data.
switch (access->GetScanlineFormat())
diff --git a/vcl/source/gdi/salmisc.cxx b/vcl/source/gdi/salmisc.cxx
index 2ab6f77a23f1..79d976ac25db 100644
--- a/vcl/source/gdi/salmisc.cxx
+++ b/vcl/source/gdi/salmisc.cxx
@@ -235,6 +235,7 @@ std::optional<BitmapBuffer> StretchAndConvert(
std::optional<BitmapBuffer> pDstBuffer(std::in_place);
+ pDstBuffer->meDirection = rSrcBuffer.meDirection;
// set function for getting pixels
pFncGetPixel = BitmapReadAccess::GetPixelFunction(rSrcBuffer.meFormat);
if( !pFncGetPixel )
@@ -378,15 +379,33 @@ std::optional<BitmapBuffer> StretchAndConvert(
}
// source scanline buffer
- Scanline pTmpScan = rSrcBuffer.mpBits;
- tools::Long nOffset = rSrcBuffer.mnScanlineSize;
+ Scanline pTmpScan;
+ tools::Long nOffset;
+ if (rSrcBuffer.meDirection == ScanlineDirection::TopDown)
+ {
+ pTmpScan = rSrcBuffer.mpBits;
+ nOffset = rSrcBuffer.mnScanlineSize;
+ }
+ else
+ {
+ pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
+ nOffset = -rSrcBuffer.mnScanlineSize;
+ }
for (tools::Long i = 0; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset)
pSrcScan[ i ] = pTmpScan;
// destination scanline buffer
- pTmpScan = pDstBuffer->mpBits;
- nOffset = pDstBuffer->mnScanlineSize;
+ if (pDstBuffer->meDirection == ScanlineDirection::TopDown)
+ {
+ pTmpScan = pDstBuffer->mpBits;
+ nOffset = pDstBuffer->mnScanlineSize;
+ }
+ else
+ {
+ pTmpScan = pDstBuffer->mpBits + ( pDstBuffer->mnHeight - 1 ) * pDstBuffer->mnScanlineSize;
+ nOffset = -pDstBuffer->mnScanlineSize;
+ }
for (tools::Long i = 0; i < pDstBuffer->mnHeight; i++, pTmpScan += nOffset)
pDstScan[ i ] = pTmpScan;
diff --git a/vcl/source/helper/canvasbitmap.cxx b/vcl/source/helper/canvasbitmap.cxx
index 55a606a466e4..fc260b591773 100644
--- a/vcl/source/helper/canvasbitmap.cxx
+++ b/vcl/source/helper/canvasbitmap.cxx
@@ -399,6 +399,11 @@ uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerB
bitmapLayout.ScanLineStride= aRequestedBytes.getOpenWidth();
sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride;
+ if (m_pBmpAcc->IsBottomUp())
+ {
+ pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getOpenHeight()-1);
+ nScanlineStride *= -1;
+ }
if( !m_aBmpEx.IsAlpha() )
{
diff --git a/vcl/source/opengl/OpenGLHelper.cxx b/vcl/source/opengl/OpenGLHelper.cxx
index 7dd10addea1d..19fb34df5d96 100644
--- a/vcl/source/opengl/OpenGLHelper.cxx
+++ b/vcl/source/opengl/OpenGLHelper.cxx
@@ -561,8 +561,12 @@ BitmapEx OpenGLHelper::ConvertBufferToBitmapEx(const sal_uInt8* const pBuffer, t
BitmapScopedWriteAccess pAlphaWriteAccess( aAlpha );
#ifdef _WIN32
assert(pWriteAccess->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr);
+ assert(pWriteAccess->IsTopDown());
+ assert(pAlphaWriteAccess->IsTopDown());
#else
assert(pWriteAccess->GetScanlineFormat() == ScanlineFormat::N24BitTcRgb);
+ assert(!pWriteAccess->IsTopDown());
+ assert(!pAlphaWriteAccess->IsTopDown());
#endif
assert(pAlphaWriteAccess->GetScanlineFormat() == ScanlineFormat::N8BitPal);