use same [un]premultiply

Change-Id: Idd1ca1243b64a9ec606382a0895e11376a2ec186
Reviewed-on: https://gerrit.libreoffice.org/64406
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/include/vcl/BitmapTools.hxx b/include/vcl/BitmapTools.hxx
index 6a8f6c8..ff43178 100644
--- a/include/vcl/BitmapTools.hxx
+++ b/include/vcl/BitmapTools.hxx
@@ -28,6 +28,11 @@ namespace com { namespace sun { namespace star { namespace geometry { struct Int
namespace vcl {
namespace bitmap {

typedef sal_uInt8 (*lookup_table)[256];

lookup_table VCL_DLLPUBLIC get_premultiply_table();
lookup_table VCL_DLLPUBLIC get_unpremultiply_table();

/**
 * Intended to be used to feed into CreateFromData to create a BitmapEx. RGB data format.
 */
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index ec01ec5..c936b0e 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -29,6 +29,7 @@

#include <sal/log.hxx>
#include <o3tl/safeint.hxx>
#include <vcl/BitmapTools.hxx>
#include <vcl/sysdata.hxx>
#include <config_cairo_canvas.h>
#include <basegfx/numeric/ftools.hxx>
@@ -1639,50 +1640,6 @@ void SvpSalGraphics::drawBitmap( const SalTwoRect& rTR,
    drawAlphaBitmap(rTR, rSourceBitmap, rTransparentBitmap);
}

static sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a)
{
    return (a == 0) ? 0 : (c * 255 + a / 2) / a;
}

static sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
{
    return (c * a + 127) / 255;
}

typedef sal_uInt8 (*lookup_table)[256];

static lookup_table get_unpremultiply_table()
{
    static bool inited;
    static sal_uInt8 unpremultiply_table[256][256];

    if (!inited)
    {
        for (int a = 0; a < 256; ++a)
            for (int c = 0; c < 256; ++c)
                unpremultiply_table[a][c] = unpremultiply(c, a);
        inited = true;
    }

    return unpremultiply_table;
}

static lookup_table get_premultiply_table()
{
    static bool inited;
    static sal_uInt8 premultiply_table[256][256];

    if (!inited)
    {
        for (int a = 0; a < 256; ++a)
            for (int c = 0; c < 256; ++c)
                premultiply_table[a][c] = premultiply(c, a);
        inited = true;
    }

    return premultiply_table;
}

void SvpSalGraphics::drawMask( const SalTwoRect& rTR,
                               const SalBitmap& rSalBitmap,
                               Color nMaskColor )
@@ -1697,7 +1654,7 @@ void SvpSalGraphics::drawMask( const SalTwoRect& rTR,
    }
    sal_Int32 nStride;
    unsigned char *mask_data = aSurface.getBits(nStride);
    lookup_table unpremultiply_table = get_unpremultiply_table();
    vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table();
    for (long y = rTR.mnSrcY ; y < rTR.mnSrcY + rTR.mnSrcHeight; ++y)
    {
        unsigned char *row = mask_data + (nStride*y);
@@ -1805,7 +1762,7 @@ Color SvpSalGraphics::getPixel( long nX, long nY )
    cairo_destroy(cr);

    cairo_surface_flush(target);
    lookup_table unpremultiply_table = get_unpremultiply_table();
    vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table();
    unsigned char *data = cairo_image_surface_get_data(target);
    sal_uInt8 a = data[SVP_CAIRO_ALPHA];
    sal_uInt8 b = unpremultiply_table[a][data[SVP_CAIRO_BLUE]];
@@ -2139,8 +2096,8 @@ void SvpSalGraphics::releaseCairoContext(cairo_t* cr, bool bXorModeAllowed, cons
        sal_Int32 nUnscaledExtentsRight = nExtentsRight * m_fScale;
        sal_Int32 nUnscaledExtentsTop = nExtentsTop * m_fScale;
        sal_Int32 nUnscaledExtentsBottom = nExtentsBottom * m_fScale;
        lookup_table unpremultiply_table = get_unpremultiply_table();
        lookup_table premultiply_table = get_premultiply_table();
        vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table();
        vcl::bitmap::lookup_table premultiply_table = vcl::bitmap::get_premultiply_table();
        for (sal_Int32 y = nUnscaledExtentsTop; y < nUnscaledExtentsBottom; ++y)
        {
            unsigned char *true_row = target_surface_data + (nStride*y);
diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx
index 317ef04..4bac9745 100644
--- a/vcl/source/bitmap/BitmapTools.cxx
+++ b/vcl/source/bitmap/BitmapTools.cxx
@@ -268,6 +268,7 @@ BitmapEx* CreateFromCairoSurface(Size aSize, cairo_surface_t * pSurface)
    cairo_surface_flush(pPixels);
    unsigned char *pSrc = cairo_image_surface_get_data( pPixels );
    unsigned int nStride = cairo_image_surface_get_stride( pPixels );
    vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table();
    for( unsigned long y = 0; y < static_cast<unsigned long>(aSize.Height()); y++ )
    {
        sal_uInt32 *pPix = reinterpret_cast<sal_uInt32 *>(pSrc + nStride * y);
@@ -287,9 +288,9 @@ BitmapEx* CreateFromCairoSurface(Size aSize, cairo_surface_t * pSurface)
            if( nAlpha != 0 && nAlpha != 255 )
            {
                // Cairo uses pre-multiplied alpha - we do not => re-multiply
                nR = static_cast<sal_uInt8>(MinMax( (static_cast<sal_uInt32>(nR) * 255) / nAlpha, 0, 255 ));
                nG = static_cast<sal_uInt8>(MinMax( (static_cast<sal_uInt32>(nG) * 255) / nAlpha, 0, 255 ));
                nB = static_cast<sal_uInt8>(MinMax( (static_cast<sal_uInt32>(nB) * 255) / nAlpha, 0, 255 ));
                nR = unpremultiply_table[nAlpha][nR];
                nG = unpremultiply_table[nAlpha][nG];
                nB = unpremultiply_table[nAlpha][nB];
            }
            pRGBWrite->SetPixel( y, x, BitmapColor( nR, nG, nB ) );
            pMaskWrite->SetPixelIndex( y, x, 255 - nAlpha );
@@ -726,6 +727,7 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
    ::Color aColor;
    unsigned int nAlpha = 255;

    vcl::bitmap::lookup_table premultiply_table = vcl::bitmap::get_premultiply_table();
    for( nY = 0; nY < nHeight; nY++ )
    {
        ::Scanline pReadScan;
@@ -754,13 +756,13 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
                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 );
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
#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 );
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
                nOff++;
#endif
            }
@@ -778,18 +780,18 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
                    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 );
                data[ nOff + 3 ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff + 2 ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff + 1 ] = premultiply_table[nAlpha][*pReadScan++];
                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 );
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                nOff++;
#endif
            }
@@ -807,17 +809,17 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
                    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 );
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*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 );
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
                pReadScan += 3;
                nOff++;
#endif
@@ -836,18 +838,18 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
                    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 );
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
                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 );
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                pReadScan++;
                nOff++;
#endif
@@ -866,18 +868,18 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
                    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 );
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                data[ nOff++ ] = premultiply_table[nAlpha][*pReadScan++];
                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 );
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 2 ]];
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 1 ]];
                data[ nOff++ ] = premultiply_table[nAlpha][pReadScan[ 0 ]];
                pReadScan += 4;
                nOff++;
#endif
@@ -901,17 +903,17 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
                    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 );
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
#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 );
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetBlue()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetGreen()];
                data[ nOff++ ] = premultiply_table[nAlpha][aColor.GetRed()];
                nOff ++;
#endif
            }
@@ -1044,6 +1046,49 @@ void CanvasCairoExtractBitmapData( BitmapEx const & aBmpEx, Bitmap & aBitmap, un
        return bRet;
    }

    static sal_uInt8 unpremultiply(sal_uInt8 c, sal_uInt8 a)
    {
        return (a == 0) ? 0 : (c * 255 + a / 2) / a;
    }

    static sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
    {
        return (c * a + 127) / 255;
    }

    lookup_table get_unpremultiply_table()
    {
        static bool inited;
        static sal_uInt8 unpremultiply_table[256][256];

        if (!inited)
        {
            for (int a = 0; a < 256; ++a)
                for (int c = 0; c < 256; ++c)
                    unpremultiply_table[a][c] = unpremultiply(c, a);
            inited = true;
        }

        return unpremultiply_table;
    }

    lookup_table get_premultiply_table()
    {
        static bool inited;
        static sal_uInt8 premultiply_table[256][256];

        if (!inited)
        {
            for (int a = 0; a < 256; ++a)
                for (int c = 0; c < 256; ++c)
                    premultiply_table[a][c] = premultiply(c, a);
            inited = true;
        }

        return premultiply_table;
    }


}} // end vcl::bitmap

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