move cairo extract bitmap code from canvas to vcl

part of making GetMask/GetAlpha an internal detail of vcl

Change-Id: I45c2e9fdae08d7f444a64e8e04a6f65bb525cbd1
Reviewed-on: https://gerrit.libreoffice.org/51417
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/canvas/source/cairo/cairo_canvashelper.cxx b/canvas/source/cairo/cairo_canvashelper.cxx
index bba59a1..2ed3d04 100644
--- a/canvas/source/cairo/cairo_canvashelper.cxx
+++ b/canvas/source/cairo/cairo_canvashelper.cxx
@@ -48,6 +48,7 @@
#include <tools/diagnose_ex.h>
#include <vcl/bitmapex.hxx>
#include <vcl/bitmapaccess.hxx>
#include <vcl/BitmapTools.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/virdev.hxx>

@@ -328,71 +329,6 @@ namespace cairocanvas
        return ::BitmapEx();
    }

    static sal_uInt8 lcl_GetColor(BitmapColor const& rColor)
    {
        sal_uInt8 nTemp(0);
        if (rColor.IsIndex())
        {
            nTemp = rColor.GetIndex();
        }
        else
        {
            nTemp = rColor.GetBlue();
            // greyscale expected here, or what would non-grey colors mean?
            assert(rColor.GetRed() == nTemp && rColor.GetGreen() == nTemp);
        }
        return nTemp;
    }

    static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff )
    {
        bool bIsAlpha = false;
        long nX;
        int nAlpha;
        Scanline pReadScan;

        nOff += 3;

        switch( pAlphaReadAcc->GetScanlineFormat() )
        {
            case ScanlineFormat::N8BitTcMask:
                pReadScan = pAlphaReadAcc->GetScanline( nY );
                for( nX = 0; nX < nWidth; nX++ )
                {
                    nAlpha = data[ nOff ] = 255 - ( *pReadScan++ );
                    if( nAlpha != 255 )
                        bIsAlpha = true;
                    nOff += 4;
                }
                break;
            case ScanlineFormat::N8BitPal:
                pReadScan = pAlphaReadAcc->GetScanline( nY );
                for( nX = 0; nX < nWidth; nX++ )
                {
                    BitmapColor const& rColor(
                        pAlphaReadAcc->GetPaletteColor(*pReadScan));
                    pReadScan++;
                    nAlpha = data[ nOff ] = 255 - lcl_GetColor(rColor);
                    if( nAlpha != 255 )
                        bIsAlpha = true;
                    nOff += 4;
                }
                break;
            default:
                SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << static_cast<int>(pAlphaReadAcc->GetScanlineFormat()) );
                for( nX = 0; nX < nWidth; nX++ )
                {
                    nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
                    if( nAlpha != 255 )
                        bIsAlpha = true;
                    nOff += 4;
                }
        }

        return bIsAlpha;
    }


    /** surfaceFromXBitmap Create a surface from XBitmap
     * @param xBitmap bitmap image that will be used for the surface
     * @param rDevice reference to the device into which we want to draw
@@ -427,232 +363,20 @@ namespace cairocanvas

            if( !pSurface )
            {
                AlphaMask aAlpha = aBmpEx.GetAlpha();
                vcl::bitmap::CanvasCairoExtractBitmapData(aBmpEx, aBitmap, data, bHasAlpha);

                ::BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess();
                ::BitmapReadAccess* pAlphaReadAcc = nullptr;
                const long      nWidth = pBitmapReadAcc->Width();
                const long      nHeight = pBitmapReadAcc->Height();
                long nX, nY;
                bool bIsAlpha = false;

                if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() )
                    pAlphaReadAcc = aAlpha.AcquireReadAccess();

                data = static_cast<unsigned char*>(malloc( nWidth*nHeight*4 ));

                long nOff = 0;
                ::Color aColor;
                unsigned int nAlpha = 255;

                for( nY = 0; nY < nHeight; nY++ )
                {
                    ::Scanline pReadScan;

                    switch( pBitmapReadAcc->GetScanlineFormat() )
                    {
                    case ScanlineFormat::N8BitPal:
                        pReadScan = pBitmapReadAcc->GetScanline( nY );
                        if( pAlphaReadAcc )
                            if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                                bIsAlpha = true;

                        for( nX = 0; nX < nWidth; nX++ )
                        {
#ifdef OSL_BIGENDIAN
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff++ ];
                            else
                                nAlpha = data[ nOff++ ] = 255;
#else
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff + 3 ];
                            else
                                nAlpha = data[ nOff + 3 ] = 255;
#endif
                            aColor = pBitmapReadAcc->GetPaletteColor(*pReadScan++).GetColor();

#ifdef OSL_BIGENDIAN
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
#else
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
                            nOff++;
#endif
                        }
                        break;
                    case ScanlineFormat::N24BitTcBgr:
                        pReadScan = pBitmapReadAcc->GetScanline( nY );
                        if( pAlphaReadAcc )
                            if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                                bIsAlpha = true;

                        for( nX = 0; nX < nWidth; nX++ )
                        {
#ifdef OSL_BIGENDIAN
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff ];
                            else
                                nAlpha = data[ nOff ] = 255;
                            data[ nOff + 3 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff + 2 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff + 1 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            nOff += 4;
#else
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff + 3 ];
                            else
                                nAlpha = data[ nOff + 3 ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            nOff++;
#endif
                        }
                        break;
                    case ScanlineFormat::N24BitTcRgb:
                        pReadScan = pBitmapReadAcc->GetScanline( nY );
                        if( pAlphaReadAcc )
                            if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                                bIsAlpha = true;

                        for( nX = 0; nX < nWidth; nX++ )
                        {
#ifdef OSL_BIGENDIAN
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff++ ];
                            else
                                nAlpha = data[ nOff++ ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
#else
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff + 3 ];
                            else
                                nAlpha = data[ nOff + 3 ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
                            pReadScan += 3;
                            nOff++;
#endif
                        }
                        break;
                    case ScanlineFormat::N32BitTcBgra:
                        pReadScan = pBitmapReadAcc->GetScanline( nY );
                        if( pAlphaReadAcc )
                            if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                                bIsAlpha = true;

                        for( nX = 0; nX < nWidth; nX++ )
                        {
#ifdef OSL_BIGENDIAN
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff++ ];
                            else
                                nAlpha = data[ nOff++ ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
                            pReadScan += 4;
#else
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff + 3 ];
                            else
                                nAlpha = data[ nOff + 3 ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            pReadScan++;
                            nOff++;
#endif
                        }
                        break;
                    case ScanlineFormat::N32BitTcRgba:
                        pReadScan = pBitmapReadAcc->GetScanline( nY );
                        if( pAlphaReadAcc )
                            if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                                bIsAlpha = true;

                        for( nX = 0; nX < nWidth; nX++ )
                        {
#ifdef OSL_BIGENDIAN
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff ++ ];
                            else
                                nAlpha = data[ nOff ++ ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                            pReadScan++;
#else
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff + 3 ];
                            else
                                nAlpha = data[ nOff + 3 ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
                            pReadScan += 4;
                            nOff++;
#endif
                        }
                        break;
                    default:
                        SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << static_cast<int>(pBitmapReadAcc->GetScanlineFormat()) );

                        if( pAlphaReadAcc )
                            if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                                bIsAlpha = true;

                        for( nX = 0; nX < nWidth; nX++ )
                        {
                            aColor = pBitmapReadAcc->GetColor( nY, nX ).GetColor();

                            // cairo need premultiplied color values
                            // TODO(rodo) handle endianness
#ifdef OSL_BIGENDIAN
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff++ ];
                            else
                                nAlpha = data[ nOff++ ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
#else
                            if( pAlphaReadAcc )
                                nAlpha = data[ nOff + 3 ];
                            else
                                nAlpha = data[ nOff + 3 ] = 255;
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
                            data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
                            nOff ++;
#endif
                        }
                    }
                }

                ::Bitmap::ReleaseAccess( pBitmapReadAcc );
                if( pAlphaReadAcc )
                    aAlpha.ReleaseAccess( pAlphaReadAcc );

                const long nWidth = aBmpEx.GetPrefSize().Width();
                const long nHeight = aBmpEx.GetPrefSize().Height();
                SurfaceSharedPtr pImageSurface = rSurfaceProvider->getOutputDevice()->CreateSurface(
                    CairoSurfaceSharedPtr(
                        cairo_image_surface_create_for_data(
                            data,
                            bIsAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
                            bHasAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
                            nWidth, nHeight, nWidth*4 ),
                        &cairo_surface_destroy) );
                pSurface = pImageSurface;

                bHasAlpha = bIsAlpha;

                SAL_INFO( "canvas.cairo","image: " << nWidth << " x " << nHeight << " alpha: " << bIsAlpha << " alphaRead " << std::hex << pAlphaReadAcc);
                SAL_INFO( "canvas.cairo","image: " << nWidth << " x " << nHeight << " alpha: " << bHasAlpha);
            }
        }

diff --git a/include/vcl/BitmapTools.hxx b/include/vcl/BitmapTools.hxx
index 3a16927..9c347d2 100644
--- a/include/vcl/BitmapTools.hxx
+++ b/include/vcl/BitmapTools.hxx
@@ -98,6 +98,12 @@ VCL_DLLPUBLIC void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const

VCL_DLLPUBLIC css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx);

/**
 * @param data will be filled with alpha data, if xBitmap is alpha/transparent image
 * @param bHasAlpha will be set to true if resulting surface has alpha
 **/
VCL_DLLPUBLIC void CanvasCairoExtractBitmapData( BitmapEx & rBmpEx, Bitmap & rBitmap, unsigned char*& data, bool& bHasAlpha );

}} // end vcl::bitmap

#endif // INCLUDED_VCL_BITMAP_TOOLS_HXX
diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx
index 3abd1ca..816bad1 100644
--- a/vcl/source/bitmap/BitmapTools.cxx
+++ b/vcl/source/bitmap/BitmapTools.cxx
@@ -648,6 +648,297 @@ css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx)
    return css::uno::Sequence< sal_Int8 >();
}

static sal_uInt8 lcl_GetColor(BitmapColor const& rColor)
{
    sal_uInt8 nTemp(0);
    if (rColor.IsIndex())
    {
        nTemp = rColor.GetIndex();
    }
    else
    {
        nTemp = rColor.GetBlue();
        // greyscale expected here, or what would non-grey colors mean?
        assert(rColor.GetRed() == nTemp && rColor.GetGreen() == nTemp);
    }
    return nTemp;
}


static bool readAlpha( BitmapReadAccess const * pAlphaReadAcc, long nY, const long nWidth, unsigned char* data, long nOff )
{
    bool bIsAlpha = false;
    long nX;
    int nAlpha;
    Scanline pReadScan;

    nOff += 3;

    switch( pAlphaReadAcc->GetScanlineFormat() )
    {
        case ScanlineFormat::N8BitTcMask:
            pReadScan = pAlphaReadAcc->GetScanline( nY );
            for( nX = 0; nX < nWidth; nX++ )
            {
                nAlpha = data[ nOff ] = 255 - ( *pReadScan++ );
                if( nAlpha != 255 )
                    bIsAlpha = true;
                nOff += 4;
            }
            break;
        case ScanlineFormat::N8BitPal:
            pReadScan = pAlphaReadAcc->GetScanline( nY );
            for( nX = 0; nX < nWidth; nX++ )
            {
                BitmapColor const& rColor(
                    pAlphaReadAcc->GetPaletteColor(*pReadScan));
                pReadScan++;
                nAlpha = data[ nOff ] = 255 - lcl_GetColor(rColor);
                if( nAlpha != 255 )
                    bIsAlpha = true;
                nOff += 4;
            }
            break;
        default:
            SAL_INFO( "canvas.cairo", "fallback to GetColor for alpha - slow, format: " << static_cast<int>(pAlphaReadAcc->GetScanlineFormat()) );
            for( nX = 0; nX < nWidth; nX++ )
            {
                nAlpha = data[ nOff ] = 255 - pAlphaReadAcc->GetColor( nY, nX ).GetIndex();
                if( nAlpha != 255 )
                    bIsAlpha = true;
                nOff += 4;
            }
    }

    return bIsAlpha;
}



/**
 * @param data will be filled with alpha data, if xBitmap is alpha/transparent image
 * @param bHasAlpha will be set to true if resulting surface has alpha
 **/
void CanvasCairoExtractBitmapData( BitmapEx & aBmpEx, Bitmap & aBitmap, unsigned char*& data, bool& bHasAlpha )
{
    AlphaMask aAlpha = aBmpEx.GetAlpha();

    ::BitmapReadAccess* pBitmapReadAcc = aBitmap.AcquireReadAccess();
    ::BitmapReadAccess* pAlphaReadAcc = nullptr;
    const long      nWidth = pBitmapReadAcc->Width();
    const long      nHeight = pBitmapReadAcc->Height();
    long nX, nY;
    bool bIsAlpha = false;

    if( aBmpEx.IsTransparent() || aBmpEx.IsAlpha() )
        pAlphaReadAcc = aAlpha.AcquireReadAccess();

    data = static_cast<unsigned char*>(malloc( nWidth*nHeight*4 ));

    long nOff = 0;
    ::Color aColor;
    unsigned int nAlpha = 255;

    for( nY = 0; nY < nHeight; nY++ )
    {
        ::Scanline pReadScan;

        switch( pBitmapReadAcc->GetScanlineFormat() )
        {
        case ScanlineFormat::N8BitPal:
            pReadScan = pBitmapReadAcc->GetScanline( nY );
            if( pAlphaReadAcc )
                if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                    bIsAlpha = true;

            for( nX = 0; nX < nWidth; nX++ )
            {
#ifdef OSL_BIGENDIAN
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff++ ];
                else
                    nAlpha = data[ nOff++ ] = 255;
#else
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff + 3 ];
                else
                    nAlpha = data[ nOff + 3 ] = 255;
#endif
                aColor = pBitmapReadAcc->GetPaletteColor(*pReadScan++).GetColor();

#ifdef OSL_BIGENDIAN
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
#else
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetBlue() ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetGreen() ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( aColor.GetRed() ) )/255 );
                nOff++;
#endif
            }
            break;
        case ScanlineFormat::N24BitTcBgr:
            pReadScan = pBitmapReadAcc->GetScanline( nY );
            if( pAlphaReadAcc )
                if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                    bIsAlpha = true;

            for( nX = 0; nX < nWidth; nX++ )
            {
#ifdef OSL_BIGENDIAN
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff ];
                else
                    nAlpha = data[ nOff ] = 255;
                data[ nOff + 3 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff + 2 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff + 1 ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                nOff += 4;
#else
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff + 3 ];
                else
                    nAlpha = data[ nOff + 3 ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                nOff++;
#endif
            }
            break;
        case ScanlineFormat::N24BitTcRgb:
            pReadScan = pBitmapReadAcc->GetScanline( nY );
            if( pAlphaReadAcc )
                if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                    bIsAlpha = true;

            for( nX = 0; nX < nWidth; nX++ )
            {
#ifdef OSL_BIGENDIAN
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff++ ];
                else
                    nAlpha = data[ nOff++ ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
#else
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff + 3 ];
                else
                    nAlpha = data[ nOff + 3 ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
                pReadScan += 3;
                nOff++;
#endif
            }
            break;
        case ScanlineFormat::N32BitTcBgra:
            pReadScan = pBitmapReadAcc->GetScanline( nY );
            if( pAlphaReadAcc )
                if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                    bIsAlpha = true;

            for( nX = 0; nX < nWidth; nX++ )
            {
#ifdef OSL_BIGENDIAN
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff++ ];
                else
                    nAlpha = data[ nOff++ ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
                pReadScan += 4;
#else
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff + 3 ];
                else
                    nAlpha = data[ nOff + 3 ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                pReadScan++;
                nOff++;
#endif
            }
            break;
        case ScanlineFormat::N32BitTcRgba:
            pReadScan = pBitmapReadAcc->GetScanline( nY );
            if( pAlphaReadAcc )
                if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                    bIsAlpha = true;

            for( nX = 0; nX < nWidth; nX++ )
            {
#ifdef OSL_BIGENDIAN
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff ++ ];
                else
                    nAlpha = data[ nOff ++ ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( *pReadScan++ ) )/255 );
                pReadScan++;
#else
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff + 3 ];
                else
                    nAlpha = data[ nOff + 3 ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 2 ] ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 1 ] ) )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*( pReadScan[ 0 ] ) )/255 );
                pReadScan += 4;
                nOff++;
#endif
            }
            break;
        default:
            SAL_INFO( "canvas.cairo", "fallback to GetColor - slow, format: " << static_cast<int>(pBitmapReadAcc->GetScanlineFormat()) );

            if( pAlphaReadAcc )
                if( readAlpha( pAlphaReadAcc, nY, nWidth, data, nOff ) )
                    bIsAlpha = true;

            for( nX = 0; nX < nWidth; nX++ )
            {
                aColor = pBitmapReadAcc->GetColor( nY, nX ).GetColor();

                // cairo need premultiplied color values
                // TODO(rodo) handle endianness
#ifdef OSL_BIGENDIAN
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff++ ];
                else
                    nAlpha = data[ nOff++ ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
#else
                if( pAlphaReadAcc )
                    nAlpha = data[ nOff + 3 ];
                else
                    nAlpha = data[ nOff + 3 ] = 255;
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetBlue() )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetGreen() )/255 );
                data[ nOff++ ] = sal::static_int_cast<unsigned char>(( nAlpha*aColor.GetRed() )/255 );
                nOff ++;
#endif
            }
        }
    }

    ::Bitmap::ReleaseAccess( pBitmapReadAcc );
    if( pAlphaReadAcc )
        aAlpha.ReleaseAccess( pAlphaReadAcc );

    bHasAlpha = bIsAlpha;

}

}} // end vcl::bitmap

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */