/*
* 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 <svsys.h>
#include <vcl/bitmap.hxx>
#include <vcl/salbtype.hxx>
#include <com/sun/star/beans/XFastPropertySet.hpp>
#include <win/wincomp.hxx>
#include <win/salgdi.h>
#include <win/saldata.hxx>
#include <win/salbmp.h>
#include <string.h>
#include <vcl/timer.hxx>
#include <cppuhelper/basemutex.hxx>
#include <sal/log.hxx>
#include <map>
#if defined _MSC_VER
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#endif
#include <prewin.h>
#include <gdiplus.h>
#include <postwin.h>
#if defined _MSC_VER
#undef min
#undef max
#endif
inline void ImplSetPixel4( sal_uInt8* pScanline, long nX, const BYTE cIndex )
{
BYTE& rByte = pScanline[ nX >> 1 ];
if ( nX & 1 )
{
rByte &= 0xf0;
rByte |= cIndex & 0x0f;
}
else
{
rByte &= 0x0f;
rByte |= cIndex << 4;
}
}
WinSalBitmap::WinSalBitmap()
: SalBitmap(),
basegfx::SystemDependentDataHolder(),
maSize(),
mhDIB(nullptr),
mhDDB(nullptr),
mnBitCount(0)
{
}
WinSalBitmap::~WinSalBitmap()
{
Destroy();
}
void WinSalBitmap::Destroy()
{
if( mhDIB )
GlobalFree( mhDIB );
else if( mhDDB )
DeleteObject( mhDDB );
maSize = Size();
mnBitCount = 0;
}
class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData
{
private:
std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap;
const WinSalBitmap* mpAssociatedAlpha;
public:
SystemDependentData_GdiPlusBitmap(
basegfx::SystemDependentDataManager& rSystemDependentDataManager);
const WinSalBitmap* getAssociatedAlpha() const { return mpAssociatedAlpha; }
void setAssociatedAlpha(const WinSalBitmap* pNew) { mpAssociatedAlpha = pNew; }
const std::shared_ptr<Gdiplus::Bitmap>& getGdiPlusBitmap() const { return mpGdiPlusBitmap; }
void setGdiPlusBitmap(const std::shared_ptr<Gdiplus::Bitmap>& rNew) { mpGdiPlusBitmap = rNew; }
};
SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap(
basegfx::SystemDependentDataManager& rSystemDependentDataManager)
: basegfx::SystemDependentData(rSystemDependentDataManager),
mpGdiPlusBitmap(),
mpAssociatedAlpha(nullptr)
{
}
std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
{
std::shared_ptr< Gdiplus::Bitmap > aRetval;
// try to access buffered data
std::shared_ptr<SystemDependentData_GdiPlusBitmap> pSystemDependentData_GdiPlusBitmap(
getSystemDependentData<SystemDependentData_GdiPlusBitmap>());
if(pSystemDependentData_GdiPlusBitmap)
{
// check data validity
if(pSystemDependentData_GdiPlusBitmap->getAssociatedAlpha() != pAlphaSource
|| 0 == maSize.Width()
|| 0 == maSize.Height())
{
// #122350# if associated alpha with which the GDIPlus was constructed has changed
// it is necessary to remove it from buffer, reset reference to it and reconstruct
// data invalid, forget
pSystemDependentData_GdiPlusBitmap.reset();
}
}
if(pSystemDependentData_GdiPlusBitmap)
{
// use from buffer
aRetval = pSystemDependentData_GdiPlusBitmap->getGdiPlusBitmap();
}
else if(maSize.Width() > 0 && maSize.Height() > 0)
{
// add to buffering mechanism
pSystemDependentData_GdiPlusBitmap = addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>(
ImplGetSystemDependentDataManager());
// create and set data
if(pAlphaSource)
{
aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource));
pSystemDependentData_GdiPlusBitmap->setGdiPlusBitmap(aRetval);
pSystemDependentData_GdiPlusBitmap->setAssociatedAlpha(pAlphaSource);
}
else
{
aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap());
pSystemDependentData_GdiPlusBitmap->setGdiPlusBitmap(aRetval);
pSystemDependentData_GdiPlusBitmap->setAssociatedAlpha(nullptr);
}
}
return aRetval;
}
Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap()
{
Gdiplus::Bitmap* pRetval(nullptr);
WinSalBitmap* pSalRGB = this;
WinSalBitmap* pExtraWinSalRGB = nullptr;
if(!pSalRGB->ImplGethDIB())
{
// we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
pExtraWinSalRGB = new WinSalBitmap();
pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
pSalRGB = pExtraWinSalRGB;
}
BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BitmapAccessMode::Read);
std::unique_ptr<BitmapBuffer> pExtraRGB;
if(pRGB && ScanlineFormat::N24BitTcBgr != (pRGB->mnFormat & ~ScanlineFormat::TopDown))
{
// convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
pExtraRGB = StretchAndConvert(
*pRGB,
aSalTwoRect,
ScanlineFormat::N24BitTcBgr);
pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Write);
pRGB = pExtraRGB.get();
}
if(pRGB
&& pRGB->mnWidth > 0
&& pRGB->mnHeight > 0
&& ScanlineFormat::N24BitTcBgr == (pRGB->mnFormat & ~ScanlineFormat::TopDown))
{
const sal_uInt32 nW(pRGB->mnWidth);
const sal_uInt32 nH(pRGB->mnHeight);
pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB);
if ( pRetval->GetLastStatus() == Gdiplus::Ok )
{
sal_uInt8* pSrcRGB(pRGB->mpBits);
const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
const bool bTopDown(pRGB->mnFormat & ScanlineFormat::TopDown);
const Gdiplus::Rect aAllRect(0, 0, nW, nH);
Gdiplus::BitmapData aGdiPlusBitmapData;
pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &aGdiPlusBitmapData);
// copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
for(sal_uInt32 y(0); y < nH; y++)
{
const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
sal_uInt8* targetPixels = static_cast<sal_uInt8*>(aGdiPlusBitmapData.Scan0) + (nYInsert * aGdiPlusBitmapData.Stride);
memcpy(targetPixels, pSrcRGB, nW * 3);
pSrcRGB += nW * 3 + nExtraRGB;
}
pRetval->UnlockBits(&aGdiPlusBitmapData);
}
else
{
delete pRetval;
pRetval = nullptr;
}
}
if(pExtraRGB)
{
// #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
// in its destructor, this *has to be done by hand*. Doing it here now
delete[] pExtraRGB->mpBits;
pExtraRGB.reset();
}
else
{
pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
}
if(pExtraWinSalRGB)
{
delete pExtraWinSalRGB;
}
return pRetval;
}
Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
{
Gdiplus::Bitmap* pRetval(nullptr);
WinSalBitmap* pSalRGB = this;
WinSalBitmap* pExtraWinSalRGB = nullptr;
if(!pSalRGB->ImplGethDIB())
{
// we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
pExtraWinSalRGB = new WinSalBitmap();
pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
pSalRGB = pExtraWinSalRGB;
}
BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BitmapAccessMode::Read);
std::unique_ptr<BitmapBuffer> pExtraRGB;
if(pRGB && ScanlineFormat::N24BitTcBgr != (pRGB->mnFormat & ~ScanlineFormat::TopDown))
{
// convert source bitmap to canlineFormat::N24BitTcBgr format if not yet in that format
SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
pExtraRGB = StretchAndConvert(
*pRGB,
aSalTwoRect,
ScanlineFormat::N24BitTcBgr);
pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
pRGB = pExtraRGB.get();
}
WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
WinSalBitmap* pExtraWinSalA = nullptr;
if(!pSalA->ImplGethDIB())
{
// we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
pExtraWinSalA = new WinSalBitmap();
pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount());
pSalA = pExtraWinSalA;
}
BitmapBuffer* pA = pSalA->AcquireBuffer(BitmapAccessMode::Read);
std::unique_ptr<BitmapBuffer> pExtraA;
if(pA && ScanlineFormat::N8BitPal != (pA->mnFormat & ~ScanlineFormat::TopDown))
{
// convert alpha bitmap to ScanlineFormat::N8BitPal format if not yet in that format
SalTwoRect aSalTwoRect(0, 0, pA->mnWidth, pA->mnHeight, 0, 0, pA->mnWidth, pA->mnHeight);
const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
pExtraA = StretchAndConvert(
*pA,
aSalTwoRect,
ScanlineFormat::N8BitPal,
&rTargetPalette);
pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
pA = pExtraA.get();
}
if(pRGB
&& pA
&& pRGB->mnWidth > 0
&& pRGB->mnHeight > 0
&& pRGB->mnWidth == pA->mnWidth
&& pRGB->mnHeight == pA->mnHeight
&& ScanlineFormat::N24BitTcBgr == (pRGB->mnFormat & ~ScanlineFormat::TopDown)
&& ScanlineFormat::N8BitPal == (pA->mnFormat & ~ScanlineFormat::TopDown))
{
// we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
const sal_uInt32 nW(pRGB->mnWidth);
const sal_uInt32 nH(pRGB->mnHeight);
pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB);
if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
{
sal_uInt8* pSrcRGB(pRGB->mpBits);
sal_uInt8* pSrcA(pA->mpBits);
const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
const bool bTopDown(pRGB->mnFormat & ScanlineFormat::TopDown);
const Gdiplus::Rect aAllRect(0, 0, nW, nH);
Gdiplus::BitmapData aGdiPlusBitmapData;
pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
// copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
// A from alpha, so inner loop is needed (who invented BitmapEx..?)
for(sal_uInt32 y(0); y < nH; y++)
{
const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
sal_uInt8* targetPixels = static_cast<sal_uInt8*>(aGdiPlusBitmapData.Scan0) + (nYInsert * aGdiPlusBitmapData.Stride);
for(sal_uInt32 x(0); x < nW; x++)
{
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = *pSrcRGB++;
*targetPixels++ = 0xff - *pSrcA++;
}
pSrcRGB += nExtraRGB;
pSrcA += nExtraA;
}
pRetval->UnlockBits(&aGdiPlusBitmapData);
}
else
{
delete pRetval;
pRetval = nullptr;
}
}
if(pExtraA)
{
// #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
// in its destructor, this *has to be done handish*. Doing it here now
delete[] pExtraA->mpBits;
pExtraA.reset();
}
else
{
pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
}
if(pExtraWinSalA)
{
delete pExtraWinSalA;
}
if(pExtraRGB)
{
// #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
// in its destructor, this *has to be done by hand*. Doing it here now
delete[] pExtraRGB->mpBits;
pExtraRGB.reset();
}
else
{
pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
}
if(pExtraWinSalRGB)
{
delete pExtraWinSalRGB;
}
return pRetval;
}
bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
{
bool bRet = TRUE;
if( bDIB )
mhDIB = static_cast<HGLOBAL>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, true ) : hBitmap );
else
mhDDB = static_cast<HBITMAP>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, false ) : hBitmap );
if( mhDIB )
{
PBITMAPINFOHEADER pBIH = static_cast<PBITMAPINFOHEADER>(GlobalLock( mhDIB ));
maSize = Size( pBIH->biWidth, pBIH->biHeight );
mnBitCount = pBIH->biBitCount;
if( mnBitCount )
mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
GlobalUnlock( mhDIB );
}
else if( mhDDB )
{
BITMAP aDDBInfo;
if( GetObjectW( mhDDB, sizeof( aDDBInfo ), &aDDBInfo ) )
{
maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
if( mnBitCount )
{
mnBitCount = ( mnBitCount <= 1 ) ? 1 :
( mnBitCount <= 4 ) ? 4 :
( mnBitCount <= 8 ) ? 8 : 24;
}
}
else
{
mhDDB = nullptr;
bRet = FALSE;
}
}
else
bRet = FALSE;
return bRet;
}
bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
{
bool bRet = FALSE;
mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
if( mhDIB )
{
maSize = rSize;
mnBitCount = nBitCount;
bRet = TRUE;
}
return bRet;
}
bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
{
bool bRet = FALSE;
const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
{
HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
rSalBitmap.mhDIB != nullptr );
if ( hNewHdl )
{
if( rSalBitmap.mhDIB )
mhDIB = static_cast<HGLOBAL>(hNewHdl);
else if( rSalBitmap.mhDDB )
mhDDB = static_cast<HBITMAP>(hNewHdl);
maSize = rSalBitmap.maSize;
mnBitCount = rSalBitmap.mnBitCount;
bRet = TRUE;
}
}
return bRet;
}
bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
{
bool bRet = FALSE;
const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
if( rSalBmp.mhDIB )
{
PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( rSalBmp.mhDIB ));
HDC hDC = pGraphics->getHDC();
HBITMAP hNewDDB;
BITMAP aDDBInfo;
PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
if( pBI->bmiHeader.biBitCount == 1 )
{
hNewDDB = CreateBitmap( pBI->bmiHeader.biWidth, pBI->bmiHeader.biHeight, 1, 1, nullptr );
if( hNewDDB )
SetDIBits( hDC, hNewDDB, 0, pBI->bmiHeader.biHeight, pBits, pBI, DIB_RGB_COLORS );
}
else
hNewDDB = CreateDIBitmap( hDC, &pBI->bmiHeader, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
GlobalUnlock( rSalBmp.mhDIB );
if( hNewDDB && GetObjectW( hNewDDB, sizeof( aDDBInfo ), &aDDBInfo ) )
{
mhDDB = hNewDDB;
maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
bRet = TRUE;
}
else if( hNewDDB )
DeleteObject( hNewDDB );
}
return bRet;
}
bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
{
bool bRet = FALSE;
const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
if( rSalBmp.mhDDB )
{
mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
if( mhDIB )
{
PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
const int nLines = static_cast<int>(rSalBmp.maSize.Height());
HDC hDC = GetDC( nullptr );
PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
SalData* pSalData = GetSalData();
HPALETTE hOldPal = nullptr;
if ( pSalData->mhDitherPal )
{
hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
RealizePalette( hDC );
}
if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
{
GlobalUnlock( mhDIB );
maSize = rSalBmp.maSize;
mnBitCount = nNewBitCount;
bRet = TRUE;
}
else
{
GlobalUnlock( mhDIB );
GlobalFree( mhDIB );
mhDIB = nullptr;
}
if( hOldPal )
SelectPalette( hDC, hOldPal, TRUE );
ReleaseDC( nullptr, hDC );
}
}
return bRet;
}
bool WinSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, Size& /*rSize*/, bool bMask )
{
css::uno::Reference< css::beans::XFastPropertySet >
xFastPropertySet( rBitmapCanvas, css::uno::UNO_QUERY );
if( xFastPropertySet.get() ) {
css::uno::Sequence< css::uno::Any > args;
if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) {
sal_Int64 aHBmp64;
if( args[0] >>= aHBmp64 ) {
return Create( HBITMAP(aHBmp64), false, false );
}
}
}
return false;
}
sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
{
sal_uInt16 nColors = 0;
if( hDIB )
{
PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( hDIB ));
if ( pBI->bmiHeader.biSize != sizeof( BITMAPCOREHEADER ) )
{
if( pBI->bmiHeader.biBitCount <= 8 )
{
if ( pBI->bmiHeader.biClrUsed )
nColors = static_cast<sal_uInt16>(pBI->bmiHeader.biClrUsed);
else
nColors = 1 << pBI->bmiHeader.biBitCount;
}
}
else if( reinterpret_cast<PBITMAPCOREHEADER>(pBI)->bcBitCount <= 8 )
nColors = 1 << reinterpret_cast<PBITMAPCOREHEADER>(pBI)->bcBitCount;
GlobalUnlock( hDIB );
}
return nColors;
}
HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
{
SAL_WARN_IF( nBits != 1 && nBits != 4 && nBits != 8 && nBits != 16 && nBits != 24, "vcl", "Unsupported BitCount!" );
HGLOBAL hDIB = nullptr;
if( rSize.Width() <= 0 || rSize.Height() <= 0 )
return hDIB;
// calculate bitmap size in Bytes
const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != static_cast<sal_uLong>(rSize.Height());
if( bOverflow )
return hDIB;
// allocate bitmap memory including header and palette
const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
bOverflow = (nHeaderSize + nImageSize) < nImageSize;
if( bOverflow )
return hDIB;
hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
if( !hDIB )
return hDIB;
PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
pBIH->biSize = sizeof( BITMAPINFOHEADER );
pBIH->biWidth = rSize.Width();
pBIH->biHeight = rSize.Height();
pBIH->biPlanes = 1;
pBIH->biBitCount = nBits;
pBIH->biCompression = BI_RGB;
pBIH->biSizeImage = nImageSize;
pBIH->biXPelsPerMeter = 0;
pBIH->biYPelsPerMeter = 0;
pBIH->biClrUsed = 0;
pBIH->biClrImportant = 0;
if( nColors )
{
// copy the palette entries if any
const sal_uInt16 nMinCount = std::min( nColors, rPal.GetEntryCount() );
if( nMinCount )
memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
}
GlobalUnlock( hDIB );
return hDIB;
}
HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
{
HANDLE hCopy = nullptr;
if ( bDIB && hHdl )
{
const sal_uLong nSize = GlobalSize( hHdl );
if ( (hCopy = GlobalAlloc( GHND, nSize )) != nullptr )
{
memcpy( GlobalLock( hCopy ), GlobalLock( hHdl ), nSize );
GlobalUnlock( hCopy );
GlobalUnlock( hHdl );
}
}
else if ( hHdl )
{
BITMAP aBmp;
// find out size of source bitmap
GetObjectW( hHdl, sizeof( aBmp ), &aBmp );
// create destination bitmap
if ( (hCopy = CreateBitmapIndirect( &aBmp )) != nullptr )
{
HDC hBmpDC = CreateCompatibleDC( nullptr );
HBITMAP hBmpOld = static_cast<HBITMAP>(SelectObject( hBmpDC, hHdl ));
HDC hCopyDC = CreateCompatibleDC( hBmpDC );
HBITMAP hCopyOld = static_cast<HBITMAP>(SelectObject( hCopyDC, hCopy ));
BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
SelectObject( hCopyDC, hCopyOld );
DeleteDC( hCopyDC );
SelectObject( hBmpDC, hBmpOld );
DeleteDC( hBmpDC );
}
}
return hCopy;
}
BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
{
BitmapBuffer* pBuffer = nullptr;
if( mhDIB )
{
PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
PBITMAPINFOHEADER pBIH = &pBI->bmiHeader;
if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
{
Size aSizePix( pBIH->biWidth, pBIH->biHeight );
HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
if( hNewDIB )
{
PBITMAPINFO pNewBI = static_cast<PBITMAPINFO>(GlobalLock( hNewDIB ));
PBITMAPINFOHEADER pNewBIH = &pNewBI->bmiHeader;
const sal_uInt16 nColorCount = ImplGetDIBColorCount( hNewDIB );
const sal_uLong nOffset = pBI->bmiHeader.biSize + nColorCount * sizeof( RGBQUAD );
BYTE* pOldBits = reinterpret_cast<PBYTE>(pBI) + nOffset;
BYTE* pNewBits = reinterpret_cast<PBYTE>(pNewBI) + nOffset;
memcpy( pNewBI, pBI, nOffset );
pNewBIH->biCompression = 0;
ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
GlobalUnlock( mhDIB );
GlobalFree( mhDIB );
mhDIB = hNewDIB;
pBI = pNewBI;
pBIH = pNewBIH;
}
}
if( pBIH->biPlanes == 1 )
{
pBuffer = new BitmapBuffer;
pBuffer->mnFormat = pBIH->biBitCount == 1 ? ScanlineFormat::N1BitMsbPal :
pBIH->biBitCount == 4 ? ScanlineFormat::N4BitMsnPal :
pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
pBIH->biBitCount == 16 ? ScanlineFormat::N16BitTcLsbMask :
pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr :
pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcMask :
ScanlineFormat::NONE;
if( RemoveScanline( pBuffer->mnFormat ) != ScanlineFormat::NONE )
{
pBuffer->mnWidth = maSize.Width();
pBuffer->mnHeight = maSize.Height();
pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
pBuffer->mnBitCount = static_cast<sal_uInt16>(pBIH->biBitCount);
if( pBuffer->mnBitCount <= 8 )
{
const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
pBuffer->maPalette.SetEntryCount( nPalCount );
memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize + nPalCount * sizeof( RGBQUAD );
}
else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
{
sal_uLong nOffset = 0;
if( pBIH->biCompression == BI_BITFIELDS )
{
nOffset = 3 * sizeof( RGBQUAD );
ColorMaskElement aRedMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 0 ]));
aRedMask.CalcMaskShift();
ColorMaskElement aGreenMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 1 ]));
aGreenMask.CalcMaskShift();
ColorMaskElement aBlueMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 2 ]));
aBlueMask.CalcMaskShift();
pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
}
else if( pBIH->biBitCount == 16 )
{
ColorMaskElement aRedMask(0x00007c00UL);
aRedMask.CalcMaskShift();
ColorMaskElement aGreenMask(0x000003e0UL);
aGreenMask.CalcMaskShift();
ColorMaskElement aBlueMask(0x0000001fUL);
aBlueMask.CalcMaskShift();
pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
}
else
{
ColorMaskElement aRedMask(0x00ff0000UL);
aRedMask.CalcMaskShift();
ColorMaskElement aGreenMask(0x0000ff00UL);
aGreenMask.CalcMaskShift();
ColorMaskElement aBlueMask(0x000000ffUL);
aBlueMask.CalcMaskShift();
pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
}
pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize + nOffset;
}
else
pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize;
}
else
{
GlobalUnlock( mhDIB );
delete pBuffer;
pBuffer = nullptr;
}
}
else
GlobalUnlock( mhDIB );
}
return pBuffer;
}
void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
{
if( pBuffer )
{
if( mhDIB )
{
if( nMode == BitmapAccessMode::Write && !!pBuffer->maPalette )
{
PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount();
const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB );
memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), std::min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
GlobalUnlock( mhDIB );
}
GlobalUnlock( mhDIB );
}
delete pBuffer;
}
if( nMode == BitmapAccessMode::Write )
InvalidateChecksum();
}
void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
const Size& rSizePixel, bool bRLE4 )
{
sal_uInt8 const * pRLE = pSrcBuf;
sal_uInt8* pDIB = pDstBuf;
sal_uInt8* pRow = pDstBuf;
sal_uLong nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
sal_uInt8* pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
sal_uLong nCountByte;
sal_uLong nRunByte;
sal_uLong i;
BYTE cTmp;
bool bEndDecoding = FALSE;
if( pRLE && pDIB )
{
sal_uLong nX = 0;
do
{
if( ( nCountByte = *pRLE++ ) == 0 )
{
nRunByte = *pRLE++;
if( nRunByte > 2 )
{
if( bRLE4 )
{
nCountByte = nRunByte >> 1;
for( i = 0; i < nCountByte; i++ )
{
cTmp = *pRLE++;
ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
}
if( nRunByte & 1 )
ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
pRLE++;
}
else
{
memcpy( &pDIB[ nX ], pRLE, nRunByte );
pRLE += nRunByte;
nX += nRunByte;
if( nRunByte & 1 )
pRLE++;
}
}
else if( !nRunByte )
{
pDIB = ( pRow += nWidthAl );
nX = 0;
}
else if( nRunByte == 1 )
bEndDecoding = TRUE;
else
{
nX += *pRLE++;
pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
}
}
else
{
cTmp = *pRLE++;
if( bRLE4 )
{
nRunByte = nCountByte >> 1;
for( i = 0; i < nRunByte; i++ )
{
ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
}
if( nCountByte & 1 )
ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
}
else
{
for( i = 0; i < nCountByte; i++ )
pDIB[ nX++ ] = cTmp;
}
}
}
while( !bEndDecoding && ( pDIB <= pLast ) );
}
}
bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
{
bool bRet = false;
if( mhDIB || mhDDB )
{
bRet = true;
rData.pDIB = mhDIB;
rData.pDDB = mhDDB;
const Size& rSize = GetSize ();
rData.mnWidth = rSize.Width();
rData.mnHeight = rSize.Height();
}
return bRet;
}
bool WinSalBitmap::ScalingSupported() const
{
return false;
}
bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
{
return false;
}
bool WinSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ )
{
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V614 Uninitialized variable 'aHBmp64' used.