tdf#157792 FILEOPEN: PPT: logo not displayed

regression from
    commit 3622404f09448b82c095256140afe6240b522ece
    Author: Noel Grandin <noel.grandin@collabora.co.uk>
    Date:   Wed Oct 11 12:54:43 2023 +0200
    tdf#157636 FILEOPEN: PPT: Images have no background

But actually from
    commit 81994cb2b8b32453a92bcb011830fcb884f22ffe
    Convert internal vcl bitmap formats transparency->alpha (II)

where BitmapEx::CombineMaskOr was not properly updated.

To make this stuff more obvious, add a version of CombineOr
called AlphaCombineOr that only operates on AlphaMask objects.

Change-Id: I8222bcdd7babefb748d21a71d02775c6a74bf068
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158085
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/include/vcl/alpha.hxx b/include/vcl/alpha.hxx
index d10d4dc..9c6b107 100644
--- a/include/vcl/alpha.hxx
+++ b/include/vcl/alpha.hxx
@@ -51,6 +51,15 @@ public:
    void        Erase( sal_uInt8 cTransparency );
    void        BlendWith(const AlphaMask& rOther);

    /** Perform boolean OR operation with another alpha-mask

        @param rMask
        The mask bitmap in the selected combine operation

        @return true, if the operation was completed successfully.
     */
    bool        AlphaCombineOr( const AlphaMask& rMask );

    // check if alpha is used, returns true if at least one pixel has transparence
    bool        hasAlpha() const;

diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx
index 9e5da1c..757cc89 100644
--- a/vcl/qa/cppunit/BitmapExTest.cxx
+++ b/vcl/qa/cppunit/BitmapExTest.cxx
@@ -25,12 +25,16 @@ class BitmapExTest : public CppUnit::TestFixture
    void testGetPixelColor32();
    void testTransformBitmapEx();
    void testAlphaBlendWith();
    void testCreateMask();
    void testCombineMaskOr();

    CPPUNIT_TEST_SUITE(BitmapExTest);
    CPPUNIT_TEST(testGetPixelColor24_8);
    CPPUNIT_TEST(testGetPixelColor32);
    CPPUNIT_TEST(testTransformBitmapEx);
    CPPUNIT_TEST(testAlphaBlendWith);
    CPPUNIT_TEST(testCreateMask);
    CPPUNIT_TEST(testCombineMaskOr);
    CPPUNIT_TEST_SUITE_END();
};

@@ -167,6 +171,79 @@ void BitmapExTest::testAlphaBlendWith()
                         AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
}

void BitmapExTest::testCreateMask()
{
    Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP);
    {
        BitmapScopedWriteAccess pWriteAccess(aBitmap);
        pWriteAccess->Erase(COL_WHITE);
        for (int i = 0; i < 3; ++i)
            pWriteAccess->SetPixel(i, i, COL_RED);
    }
    aBitmap = aBitmap.CreateMask(COL_RED, 1);
    Bitmap::ScopedReadAccess pAccess(aBitmap);
    // the output is a greyscale palette bitmap
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 0));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(0, 1));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(0, 2));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 0));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(1, 1));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 2));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(2, 0));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(2, 1));
    CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 2));
}

void BitmapExTest::testCombineMaskOr()
{
    Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N24_BPP);
    {
        BitmapScopedWriteAccess pWriteAccess(aBitmap);
        pWriteAccess->Erase(COL_WHITE);
        for (int i = 0; i < 3; ++i)
            pWriteAccess->SetPixel(1, i, COL_RED);
    }
    AlphaMask aAlphaBitmap(Size(3, 3));
    {
        BitmapScopedWriteAccess pWriteAccess(aAlphaBitmap);
        pWriteAccess->Erase(Color(0xff, 0xff, 0xff));
        for (int i = 1; i < 3; ++i)
        {
            pWriteAccess->SetPixel(i, 0, Color(0x00, 0x00, 0x00));
            pWriteAccess->SetPixel(i, 1, Color(0x80, 0x80, 0x80));
            pWriteAccess->SetPixel(i, 0, Color(0xef, 0xef, 0xef));
        }
    }

    {
        AlphaMask aMask = aBitmap.CreateAlphaMask(COL_RED, 1);
        Bitmap::ScopedReadAccess pAccess(aMask);
        // the output is a greyscale palette bitmap
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 0));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 1));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(0, 2));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 0));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 1));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0x00), pAccess->GetPixelIndex(1, 2));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 0));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 1));
        CPPUNIT_ASSERT_EQUAL(sal_uInt8(0xff), pAccess->GetPixelIndex(2, 2));
    }

    BitmapEx aBitmapEx(aBitmap, aAlphaBitmap);
    aBitmapEx.CombineMaskOr(COL_RED, 1);

    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), aBitmapEx.GetPixelColor(0, 0));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x80, 0x00, 0x00), aBitmapEx.GetPixelColor(0, 1));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0xff, 0xff, 0xff), aBitmapEx.GetPixelColor(0, 2));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), aBitmapEx.GetPixelColor(1, 0));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x80, 0x00, 0x00), aBitmapEx.GetPixelColor(1, 1));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0xff, 0xff, 0xff), aBitmapEx.GetPixelColor(1, 2));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), aBitmapEx.GetPixelColor(2, 0));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x80, 0x00, 0x00), aBitmapEx.GetPixelColor(2, 1));
    CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), aBitmapEx.GetPixelColor(2, 2));
}

} // namespace

CPPUNIT_TEST_SUITE_REGISTRATION(BitmapExTest);
diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx
index 7333aea..5608254 100644
--- a/vcl/source/bitmap/BitmapEx.cxx
+++ b/vcl/source/bitmap/BitmapEx.cxx
@@ -1444,10 +1444,9 @@ void BitmapEx::AdjustTransparency(sal_uInt8 cTrans)

void BitmapEx::CombineMaskOr(Color maskColor, sal_uInt8 nTol)
{
    Bitmap aNewMask = maBitmap.CreateMask( maskColor, nTol );
    AlphaMask aNewMask = maBitmap.CreateAlphaMask( maskColor, nTol );
    if ( IsAlpha() )
         aNewMask.CombineOr( maAlphaMask );
    aNewMask.Invert();
         aNewMask.AlphaCombineOr( maAlphaMask );
    maAlphaMask = aNewMask;
}

diff --git a/vcl/source/bitmap/alpha.cxx b/vcl/source/bitmap/alpha.cxx
index cb8be28..005edbe 100644
--- a/vcl/source/bitmap/alpha.cxx
+++ b/vcl/source/bitmap/alpha.cxx
@@ -182,4 +182,35 @@ void AlphaMask::ReleaseAccess( BitmapReadAccess* pAccess )
    assert( HasGreyPalette8Bit() && "alpha bitmap should have greyscale palette" );
}

bool AlphaMask::AlphaCombineOr(const AlphaMask& rMask)
{
    ScopedReadAccess pMaskAcc(const_cast<AlphaMask&>(rMask));
    AlphaScopedWriteAccess pAcc(*this);

    if (!pMaskAcc || !pAcc)
        return false;

    assert (pMaskAcc->GetBitCount() == 8 && pAcc->GetBitCount() == 8);

    const tools::Long nWidth = std::min(pMaskAcc->Width(), pAcc->Width());
    const tools::Long nHeight = std::min(pMaskAcc->Height(), pAcc->Height());

    for (tools::Long nY = 0; nY < nHeight; nY++)
    {
        Scanline pScanline = pAcc->GetScanline(nY);
        ConstScanline pScanlineMask = pMaskAcc->GetScanline(nY);
        for (tools::Long nX = 0; nX < nWidth; nX++)
        {
            if (*pScanlineMask != 255 || *pScanline != 255)
                *pScanline = 0;
            else
                *pScanline = 255;
            ++pScanline;
            ++pScanlineMask;
        }
    }

    return true;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/bitmap/bitmappaint.cxx b/vcl/source/bitmap/bitmappaint.cxx
index dc4fda1..f3e51dd 100644
--- a/vcl/source/bitmap/bitmappaint.cxx
+++ b/vcl/source/bitmap/bitmappaint.cxx
@@ -1164,6 +1164,9 @@ bool Bitmap::Replace(const Color* pSearchColors, const Color* pReplaceColors, si

bool Bitmap::CombineOr(const Bitmap& rMask)
{
    assert(!dynamic_cast<AlphaMask*>(this) && "should rather be calling AlphaMask::AlphaCombineOr");
    assert(!dynamic_cast<const AlphaMask*>(&rMask)
           && "should rather be calling AlphaMask::AlphaCombineOr");
    ScopedReadAccess pMaskAcc(const_cast<Bitmap&>(rMask));
    BitmapScopedWriteAccess pAcc(*this);