1
0
Fork 0
libreoffice/vcl/source/bitmap/bmpfast.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

818 lines
28 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <vcl/salgtype.hxx>
#include <vcl/BitmapWriteAccess.hxx>
#include <bitmap/bmpfast.hxx>
#include <sal/log.hxx>
typedef unsigned char PIXBYTE;
namespace {
class BasePixelPtr
{
public:
explicit BasePixelPtr( PIXBYTE* p = nullptr ) : mpPixel( p ) {}
void SetRawPtr( PIXBYTE* pRawPtr ) { mpPixel = pRawPtr; }
void AddByteOffset( int nByteOffset ) { mpPixel += nByteOffset; }
protected:
PIXBYTE* mpPixel;
};
template <ScanlineFormat PIXFMT>
class TrueColorPixelPtr : public BasePixelPtr
{
public:
PIXBYTE GetRed() const;
PIXBYTE GetGreen() const;
PIXBYTE GetBlue() const;
PIXBYTE GetAlpha() const;
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const;
void SetAlpha( PIXBYTE a ) const;
};
// template specializations for truecolor pixel formats
template <>
class TrueColorPixelPtr<ScanlineFormat::N24BitTcRgb> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 3; }
PIXBYTE GetRed() const { return mpPixel[0]; }
PIXBYTE GetGreen() const { return mpPixel[1]; }
PIXBYTE GetBlue() const { return mpPixel[2]; }
static PIXBYTE GetAlpha() { return 255; }
static void SetAlpha( PIXBYTE ) {}
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
{
mpPixel[0] = r;
mpPixel[1] = g;
mpPixel[2] = b;
}
};
template <>
class TrueColorPixelPtr<ScanlineFormat::N24BitTcBgr> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 3; }
PIXBYTE GetRed() const { return mpPixel[2]; }
PIXBYTE GetGreen() const { return mpPixel[1]; }
PIXBYTE GetBlue() const { return mpPixel[0]; }
static PIXBYTE GetAlpha() { return 255; }
static void SetAlpha( PIXBYTE ) {}
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
{
mpPixel[0] = b;
mpPixel[1] = g;
mpPixel[2] = r;
}
};
template <>
class TrueColorPixelPtr<ScanlineFormat::N32BitTcArgb> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 4; }
PIXBYTE GetRed() const { return mpPixel[1]; }
PIXBYTE GetGreen() const { return mpPixel[2]; }
PIXBYTE GetBlue() const { return mpPixel[3]; }
PIXBYTE GetAlpha() const { return mpPixel[0]; }
void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
{
mpPixel[1] = r;
mpPixel[2] = g;
mpPixel[3] = b;
}
};
template <>
class TrueColorPixelPtr<ScanlineFormat::N32BitTcAbgr> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 4; }
PIXBYTE GetRed() const { return mpPixel[3]; }
PIXBYTE GetGreen() const { return mpPixel[2]; }
PIXBYTE GetBlue() const { return mpPixel[1]; }
PIXBYTE GetAlpha() const { return mpPixel[0]; }
void SetAlpha( PIXBYTE a ) const { mpPixel[0] = a; }
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
{
mpPixel[1] = b;
mpPixel[2] = g;
mpPixel[3] = r;
}
};
template <>
class TrueColorPixelPtr<ScanlineFormat::N32BitTcRgba> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 4; }
PIXBYTE GetRed() const { return mpPixel[0]; }
PIXBYTE GetGreen() const { return mpPixel[1]; }
PIXBYTE GetBlue() const { return mpPixel[2]; }
PIXBYTE GetAlpha() const { return mpPixel[3]; }
void SetAlpha( PIXBYTE a ) const{ mpPixel[3] = a; }
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
{
mpPixel[0] = r;
mpPixel[1] = g;
mpPixel[2] = b;
}
};
template <>
class TrueColorPixelPtr<ScanlineFormat::N32BitTcBgra> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 4; }
PIXBYTE GetRed() const { return mpPixel[2]; }
PIXBYTE GetGreen() const { return mpPixel[1]; }
PIXBYTE GetBlue() const { return mpPixel[0]; }
PIXBYTE GetAlpha() const { return mpPixel[3]; }
void SetAlpha( PIXBYTE a ) const{ mpPixel[3] = a; }
void SetColor( PIXBYTE r, PIXBYTE g, PIXBYTE b ) const
{
mpPixel[0] = b;
mpPixel[1] = g;
mpPixel[2] = r;
}
};
// This assumes the content uses the grayscale palette (needs to be checked
// by code allowing the use of the format).
// Only reading color is implemented, since e.g. 24bpp input couldn't be
// easily guaranteed to be grayscale.
template <>
class TrueColorPixelPtr<ScanlineFormat::N8BitPal> : public BasePixelPtr
{
public:
void operator++() { mpPixel += 1; }
PIXBYTE GetRed() const { return mpPixel[0]; }
PIXBYTE GetGreen() const { return mpPixel[0]; }
PIXBYTE GetBlue() const { return mpPixel[0]; }
static PIXBYTE GetAlpha() { return 255; }
};
}
// converting truecolor formats
template <ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
static void ImplConvertPixel( const TrueColorPixelPtr<DSTFMT>& rDst,
const TrueColorPixelPtr<SRCFMT>& rSrc )
{
rDst.SetColor( rSrc.GetRed(), rSrc.GetGreen(), rSrc.GetBlue() );
rDst.SetAlpha( rSrc.GetAlpha() );
}
template <ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
static void ImplConvertLine( const TrueColorPixelPtr<DSTFMT>& rDst,
const TrueColorPixelPtr<SRCFMT>& rSrc, int nPixelCount )
{
TrueColorPixelPtr<DSTFMT> aDst( rDst );
TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
while( --nPixelCount >= 0 )
{
ImplConvertPixel( aDst, aSrc );
++aSrc;
++aDst;
}
}
// alpha blending truecolor pixels
template <ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
static void ImplBlendPixels( const TrueColorPixelPtr<DSTFMT>& rDst,
const TrueColorPixelPtr<SRCFMT>& rSrc, unsigned nAlphaVal )
{
static const unsigned nAlphaShift = 8;
if( !nAlphaVal )
ImplConvertPixel( rDst, rSrc );
else if( nAlphaVal != ~(~0U << nAlphaShift) )
{
int nR = rDst.GetRed();
int nS = rSrc.GetRed();
nR = nS + (((nR - nS) * nAlphaVal) >> nAlphaShift);
int nG = rDst.GetGreen();
nS = rSrc.GetGreen();
nG = nS + (((nG - nS) * nAlphaVal) >> nAlphaShift);
int nB = rDst.GetBlue();
nS = rSrc.GetBlue();
nB = nS + (((nB - nS) * nAlphaVal) >> nAlphaShift);
rDst.SetColor( sal::static_int_cast<PIXBYTE>(nR),
sal::static_int_cast<PIXBYTE>(nG),
sal::static_int_cast<PIXBYTE>(nB) );
}
}
template <ScanlineFormat MASKFMT, ScanlineFormat SRCFMT, ScanlineFormat DSTFMT>
static void ImplBlendLines( const TrueColorPixelPtr<DSTFMT>& rDst,
const TrueColorPixelPtr<SRCFMT>& rSrc, const TrueColorPixelPtr<MASKFMT>& rMsk,
int nPixelCount )
{
TrueColorPixelPtr<MASKFMT> aMsk( rMsk );
TrueColorPixelPtr<DSTFMT> aDst( rDst );
TrueColorPixelPtr<SRCFMT> aSrc( rSrc );
while( --nPixelCount >= 0 )
{
// VCL masks store alpha as color, hence the GetRed() and not GetAlpha().
ImplBlendPixels(aDst, aSrc, aMsk.GetRed());
++aDst;
++aSrc;
++aMsk;
}
}
static bool ImplCopyImage( BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer )
{
const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
int nDstLinestep = rDstBuffer.mnScanlineSize;
const PIXBYTE* pRawSrc = rSrcBuffer.mpBits;
PIXBYTE* pRawDst = rDstBuffer.mpBits;
// 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;
}
int nByteWidth = nSrcLinestep;
if( nByteWidth > rDstBuffer.mnScanlineSize )
nByteWidth = rDstBuffer.mnScanlineSize;
for( int y = rSrcBuffer.mnHeight; --y >= 0; )
{
memcpy( pRawDst, pRawSrc, nByteWidth );
pRawSrc += nSrcLinestep;
pRawDst += nDstLinestep;
}
return true;
}
template <ScanlineFormat DSTFMT,ScanlineFormat SRCFMT>
static bool ImplConvertToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer )
{
// help the compiler to avoid instantiations of unneeded conversions
SAL_WARN_IF( SRCFMT == DSTFMT, "vcl.gdi", "ImplConvertToBitmap into same format");
if( SRCFMT == DSTFMT )
return false;
const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
int nDstLinestep = rDstBuffer.mnScanlineSize;
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 );
rSrcLine.AddByteOffset( nSrcLinestep );
aDstLine.AddByteOffset( nDstLinestep );
}
return true;
}
template <ScanlineFormat SRCFMT>
static bool ImplConvertFromBitmap( BitmapBuffer& rDst, const BitmapBuffer& rSrc )
{
TrueColorPixelPtr<SRCFMT> aSrcType; aSrcType.SetRawPtr( rSrc.mpBits );
// select the matching instantiation for the destination's bitmap format
switch (rDst.meFormat)
{
case ScanlineFormat::N1BitMsbPal:
case ScanlineFormat::N8BitPal:
break;
case ScanlineFormat::N32BitTcMask:
// return ImplConvertToBitmap<ScanlineFormat::N32BitTcMask>( aSrcType, rDst, rSrc );
break;
case ScanlineFormat::N24BitTcBgr:
return ImplConvertToBitmap<ScanlineFormat::N24BitTcBgr>( aSrcType, rDst, rSrc );
case ScanlineFormat::N24BitTcRgb:
return ImplConvertToBitmap<ScanlineFormat::N24BitTcRgb>( aSrcType, rDst, rSrc );
case ScanlineFormat::N32BitTcAbgr:
return ImplConvertToBitmap<ScanlineFormat::N32BitTcAbgr>( aSrcType, rDst, rSrc );
case ScanlineFormat::N32BitTcArgb:
return ImplConvertToBitmap<ScanlineFormat::N32BitTcArgb>( aSrcType, rDst, rSrc );
case ScanlineFormat::N32BitTcBgra:
return ImplConvertToBitmap<ScanlineFormat::N32BitTcBgra>( aSrcType, rDst, rSrc );
case ScanlineFormat::N32BitTcRgba:
return ImplConvertToBitmap<ScanlineFormat::N32BitTcRgba>( aSrcType, rDst, rSrc );
default: break;
}
static int nNotAccelerated = 0;
SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
"vcl.gdi",
"ImplConvertFromBitmap for not accelerated case (" << std::hex << int(rSrc.meFormat) << "->" << int(rDst.meFormat) << ")" );
return false;
}
// A universal stretching conversion is overkill in most common situations
// => performance benefits for speeding up the non-stretching cases
bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc,
const SalTwoRect& rTR )
{
// TODO:horizontal mirroring not implemented yet
if( rTR.mnDestWidth < 0 )
return false;
// vertical mirroring
if( rTR.mnDestHeight < 0 )
// TODO: rDst.meDirection != ScanlineDirection::TopDown;
return false;
// offsetted conversion is not implemented yet
if( rTR.mnSrcX || rTR.mnSrcY )
return false;
if( rTR.mnDestX || rTR.mnDestY )
return false;
// stretched conversion is not implemented yet
if( rTR.mnDestWidth != rTR.mnSrcWidth )
return false;
if( rTR.mnDestHeight!= rTR.mnSrcHeight )
return false;
// check source image size
if( rSrc.mnWidth < rTR.mnSrcX + rTR.mnSrcWidth )
return false;
if( rSrc.mnHeight < rTR.mnSrcY + rTR.mnSrcHeight )
return false;
// check dest image size
if( rDst.mnWidth < rTR.mnDestX + rTR.mnDestWidth )
return false;
if( rDst.mnHeight < rTR.mnDestY + rTR.mnDestHeight )
return false;
const ScanlineFormat nSrcFormat = rSrc.meFormat;
const ScanlineFormat nDstFormat = rDst.meFormat;
// special handling of trivial cases
if( nSrcFormat == nDstFormat )
{
// accelerated palette conversions not yet implemented
if( rSrc.maPalette != rDst.maPalette )
return false;
return ImplCopyImage( rDst, rSrc );
}
// select the matching instantiation for the source's bitmap format
switch( nSrcFormat )
{
case ScanlineFormat::N1BitMsbPal:
break;
case ScanlineFormat::N32BitTcMask:
// return ImplConvertFromBitmap<ScanlineFormat::N32BitTcMask>( rDst, rSrc );
break;
case ScanlineFormat::N8BitPal:
if(rSrc.maPalette.IsGreyPalette8Bit())
return ImplConvertFromBitmap<ScanlineFormat::N8BitPal>( rDst, rSrc );
break;
case ScanlineFormat::N24BitTcBgr:
return ImplConvertFromBitmap<ScanlineFormat::N24BitTcBgr>( rDst, rSrc );
case ScanlineFormat::N24BitTcRgb:
return ImplConvertFromBitmap<ScanlineFormat::N24BitTcRgb>( rDst, rSrc );
case ScanlineFormat::N32BitTcAbgr:
return ImplConvertFromBitmap<ScanlineFormat::N32BitTcAbgr>( rDst, rSrc );
case ScanlineFormat::N32BitTcArgb:
return ImplConvertFromBitmap<ScanlineFormat::N32BitTcArgb>( rDst, rSrc );
case ScanlineFormat::N32BitTcBgra:
return ImplConvertFromBitmap<ScanlineFormat::N32BitTcBgra>( rDst, rSrc );
case ScanlineFormat::N32BitTcRgba:
return ImplConvertFromBitmap<ScanlineFormat::N32BitTcRgba>( rDst, rSrc );
default: break;
}
static int nNotAccelerated = 0;
SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
"vcl.gdi",
"ImplFastBitmapConversion for not accelerated case (" << std::hex << int(rSrc.meFormat) << "->" << int(rDst.meFormat) << ")" );
return false;
}
static inline ConstScanline ImplGetScanline( const BitmapBuffer& rBuf, tools::Long nY )
{
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 )
{
return const_cast<Scanline>(ImplGetScanline( const_cast<const BitmapBuffer&>(rBuf), nY ));
}
template <ScanlineFormat DSTFMT, ScanlineFormat SRCFMT>
static bool ImplCopyToScanline( tools::Long nY, BitmapBuffer& rDst, TrueColorPixelPtr<SRCFMT>& rSrcLine, tools::Long nSrcWidth )
{
TrueColorPixelPtr<DSTFMT> aDstType;
aDstType.SetRawPtr( ImplGetScanline( rDst, nY ));
ImplConvertLine( aDstType, rSrcLine, std::min( nSrcWidth, rDst.mnWidth ));
return true;
}
template <ScanlineFormat SRCFMT>
static bool ImplCopyFromScanline( tools::Long nY, BitmapBuffer& rDst, ConstScanline aSrcScanline, tools::Long nSrcWidth )
{
TrueColorPixelPtr<SRCFMT> aSrcType;
aSrcType.SetRawPtr( const_cast<Scanline>( aSrcScanline ));
// select the matching instantiation for the destination's bitmap format
switch (rDst.meFormat)
{
case ScanlineFormat::N24BitTcBgr:
return ImplCopyToScanline<ScanlineFormat::N24BitTcBgr>( nY, rDst, aSrcType, nSrcWidth );
case ScanlineFormat::N24BitTcRgb:
return ImplCopyToScanline<ScanlineFormat::N24BitTcRgb>( nY, rDst, aSrcType, nSrcWidth );
case ScanlineFormat::N32BitTcAbgr:
return ImplCopyToScanline<ScanlineFormat::N32BitTcAbgr>( nY, rDst, aSrcType, nSrcWidth );
case ScanlineFormat::N32BitTcArgb:
return ImplCopyToScanline<ScanlineFormat::N32BitTcArgb>( nY, rDst, aSrcType, nSrcWidth );
case ScanlineFormat::N32BitTcBgra:
return ImplCopyToScanline<ScanlineFormat::N32BitTcBgra>( nY, rDst, aSrcType, nSrcWidth );
case ScanlineFormat::N32BitTcRgba:
return ImplCopyToScanline<ScanlineFormat::N32BitTcRgba>( nY, rDst, aSrcType, nSrcWidth );
default:
break;
}
return false;
}
bool ImplFastCopyScanline( tools::Long nY, BitmapBuffer& rDst, ConstScanline aSrcScanline,
ScanlineFormat nSrcScanlineFormat, sal_uInt32 nSrcScanlineSize)
{
if( rDst.mnHeight <= nY )
return false;
const ScanlineFormat nSrcFormat = nSrcScanlineFormat;
const ScanlineFormat nDstFormat = rDst.meFormat;
// special handling of trivial cases
if( nSrcFormat == nDstFormat )
{
memcpy( ImplGetScanline( rDst, nY ), aSrcScanline, std::min<tools::Long>(nSrcScanlineSize, rDst.mnScanlineSize));
return true;
}
// select the matching instantiation for the source's bitmap format
switch( nSrcFormat )
{
case ScanlineFormat::N24BitTcBgr:
return ImplCopyFromScanline<ScanlineFormat::N24BitTcBgr>( nY, rDst, aSrcScanline, nSrcScanlineSize / 3 );
case ScanlineFormat::N24BitTcRgb:
return ImplCopyFromScanline<ScanlineFormat::N24BitTcRgb>( nY, rDst, aSrcScanline, nSrcScanlineSize / 3 );
case ScanlineFormat::N32BitTcAbgr:
return ImplCopyFromScanline<ScanlineFormat::N32BitTcAbgr>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
case ScanlineFormat::N32BitTcArgb:
return ImplCopyFromScanline<ScanlineFormat::N32BitTcArgb>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
case ScanlineFormat::N32BitTcBgra:
return ImplCopyFromScanline<ScanlineFormat::N32BitTcBgra>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
case ScanlineFormat::N32BitTcRgba:
return ImplCopyFromScanline<ScanlineFormat::N32BitTcRgba>( nY, rDst, aSrcScanline, nSrcScanlineSize / 4 );
default:
break;
}
return false;
}
bool ImplFastCopyScanline( tools::Long nY, BitmapBuffer& rDst, const BitmapBuffer& rSrc)
{
if( nY >= rDst.mnHeight )
return false;
if( rSrc.maPalette != rDst.maPalette )
return false;
return ImplFastCopyScanline( nY, rDst, ImplGetScanline( rSrc, nY ), rSrc.meFormat, rSrc.mnScanlineSize);
}
template <ScanlineFormat DSTFMT, ScanlineFormat SRCFMT> //,sal_uLong MSKFMT>
static bool ImplBlendToBitmap( TrueColorPixelPtr<SRCFMT>& rSrcLine,
BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
const BitmapBuffer& rMskBuffer )
{
SAL_WARN_IF(rMskBuffer.meFormat != ScanlineFormat::N8BitPal, "vcl.gdi", "FastBmp BlendImage: unusual MSKFMT");
const int nSrcLinestep = rSrcBuffer.mnScanlineSize;
int nMskLinestep = rMskBuffer.mnScanlineSize;
int nDstLinestep = rDstBuffer.mnScanlineSize;
TrueColorPixelPtr<ScanlineFormat::N8BitPal> aMskLine; aMskLine.SetRawPtr( rMskBuffer.mpBits );
TrueColorPixelPtr<DSTFMT> aDstLine; aDstLine.SetRawPtr( rDstBuffer.mpBits );
// special case for single line masks
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;)
{
ImplBlendLines(aDstLine, rSrcLine, aMskLine, rDstBuffer.mnWidth);
aDstLine.AddByteOffset( nDstLinestep );
rSrcLine.AddByteOffset( nSrcLinestep );
aMskLine.AddByteOffset( nMskLinestep );
}
return true;
}
// some specializations to reduce the code size
template <>
bool ImplBlendToBitmap<ScanlineFormat::N24BitTcBgr,ScanlineFormat::N24BitTcBgr>(
TrueColorPixelPtr<ScanlineFormat::N24BitTcBgr>&,
BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
const BitmapBuffer& rMskBuffer )
{
TrueColorPixelPtr<ScanlineFormat::N24BitTcRgb> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
return ImplBlendToBitmap<ScanlineFormat::N24BitTcRgb>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
}
template <>
bool ImplBlendToBitmap<ScanlineFormat::N32BitTcAbgr,ScanlineFormat::N32BitTcAbgr>(
TrueColorPixelPtr<ScanlineFormat::N32BitTcAbgr>&,
BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
const BitmapBuffer& rMskBuffer )
{
TrueColorPixelPtr<ScanlineFormat::N32BitTcArgb> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
return ImplBlendToBitmap<ScanlineFormat::N32BitTcArgb>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
}
template <>
bool ImplBlendToBitmap<ScanlineFormat::N32BitTcBgra,ScanlineFormat::N32BitTcBgra>(
TrueColorPixelPtr<ScanlineFormat::N32BitTcBgra>&,
BitmapBuffer& rDstBuffer, const BitmapBuffer& rSrcBuffer,
const BitmapBuffer& rMskBuffer )
{
TrueColorPixelPtr<ScanlineFormat::N32BitTcRgba> aSrcType; aSrcType.SetRawPtr( rSrcBuffer.mpBits );
return ImplBlendToBitmap<ScanlineFormat::N32BitTcRgba>( aSrcType, rDstBuffer, rSrcBuffer, rMskBuffer );
}
template <ScanlineFormat SRCFMT>
static bool ImplBlendFromBitmap( BitmapBuffer& rDst, const BitmapBuffer& rSrc, const BitmapBuffer& rMsk )
{
TrueColorPixelPtr<SRCFMT> aSrcType; aSrcType.SetRawPtr( rSrc.mpBits );
// select the matching instantiation for the destination's bitmap format
switch (rDst.meFormat)
{
case ScanlineFormat::N1BitMsbPal:
case ScanlineFormat::N8BitPal:
break;
case ScanlineFormat::N32BitTcMask:
// return ImplBlendToBitmap<ScanlineFormat::N32BitTcMask>( aSrcType, rDst, rSrc, rMsk );
break;
case ScanlineFormat::N24BitTcBgr:
return ImplBlendToBitmap<ScanlineFormat::N24BitTcBgr>( aSrcType, rDst, rSrc, rMsk );
case ScanlineFormat::N24BitTcRgb:
return ImplBlendToBitmap<ScanlineFormat::N24BitTcRgb>( aSrcType, rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcAbgr:
return ImplBlendToBitmap<ScanlineFormat::N32BitTcAbgr>( aSrcType, rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcArgb:
return ImplBlendToBitmap<ScanlineFormat::N32BitTcArgb>( aSrcType, rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcBgra:
return ImplBlendToBitmap<ScanlineFormat::N32BitTcBgra>( aSrcType, rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcRgba:
return ImplBlendToBitmap<ScanlineFormat::N32BitTcRgba>( aSrcType, rDst, rSrc, rMsk );
default: break;
}
static int nNotAccelerated = 0;
SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
"vcl.gdi",
"ImplBlendFromBitmap for not accelerated case (" << std::hex << int(rSrc.meFormat) << "*" << int(rMsk.meFormat) << "->" << int(rDst.meFormat) );
return false;
}
bool ImplFastBitmapBlending( BitmapWriteAccess const & rDstWA,
const BitmapReadAccess& rSrcRA, const BitmapReadAccess& rMskRA,
const SalTwoRect& rTR )
{
// accelerated blending of paletted bitmaps not implemented yet
if( rSrcRA.HasPalette() )
return false;
if( rDstWA.HasPalette() )
return false;
// TODO: either get rid of mask's use of 8BIT_PAL or check the palette
// horizontal mirroring not implemented yet
if( rTR.mnDestWidth < 0 )
return false;
// vertical mirroring
if( rTR.mnDestHeight < 0 )
// TODO: rDst.meDirection != ScanlineDirection::TopDown;
return false;
// offsetted blending is not implemented yet
if( rTR.mnSrcX || rTR.mnSrcY )
return false;
if( rTR.mnDestX || rTR.mnDestY )
return false;
// stretched blending is not implemented yet
if( rTR.mnDestWidth != rTR.mnSrcWidth )
return false;
if( rTR.mnDestHeight!= rTR.mnSrcHeight )
return false;
// check source image size
if( rSrcRA.Width() < rTR.mnSrcX + rTR.mnSrcWidth )
return false;
if( rSrcRA.Height() < rTR.mnSrcY + rTR.mnSrcHeight )
return false;
// check mask image size
if( rMskRA.Width() < rTR.mnSrcX + rTR.mnSrcWidth )
return false;
if( rMskRA.Height() < rTR.mnSrcY + rTR.mnSrcHeight )
if( rMskRA.Height() != 1 )
return false;
// check dest image size
if( rDstWA.Width() < rTR.mnDestX + rTR.mnDestWidth )
return false;
if( rDstWA.Height() < rTR.mnDestY + rTR.mnDestHeight )
return false;
BitmapBuffer& rDst = *rDstWA.ImplGetBitmapBuffer();
const BitmapBuffer& rSrc = *rSrcRA.ImplGetBitmapBuffer();
const BitmapBuffer& rMsk = *rMskRA.ImplGetBitmapBuffer();
// select the matching instantiation for the source's bitmap format
switch (rSrc.meFormat)
{
case ScanlineFormat::N1BitMsbPal:
break;
case ScanlineFormat::N32BitTcMask:
// return ImplBlendFromBitmap<ScanlineFormat::N32BitTcMask>( rDst, rSrc );
break;
case ScanlineFormat::N8BitPal:
if(rSrc.maPalette.IsGreyPalette8Bit())
return ImplBlendFromBitmap<ScanlineFormat::N8BitPal>( rDst, rSrc, rMsk );
break;
case ScanlineFormat::N24BitTcBgr:
return ImplBlendFromBitmap<ScanlineFormat::N24BitTcBgr>( rDst, rSrc, rMsk );
case ScanlineFormat::N24BitTcRgb:
return ImplBlendFromBitmap<ScanlineFormat::N24BitTcRgb>( rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcAbgr:
return ImplBlendFromBitmap<ScanlineFormat::N32BitTcAbgr>( rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcArgb:
return ImplBlendFromBitmap<ScanlineFormat::N32BitTcArgb>( rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcBgra:
return ImplBlendFromBitmap<ScanlineFormat::N32BitTcBgra>( rDst, rSrc, rMsk );
case ScanlineFormat::N32BitTcRgba:
return ImplBlendFromBitmap<ScanlineFormat::N32BitTcRgba>( rDst, rSrc, rMsk );
default: break;
}
static int nNotAccelerated = 0;
SAL_WARN_IF( rSrc.mnWidth * rSrc.mnHeight >= 4000 && ++nNotAccelerated == 100,
"vcl.gdi",
"ImplFastBlend for not accelerated case (" << std::hex << int(rSrc.meFormat) << "*" << int(rMsk.meFormat) << "->" << int(rDst.meFormat) << ")" );
return false;
}
bool ImplFastEraseBitmap( BitmapBuffer& rDst, const BitmapColor& rColor )
{
// erasing a bitmap is often just a byte-wise memory fill
bool bByteFill = true;
sal_uInt8 nFillByte;
switch (rDst.meFormat)
{
case ScanlineFormat::N1BitMsbPal:
nFillByte = rColor.GetIndex();
nFillByte = static_cast<sal_uInt8>( -(nFillByte & 1) ); // 0x00 or 0xFF
break;
case ScanlineFormat::N8BitPal:
nFillByte = rColor.GetIndex();
break;
case ScanlineFormat::N24BitTcBgr:
case ScanlineFormat::N24BitTcRgb:
nFillByte = rColor.GetRed();
if( (nFillByte != rColor.GetGreen())
|| (nFillByte != rColor.GetBlue()) )
bByteFill = false;
break;
default:
bByteFill = false;
nFillByte = 0x00;
break;
}
if( bByteFill )
{
tools::Long nByteCount = rDst.mnHeight * rDst.mnScanlineSize;
memset( rDst.mpBits, nFillByte, nByteCount );
return true;
}
// TODO: handle other bitmap formats
switch (rDst.meFormat)
{
case ScanlineFormat::N32BitTcMask:
case ScanlineFormat::N24BitTcBgr:
case ScanlineFormat::N24BitTcRgb:
case ScanlineFormat::N32BitTcAbgr:
case ScanlineFormat::N32BitTcArgb:
case ScanlineFormat::N32BitTcBgra:
case ScanlineFormat::N32BitTcRgba:
break;
default:
break;
}
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */