include/vcl/bitmap.hxx       |    2 -
 vcl/headless/svpbmp.cxx      |   13 ++-------
 vcl/inc/headless/svpbmp.hxx  |    2 -
 vcl/inc/qt5/QtBitmap.hxx     |    2 -
 vcl/inc/quartz/salbmp.h      |    2 -
 vcl/inc/salbmp.hxx           |    3 +-
 vcl/inc/skia/salbmp.hxx      |    2 -
 vcl/inc/win/salbmp.h         |    2 -
 vcl/qt5/QtBitmap.cxx         |   36 +++++++++++++++++---------
 vcl/quartz/salbmp.cxx        |   32 ++++++++++-------------
 vcl/skia/salbmp.cxx          |   59 +++++++++++++++++++++----------------------
 vcl/source/bitmap/bitmap.cxx |   16 +++++++++++
 vcl/source/bitmap/salbmp.cxx |   22 ++++++++++++++++
 vcl/win/gdi/salbmp.cxx       |   24 ++++++++++++++---
 14 files changed, 137 insertions(+), 80 deletions(-)

New commits:
commit 18b488deededee4b62b3c041c8db84452ad72b55
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Tue Aug 26 21:26:33 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Wed Aug 27 07:39:21 2025 +0200

    Make Bitmap::HasAlpha() more reliable
    
    checking for 32-bit format is not sufficient when there are 32-bit
    formats which do not have actual alpha data.
    
    Change the SalBitmap backend interface to return ScanlineFormat
    rather than BitCount, to give a more reliable picture.
    
    Change-Id: I6dde931a05415a9fbe0e8e696173b58e744b0e0c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190242
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index 2267c08d4e5a..8788a718f001 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -142,7 +142,7 @@ public:
     bool                    HasGreyPalette8Bit() const;
     bool                    HasGreyPaletteAny() const;
     // does this bitmap have alpha information?
-    inline bool             HasAlpha() const { return getPixelFormat() == 
vcl::PixelFormat::N32_BPP; }
+    bool                    HasAlpha() const;
 
     /** return the alpha data, copied into an AlphaMask. Will assert if this 
Bitmap has no alpha. */
     AlphaMask               CreateAlphaMask() const;
diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx
index b1ef601e80e7..314269c1a01e 100644
--- a/vcl/headless/svpbmp.cxx
+++ b/vcl/headless/svpbmp.cxx
@@ -223,16 +223,11 @@ Size SvpSalBitmap::GetSize() const
     return aSize;
 }
 
-sal_uInt16 SvpSalBitmap::GetBitCount() const
+ScanlineFormat SvpSalBitmap::GetScanlineFormat() const
 {
-    sal_uInt16 nBitCount;
-
-    if (moDIB.has_value())
-        nBitCount = moDIB->mnBitCount;
-    else
-        nBitCount = 0;
-
-    return nBitCount;
+    if (!moDIB.has_value())
+        return ScanlineFormat::NONE;
+    return moDIB->meFormat;
 }
 
 BitmapBuffer* SvpSalBitmap::AcquireBuffer(BitmapAccessMode)
diff --git a/vcl/inc/headless/svpbmp.hxx b/vcl/inc/headless/svpbmp.hxx
index 53756e25c58e..b650626bf0e1 100644
--- a/vcl/inc/headless/svpbmp.hxx
+++ b/vcl/inc/headless/svpbmp.hxx
@@ -55,7 +55,7 @@ public:
     }
     SAL_DLLPRIVATE virtual void            Destroy() final override;
     SAL_DLLPRIVATE virtual Size            GetSize() const override;
-    SAL_DLLPRIVATE virtual sal_uInt16      GetBitCount() const override;
+    SAL_DLLPRIVATE virtual ScanlineFormat  GetScanlineFormat() const override;
 
     SAL_DLLPRIVATE virtual BitmapBuffer*   AcquireBuffer( BitmapAccessMode 
nMode ) override;
     SAL_DLLPRIVATE virtual void            ReleaseBuffer( BitmapBuffer* 
pBuffer, BitmapAccessMode nMode ) override;
diff --git a/vcl/inc/qt5/QtBitmap.hxx b/vcl/inc/qt5/QtBitmap.hxx
index 1005bfe5f429..6e6c82ba8fc9 100644
--- a/vcl/inc/qt5/QtBitmap.hxx
+++ b/vcl/inc/qt5/QtBitmap.hxx
@@ -45,7 +45,7 @@ public:
                         Size& rSize) override;
     virtual void Destroy() final override;
     virtual Size GetSize() const override;
-    virtual sal_uInt16 GetBitCount() const override;
+    virtual ScanlineFormat GetScanlineFormat() const override;
 
     virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override;
     virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) 
override;
diff --git a/vcl/inc/quartz/salbmp.h b/vcl/inc/quartz/salbmp.h
index c0b30184c7c0..7ada1f6829f1 100644
--- a/vcl/inc/quartz/salbmp.h
+++ b/vcl/inc/quartz/salbmp.h
@@ -66,7 +66,7 @@ public:
     void            Destroy() override;
 
     Size            GetSize() const override;
-    sal_uInt16          GetBitCount() const override;
+    ScanlineFormat  GetScanlineFormat() const override;
 
     BitmapBuffer   *AcquireBuffer( BitmapAccessMode nMode ) override;
     void            ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode 
nMode ) override;
diff --git a/vcl/inc/salbmp.hxx b/vcl/inc/salbmp.hxx
index 2b1d8e479bf4..441f630da167 100644
--- a/vcl/inc/salbmp.hxx
+++ b/vcl/inc/salbmp.hxx
@@ -71,7 +71,8 @@ public:
                                     Size& rSize ) = 0;
     virtual void            Destroy() = 0;
     virtual Size            GetSize() const = 0;
-    virtual sal_uInt16      GetBitCount() const = 0;
+    sal_uInt16              GetBitCount() const;
+    virtual ScanlineFormat  GetScanlineFormat() const = 0;
 
     virtual BitmapBuffer*   AcquireBuffer( BitmapAccessMode nMode ) = 0;
     virtual void            ReleaseBuffer( BitmapBuffer* pBuffer, 
BitmapAccessMode nMode ) = 0;
diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index f9459dbff2c9..0212705c0e3e 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -47,7 +47,7 @@ public:
     virtual void Destroy() final override;
 
     virtual Size GetSize() const override;
-    virtual sal_uInt16 GetBitCount() const override;
+    virtual ScanlineFormat GetScanlineFormat() const override;
 
     virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override;
     virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) 
override;
diff --git a/vcl/inc/win/salbmp.h b/vcl/inc/win/salbmp.h
index b7a5a1947a2b..4ad38ecbec15 100644
--- a/vcl/inc/win/salbmp.h
+++ b/vcl/inc/win/salbmp.h
@@ -81,7 +81,7 @@ public:
     virtual void                Destroy() override;
 
     virtual Size                GetSize() const override { return maSize; }
-    virtual sal_uInt16          GetBitCount() const override { return 
mnBitCount; }
+    virtual ScanlineFormat      GetScanlineFormat() const override;
 
     virtual BitmapBuffer*       AcquireBuffer( BitmapAccessMode nMode ) 
override;
     virtual void                ReleaseBuffer( BitmapBuffer* pBuffer, 
BitmapAccessMode nMode ) override;
diff --git a/vcl/qt5/QtBitmap.cxx b/vcl/qt5/QtBitmap.cxx
index 53277649d774..643208b23c5d 100644
--- a/vcl/qt5/QtBitmap.cxx
+++ b/vcl/qt5/QtBitmap.cxx
@@ -96,11 +96,30 @@ Size QtBitmap::GetSize() const
     return Size();
 }
 
-sal_uInt16 QtBitmap::GetBitCount() const
+ScanlineFormat QtBitmap::GetScanlineFormat() const
 {
-    if (m_pImage)
-        return getFormatBits(m_pImage->format());
-    return 0;
+    if (!m_pImage)
+        return ScanlineFormat::NONE;
+    auto nBits = getFormatBits(m_pImage->format());
+    switch (nBits)
+    {
+        case 1:
+            return ScanlineFormat::N1BitMsbPal;
+        case 8:
+            return ScanlineFormat::N8BitPal;
+        case 24:
+            return ScanlineFormat::N24BitTcRgb;
+        case 32:
+        {
+#ifdef OSL_BIGENDIAN
+            return ScanlineFormat::N32BitTcArgb;
+#else
+            return ScanlineFormat::N32BitTcBgra;
+#endif
+        }
+        default:
+            abort();
+    }
 }
 
 BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode /*nMode*/)
@@ -118,28 +137,21 @@ BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode 
/*nMode*/)
     pBuffer->mpBits = m_pImage->bits();
     pBuffer->mnScanlineSize = m_pImage->bytesPerLine();
     pBuffer->meDirection = ScanlineDirection::TopDown;
+    pBuffer->meFormat = GetScanlineFormat();
 
     switch (pBuffer->mnBitCount)
     {
         case 1:
-            pBuffer->meFormat = ScanlineFormat::N1BitMsbPal;
             pBuffer->maPalette = m_aPalette;
             break;
         case 8:
-            pBuffer->meFormat = ScanlineFormat::N8BitPal;
             pBuffer->maPalette = m_aPalette;
             break;
         case 24:
-            pBuffer->meFormat = ScanlineFormat::N24BitTcRgb;
             pBuffer->maPalette = aEmptyPalette;
             break;
         case 32:
         {
-#ifdef OSL_BIGENDIAN
-            pBuffer->meFormat = ScanlineFormat::N32BitTcArgb;
-#else
-            pBuffer->meFormat = ScanlineFormat::N32BitTcBgra;
-#endif
             pBuffer->maPalette = aEmptyPalette;
             break;
         }
diff --git a/vcl/quartz/salbmp.cxx b/vcl/quartz/salbmp.cxx
index 725aa5574996..e65de0090e4d 100644
--- a/vcl/quartz/salbmp.cxx
+++ b/vcl/quartz/salbmp.cxx
@@ -320,9 +320,20 @@ Size QuartzSalBitmap::GetSize() const
     return Size( mnWidth, mnHeight );
 }
 
-sal_uInt16 QuartzSalBitmap::GetBitCount() const
+ScanlineFormat QuartzSalBitmap::GetScanlineFormat() const
 {
-    return mnBits;
+    switch( mnBits )
+    {
+        case 1:
+            return ScanlineFormat::N1BitMsbPal;
+        case 8:
+            return ScanlineFormat::N8BitPal;
+        case 24:
+            return ScanlineFormat::N24BitTcBgr;
+        case 32:
+            return ScanlineFormat::N32BitTcArgb;
+        default: abort();
+    }
 }
 
 namespace {
@@ -427,22 +438,7 @@ BitmapBuffer* QuartzSalBitmap::AcquireBuffer( 
BitmapAccessMode /*nMode*/ )
     pBuffer->mnScanlineSize = mnBytesPerRow;
     pBuffer->mpBits = m_pUserBuffer.get();
     pBuffer->mnBitCount = mnBits;
-    switch( mnBits )
-    {
-        case 1:
-            pBuffer->meFormat = ScanlineFormat::N1BitMsbPal;
-            break;
-        case 8:
-            pBuffer->meFormat = ScanlineFormat::N8BitPal;
-            break;
-        case 24:
-            pBuffer->meFormat = ScanlineFormat::N24BitTcBgr;
-            break;
-        case 32:
-            pBuffer->meFormat = ScanlineFormat::N32BitTcArgb;
-            break;
-        default: assert(false);
-    }
+    pBuffer->meFormat = GetScanlineFormat();
 
     // some BitmapBuffer users depend on a complete palette
     if( (mnBits <= 8) && !maPalette )
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index ddea043133a4..16cfb2b1c994 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -201,7 +201,34 @@ void SkiaSalBitmap::Destroy()
 
 Size SkiaSalBitmap::GetSize() const { return mSize; }
 
-sal_uInt16 SkiaSalBitmap::GetBitCount() const { return mBitCount; }
+ScanlineFormat SkiaSalBitmap::GetScanlineFormat() const
+{
+    switch (mBitCount)
+    {
+        case 1:
+            return ScanlineFormat::N1BitMsbPal;
+        case 8:
+            return ScanlineFormat::N8BitPal;
+        case 24:
+            // Make the RGB/BGR format match the default Skia 32bpp format, to 
allow
+            // easy conversion later.
+            return kN32_SkColorTypeIsBGRA ? ScanlineFormat::N24BitTcBgr
+                                          : ScanlineFormat::N24BitTcRgb;
+        case 32:
+            if (m_bWithoutAlpha)
+            {
+                return kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgrx
+                                              : ScanlineFormat::N32BitTcRgbx;
+            }
+            else
+            {
+                return kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgra
+                                              : ScanlineFormat::N32BitTcRgba;
+            }
+        default:
+            abort();
+    }
+}
 
 BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
 {
@@ -282,35 +309,7 @@ BitmapBuffer* 
SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
         mPixelsSize = savedPixelsSize;
         ComputeScanlineSize();
     }
-    switch (mBitCount)
-    {
-        case 1:
-            buffer->meFormat = ScanlineFormat::N1BitMsbPal;
-            break;
-        case 8:
-            buffer->meFormat = ScanlineFormat::N8BitPal;
-            break;
-        case 24:
-            // Make the RGB/BGR format match the default Skia 32bpp format, to 
allow
-            // easy conversion later.
-            buffer->meFormat = kN32_SkColorTypeIsBGRA ? 
ScanlineFormat::N24BitTcBgr
-                                                      : 
ScanlineFormat::N24BitTcRgb;
-            break;
-        case 32:
-            if (m_bWithoutAlpha)
-            {
-                buffer->meFormat = kN32_SkColorTypeIsBGRA ? 
ScanlineFormat::N32BitTcBgrx
-                                                          : 
ScanlineFormat::N32BitTcRgbx;
-            }
-            else
-            {
-                buffer->meFormat = kN32_SkColorTypeIsBGRA ? 
ScanlineFormat::N32BitTcBgra
-                                                          : 
ScanlineFormat::N32BitTcRgba;
-            }
-            break;
-        default:
-            abort();
-    }
+    buffer->meFormat = GetScanlineFormat();
     buffer->meDirection = ScanlineDirection::TopDown;
     // Refcount all read/write accesses, to catch problems with existing 
accesses while
     // a bitmap changes, and also to detect when we can free mBuffer if wanted.
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
index e41c571ce176..e5d8f81a8102 100644
--- a/vcl/source/bitmap/bitmap.cxx
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -353,6 +353,22 @@ vcl::PixelFormat Bitmap::getPixelFormat() const
     return vcl::PixelFormat::INVALID;
 }
 
+bool Bitmap::HasAlpha() const
+{
+    if (!mxSalBmp)
+        return false;
+    switch(mxSalBmp->GetScanlineFormat())
+    {
+        case ScanlineFormat::N32BitTcAbgr:
+        case ScanlineFormat::N32BitTcArgb:
+        case ScanlineFormat::N32BitTcBgra:
+        case ScanlineFormat::N32BitTcRgba:
+            return true;
+        default:
+            return false;
+    }
+}
+
 bool Bitmap::HasGreyPaletteAny() const
 {
     bool bRet = false;
diff --git a/vcl/source/bitmap/salbmp.cxx b/vcl/source/bitmap/salbmp.cxx
index 6148e2ee3a48..fec5751e3e1f 100644
--- a/vcl/source/bitmap/salbmp.cxx
+++ b/vcl/source/bitmap/salbmp.cxx
@@ -85,6 +85,28 @@ void SalBitmap::updateChecksum() const
     }
 }
 
+sal_uInt16 SalBitmap::GetBitCount() const
+{
+    switch (GetScanlineFormat())
+    {
+        case ScanlineFormat::NONE: return 0;
+        case ScanlineFormat::N1BitMsbPal: return 1;
+        case ScanlineFormat::N8BitPal: return 8;
+        case ScanlineFormat::N24BitTcBgr: return 24;
+        case ScanlineFormat::N24BitTcRgb: return 24;
+        case ScanlineFormat::N32BitTcAbgr:
+        case ScanlineFormat::N32BitTcXbgr:
+        case ScanlineFormat::N32BitTcArgb:
+        case ScanlineFormat::N32BitTcXrgb:
+        case ScanlineFormat::N32BitTcBgra:
+        case ScanlineFormat::N32BitTcBgrx:
+        case ScanlineFormat::N32BitTcRgba:
+        case ScanlineFormat::N32BitTcRgbx:
+            return 32;
+        default: abort();
+    }
+}
+
 namespace
 {
 
diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx
index 3475377351d1..b3d7ea40fa08 100644
--- a/vcl/win/gdi/salbmp.cxx
+++ b/vcl/win/gdi/salbmp.cxx
@@ -730,6 +730,25 @@ void* WinSalBitmap::ImplCopyDIB( void* pDIB, sal_Int32 
nSize )
     return pCopy;
 }
 
+ScanlineFormat WinSalBitmap::GetScanlineFormat() const
+{
+    if (!mpDIB)
+        return ScanlineFormat::NONE;
+
+    PBITMAPINFO pBI = static_cast<PBITMAPINFO>(mpDIB);
+    if (!pBI)
+        return ScanlineFormat::NONE;
+
+    PBITMAPINFOHEADER pBIH = &pBI->bmiHeader;
+    if( pBIH->biPlanes != 1 )
+        return ScanlineFormat::NONE;
+
+    return pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
+           pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr :
+           pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcBgra :
+           ScanlineFormat::NONE;
+}
+
 BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
 {
     if (!mpDIB)
@@ -746,10 +765,7 @@ BitmapBuffer* WinSalBitmap::AcquireBuffer( 
BitmapAccessMode /*nMode*/ )
     {
         pBuffer.reset(new BitmapBuffer);
 
-        pBuffer->meFormat = pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
-                            pBIH->biBitCount == 24 ? 
ScanlineFormat::N24BitTcBgr :
-                            pBIH->biBitCount == 32 ? 
ScanlineFormat::N32BitTcBgra :
-                            ScanlineFormat::NONE;
+        pBuffer->meFormat = GetScanlineFormat();
         assert (pBuffer->meFormat != ScanlineFormat::NONE);
 
         if (pBuffer->meFormat != ScanlineFormat::NONE)

Reply via email to