build fix
[LibreOffice.git] / vcl / win / gdi / salbmp.cxx
blob77a29025cd78020f366db66960eb517eab3e11da
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <svsys.h>
20 #include <vcl/bitmap.hxx>
21 #include <vcl/salbtype.hxx>
22 #include <com/sun/star/beans/XFastPropertySet.hpp>
23 #include <win/wincomp.hxx>
24 #include <win/salgdi.h>
25 #include <win/saldata.hxx>
26 #include <win/salbmp.h>
27 #include <string.h>
28 #include <vcl/timer.hxx>
29 #include <cppuhelper/basemutex.hxx>
30 #include <map>
32 #if defined _MSC_VER
33 #ifndef min
34 #define min(a,b) (((a) < (b)) ? (a) : (b))
35 #endif
36 #ifndef max
37 #define max(a,b) (((a) > (b)) ? (a) : (b))
38 #endif
39 #endif
41 #include "prewin.h"
42 #include <gdiplus.h>
43 #include "postwin.h"
46 inline void ImplSetPixel4( sal_uInt8* pScanline, long nX, const BYTE cIndex )
48 BYTE& rByte = pScanline[ nX >> 1 ];
50 if ( nX & 1 )
52 rByte &= 0xf0;
53 rByte |= cIndex & 0x0f;
55 else
57 rByte &= 0x0f;
58 rByte |= cIndex << 4;
62 // Helper class to manage Gdiplus::Bitmap instances inside of
63 // WinSalBitmap
65 typedef ::std::map< WinSalBitmap*, sal_uInt32 > EntryMap;
66 static const sal_uInt32 nDefaultCycles(60);
68 class GdiPlusBuffer : protected cppu::BaseMutex, public Timer
70 private:
71 EntryMap maEntries;
73 public:
74 GdiPlusBuffer()
75 : Timer(),
76 maEntries()
78 SetTimeout(1000);
79 Stop();
82 ~GdiPlusBuffer() override
84 Stop();
87 void addEntry(WinSalBitmap& rEntry)
89 ::osl::MutexGuard aGuard(m_aMutex);
90 EntryMap::iterator aFound = maEntries.find(&rEntry);
92 if(aFound == maEntries.end())
94 if(maEntries.empty())
96 Start();
99 maEntries[&rEntry] = nDefaultCycles;
103 void remEntry(WinSalBitmap& rEntry)
105 ::osl::MutexGuard aGuard(m_aMutex);
106 EntryMap::iterator aFound = maEntries.find(&rEntry);
108 if(aFound != maEntries.end())
110 maEntries.erase(aFound);
112 if(maEntries.empty())
114 Stop();
119 void touchEntry(WinSalBitmap& rEntry)
121 ::osl::MutexGuard aGuard(m_aMutex);
122 EntryMap::iterator aFound = maEntries.find(&rEntry);
124 if(aFound != maEntries.end())
126 aFound->second = nDefaultCycles;
130 // from parent Timer
131 virtual void Invoke() override
133 ::osl::MutexGuard aGuard(m_aMutex);
134 EntryMap::iterator aIter(maEntries.begin());
136 while(aIter != maEntries.end())
138 if(aIter->second)
140 aIter->second--;
141 ++aIter;
143 else
145 EntryMap::iterator aDelete(aIter);
146 WinSalBitmap* pSource = aDelete->first;
147 ++aIter;
148 maEntries.erase(aDelete);
150 if(maEntries.empty())
152 Stop();
155 // delete at WinSalBitmap after entry is removed; this
156 // way it would not hurt to call remEntry from there, too
157 if(pSource->maGdiPlusBitmap.get())
159 pSource->maGdiPlusBitmap.reset();
160 pSource->mpAssociatedAlpha = nullptr;
165 if(!maEntries.empty())
167 Start();
172 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
173 // instances
175 static GdiPlusBuffer aGdiPlusBuffer;
178 WinSalBitmap::WinSalBitmap()
179 : maSize(),
180 mhDIB(nullptr),
181 mhDDB(nullptr),
182 maGdiPlusBitmap(),
183 mpAssociatedAlpha(nullptr),
184 mnBitCount(0)
188 WinSalBitmap::~WinSalBitmap()
190 Destroy();
193 void WinSalBitmap::Destroy()
195 if(maGdiPlusBitmap.get())
197 aGdiPlusBuffer.remEntry(*this);
200 if( mhDIB )
201 GlobalFree( mhDIB );
202 else if( mhDDB )
203 DeleteObject( mhDDB );
205 maSize = Size();
206 mnBitCount = 0;
209 std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
211 WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this);
213 if(maGdiPlusBitmap.get() && pAlphaSource != mpAssociatedAlpha)
215 // #122350# if associated alpha with which the GDIPlus was constructed has changed
216 // it is necessary to remove it from buffer, reset reference to it and reconstruct
217 pThat->maGdiPlusBitmap.reset();
218 aGdiPlusBuffer.remEntry(const_cast< WinSalBitmap& >(*this));
221 if(maGdiPlusBitmap.get())
223 aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this));
225 else
227 if(maSize.Width() > 0 && maSize.Height() > 0)
229 if(pAlphaSource)
231 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource));
232 pThat->mpAssociatedAlpha = pAlphaSource;
234 else
236 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap());
237 pThat->mpAssociatedAlpha = nullptr;
240 if(maGdiPlusBitmap.get())
242 aGdiPlusBuffer.addEntry(*pThat);
247 return maGdiPlusBitmap;
250 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap()
252 Gdiplus::Bitmap* pRetval(nullptr);
253 WinSalBitmap* pSalRGB = this;
254 WinSalBitmap* pExtraWinSalRGB = nullptr;
256 if(!pSalRGB->ImplGethDIB())
258 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
259 pExtraWinSalRGB = new WinSalBitmap();
260 pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
261 pSalRGB = pExtraWinSalRGB;
264 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BitmapAccessMode::Read);
265 BitmapBuffer* pExtraRGB = nullptr;
267 if(pRGB && ScanlineFormat::N24BitTcBgr != (pRGB->mnFormat & ~ScanlineFormat::TopDown))
269 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
270 SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
271 pExtraRGB = StretchAndConvert(
272 *pRGB,
273 aSalTwoRect,
274 ScanlineFormat::N24BitTcBgr);
276 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Write);
277 pRGB = pExtraRGB;
280 if(pRGB
281 && pRGB->mnWidth > 0
282 && pRGB->mnHeight > 0
283 && ScanlineFormat::N24BitTcBgr == (pRGB->mnFormat & ~ScanlineFormat::TopDown))
285 const sal_uInt32 nW(pRGB->mnWidth);
286 const sal_uInt32 nH(pRGB->mnHeight);
288 pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB);
290 if ( pRetval->GetLastStatus() == Gdiplus::Ok )
292 sal_uInt8* pSrcRGB(pRGB->mpBits);
293 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
294 const bool bTopDown(pRGB->mnFormat & ScanlineFormat::TopDown);
295 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
296 Gdiplus::BitmapData aGdiPlusBitmapData;
297 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &aGdiPlusBitmapData);
299 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
300 for(sal_uInt32 y(0); y < nH; y++)
302 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
303 sal_uInt8* targetPixels = static_cast<sal_uInt8*>(aGdiPlusBitmapData.Scan0) + (nYInsert * aGdiPlusBitmapData.Stride);
305 memcpy(targetPixels, pSrcRGB, nW * 3);
306 pSrcRGB += nW * 3 + nExtraRGB;
309 pRetval->UnlockBits(&aGdiPlusBitmapData);
311 else
313 delete pRetval;
314 pRetval = nullptr;
318 if(pExtraRGB)
320 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
321 // in its destructor, this *has to be done handish*. Doing it here now
322 delete[] pExtraRGB->mpBits;
323 delete pExtraRGB;
325 else
327 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
330 if(pExtraWinSalRGB)
332 delete pExtraWinSalRGB;
335 return pRetval;
338 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
340 Gdiplus::Bitmap* pRetval(nullptr);
341 WinSalBitmap* pSalRGB = this;
342 WinSalBitmap* pExtraWinSalRGB = nullptr;
344 if(!pSalRGB->ImplGethDIB())
346 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
347 pExtraWinSalRGB = new WinSalBitmap();
348 pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
349 pSalRGB = pExtraWinSalRGB;
352 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BitmapAccessMode::Read);
353 BitmapBuffer* pExtraRGB = nullptr;
355 if(pRGB && ScanlineFormat::N24BitTcBgr != (pRGB->mnFormat & ~ScanlineFormat::TopDown))
357 // convert source bitmap to canlineFormat::N24BitTcBgr format if not yet in that format
358 SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
359 pExtraRGB = StretchAndConvert(
360 *pRGB,
361 aSalTwoRect,
362 ScanlineFormat::N24BitTcBgr);
364 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
365 pRGB = pExtraRGB;
368 WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
369 WinSalBitmap* pExtraWinSalA = nullptr;
371 if(!pSalA->ImplGethDIB())
373 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
374 pExtraWinSalA = new WinSalBitmap();
375 pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount());
376 pSalA = pExtraWinSalA;
379 BitmapBuffer* pA = pSalA->AcquireBuffer(BitmapAccessMode::Read);
380 BitmapBuffer* pExtraA = nullptr;
382 if(pA && ScanlineFormat::N8BitPal != (pA->mnFormat & ~ScanlineFormat::TopDown))
384 // convert alpha bitmap to ScanlineFormat::N8BitPal format if not yet in that format
385 SalTwoRect aSalTwoRect(0, 0, pA->mnWidth, pA->mnHeight, 0, 0, pA->mnWidth, pA->mnHeight);
386 const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
388 pExtraA = StretchAndConvert(
389 *pA,
390 aSalTwoRect,
391 ScanlineFormat::N8BitPal,
392 &rTargetPalette);
394 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
395 pA = pExtraA;
398 if(pRGB
399 && pA
400 && pRGB->mnWidth > 0
401 && pRGB->mnHeight > 0
402 && pRGB->mnWidth == pA->mnWidth
403 && pRGB->mnHeight == pA->mnHeight
404 && ScanlineFormat::N24BitTcBgr == (pRGB->mnFormat & ~ScanlineFormat::TopDown)
405 && ScanlineFormat::N8BitPal == (pA->mnFormat & ~ScanlineFormat::TopDown))
407 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
408 const sal_uInt32 nW(pRGB->mnWidth);
409 const sal_uInt32 nH(pRGB->mnHeight);
411 pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB);
413 if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
415 sal_uInt8* pSrcRGB(pRGB->mpBits);
416 sal_uInt8* pSrcA(pA->mpBits);
417 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
418 const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
419 const bool bTopDown(pRGB->mnFormat & ScanlineFormat::TopDown);
420 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
421 Gdiplus::BitmapData aGdiPlusBitmapData;
422 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
424 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
425 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
426 for(sal_uInt32 y(0); y < nH; y++)
428 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
429 sal_uInt8* targetPixels = static_cast<sal_uInt8*>(aGdiPlusBitmapData.Scan0) + (nYInsert * aGdiPlusBitmapData.Stride);
431 for(sal_uInt32 x(0); x < nW; x++)
433 *targetPixels++ = *pSrcRGB++;
434 *targetPixels++ = *pSrcRGB++;
435 *targetPixels++ = *pSrcRGB++;
436 *targetPixels++ = 0xff - *pSrcA++;
439 pSrcRGB += nExtraRGB;
440 pSrcA += nExtraA;
443 pRetval->UnlockBits(&aGdiPlusBitmapData);
445 else
447 delete pRetval;
448 pRetval = nullptr;
452 if(pExtraA)
454 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
455 // in its destructor, this *has to be done handish*. Doing it here now
456 delete[] pExtraA->mpBits;
457 delete pExtraA;
459 else
461 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
464 if(pExtraWinSalA)
466 delete pExtraWinSalA;
469 if(pExtraRGB)
471 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
472 // in its destructor, this *has to be done handish*. Doing it here now
473 delete[] pExtraRGB->mpBits;
474 delete pExtraRGB;
476 else
478 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
481 if(pExtraWinSalRGB)
483 delete pExtraWinSalRGB;
486 return pRetval;
489 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
491 bool bRet = TRUE;
493 if( bDIB )
494 mhDIB = static_cast<HGLOBAL>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, true ) : hBitmap );
495 else
496 mhDDB = static_cast<HBITMAP>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, false ) : hBitmap );
498 if( mhDIB )
500 PBITMAPINFOHEADER pBIH = static_cast<PBITMAPINFOHEADER>(GlobalLock( mhDIB ));
502 maSize = Size( pBIH->biWidth, pBIH->biHeight );
503 mnBitCount = pBIH->biBitCount;
505 if( mnBitCount )
506 mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
508 GlobalUnlock( mhDIB );
510 else if( mhDDB )
512 BITMAP aDDBInfo;
514 if( GetObjectA( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
516 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
517 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
519 if( mnBitCount )
521 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
522 ( mnBitCount <= 4 ) ? 4 :
523 ( mnBitCount <= 8 ) ? 8 : 24;
526 else
528 mhDDB = nullptr;
529 bRet = FALSE;
532 else
533 bRet = FALSE;
535 return bRet;
538 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
540 bool bRet = FALSE;
542 mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
544 if( mhDIB )
546 maSize = rSize;
547 mnBitCount = nBitCount;
548 bRet = TRUE;
551 return bRet;
554 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
556 bool bRet = FALSE;
557 const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
559 if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
561 HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
562 rSalBitmap.mhDIB != nullptr );
564 if ( hNewHdl )
566 if( rSalBitmap.mhDIB )
567 mhDIB = static_cast<HGLOBAL>(hNewHdl);
568 else if( rSalBitmap.mhDDB )
569 mhDDB = static_cast<HBITMAP>(hNewHdl);
571 maSize = rSalBitmap.maSize;
572 mnBitCount = rSalBitmap.mnBitCount;
574 bRet = TRUE;
578 return bRet;
581 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
583 bool bRet = FALSE;
585 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
586 WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
588 if( rSalBmp.mhDIB )
590 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( rSalBmp.mhDIB ));
591 HDC hDC = pGraphics->getHDC();
592 HBITMAP hNewDDB;
593 BITMAP aDDBInfo;
594 PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
595 ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
597 if( pBI->bmiHeader.biBitCount == 1 )
599 hNewDDB = CreateBitmap( pBI->bmiHeader.biWidth, pBI->bmiHeader.biHeight, 1, 1, nullptr );
601 if( hNewDDB )
602 SetDIBits( hDC, hNewDDB, 0, pBI->bmiHeader.biHeight, pBits, pBI, DIB_RGB_COLORS );
604 else
605 hNewDDB = CreateDIBitmap( hDC, &pBI->bmiHeader, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
607 GlobalUnlock( rSalBmp.mhDIB );
609 if( hNewDDB && GetObjectA( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
611 mhDDB = hNewDDB;
612 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
613 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
615 bRet = TRUE;
617 else if( hNewDDB )
618 DeleteObject( hNewDDB );
621 return bRet;
624 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
626 bool bRet = FALSE;
628 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
630 if( rSalBmp.mhDDB )
632 mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
634 if( mhDIB )
636 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
637 const int nLines = (int) rSalBmp.maSize.Height();
638 HDC hDC = GetDC( nullptr );
639 PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
640 ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
641 SalData* pSalData = GetSalData();
642 HPALETTE hOldPal = nullptr;
644 if ( pSalData->mhDitherPal )
646 hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
647 RealizePalette( hDC );
650 if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
652 GlobalUnlock( mhDIB );
653 maSize = rSalBmp.maSize;
654 mnBitCount = nNewBitCount;
655 bRet = TRUE;
657 else
659 GlobalUnlock( mhDIB );
660 GlobalFree( mhDIB );
661 mhDIB = nullptr;
664 if( hOldPal )
665 SelectPalette( hDC, hOldPal, TRUE );
667 ReleaseDC( nullptr, hDC );
671 return bRet;
674 bool WinSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, Size& /*rSize*/, bool bMask )
676 css::uno::Reference< css::beans::XFastPropertySet >
677 xFastPropertySet( rBitmapCanvas, css::uno::UNO_QUERY );
679 if( xFastPropertySet.get() ) {
680 css::uno::Sequence< css::uno::Any > args;
682 if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) {
683 sal_Int64 aHBmp64;
685 if( args[0] >>= aHBmp64 ) {
686 return Create( HBITMAP(aHBmp64), false, false );
690 return false;
693 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
695 sal_uInt16 nColors = 0;
697 if( hDIB )
699 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( hDIB ));
701 if ( pBI->bmiHeader.biSize != sizeof( BITMAPCOREHEADER ) )
703 if( pBI->bmiHeader.biBitCount <= 8 )
705 if ( pBI->bmiHeader.biClrUsed )
706 nColors = (sal_uInt16) pBI->bmiHeader.biClrUsed;
707 else
708 nColors = 1 << pBI->bmiHeader.biBitCount;
711 else if( reinterpret_cast<PBITMAPCOREHEADER>(pBI)->bcBitCount <= 8 )
712 nColors = 1 << reinterpret_cast<PBITMAPCOREHEADER>(pBI)->bcBitCount;
714 GlobalUnlock( hDIB );
717 return nColors;
720 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
722 SAL_WARN_IF( nBits != 1 && nBits != 4 && nBits != 8 && nBits != 16 && nBits != 24, "vcl", "Unsupported BitCount!" );
724 HGLOBAL hDIB = nullptr;
726 if( rSize.Width() <= 0 || rSize.Height() <= 0 )
727 return hDIB;
729 // calculate bitmap size in Bytes
730 const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
731 const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
732 bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != (sal_uLong) rSize.Height();
733 if( bOverflow )
734 return hDIB;
736 // allocate bitmap memory including header and palette
737 const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
738 const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
739 bOverflow = (nHeaderSize + nImageSize) < nImageSize;
740 if( bOverflow )
741 return hDIB;
743 hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
744 if( !hDIB )
745 return hDIB;
747 PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
748 PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
750 pBIH->biSize = sizeof( BITMAPINFOHEADER );
751 pBIH->biWidth = rSize.Width();
752 pBIH->biHeight = rSize.Height();
753 pBIH->biPlanes = 1;
754 pBIH->biBitCount = nBits;
755 pBIH->biCompression = BI_RGB;
756 pBIH->biSizeImage = nImageSize;
757 pBIH->biXPelsPerMeter = 0;
758 pBIH->biYPelsPerMeter = 0;
759 pBIH->biClrUsed = 0;
760 pBIH->biClrImportant = 0;
762 if( nColors )
764 // copy the palette entries if any
765 const sal_uInt16 nMinCount = (std::min)( nColors, rPal.GetEntryCount() );
766 if( nMinCount )
767 memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
770 GlobalUnlock( hDIB );
772 return hDIB;
775 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
777 HANDLE hCopy = nullptr;
779 if ( bDIB && hHdl )
781 const sal_uLong nSize = GlobalSize( hHdl );
783 if ( (hCopy = GlobalAlloc( GHND, nSize )) != nullptr )
785 memcpy( GlobalLock( hCopy ), GlobalLock( hHdl ), nSize );
787 GlobalUnlock( hCopy );
788 GlobalUnlock( hHdl );
791 else if ( hHdl )
793 BITMAP aBmp;
795 // find out size of source bitmap
796 GetObjectA( hHdl, sizeof( BITMAP ), &aBmp );
798 // create destination bitmap
799 if ( (hCopy = CreateBitmapIndirect( &aBmp )) != nullptr )
801 HDC hBmpDC = CreateCompatibleDC( nullptr );
802 HBITMAP hBmpOld = static_cast<HBITMAP>(SelectObject( hBmpDC, hHdl ));
803 HDC hCopyDC = CreateCompatibleDC( hBmpDC );
804 HBITMAP hCopyOld = static_cast<HBITMAP>(SelectObject( hCopyDC, hCopy ));
806 BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
808 SelectObject( hCopyDC, hCopyOld );
809 DeleteDC( hCopyDC );
811 SelectObject( hBmpDC, hBmpOld );
812 DeleteDC( hBmpDC );
816 return hCopy;
819 BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
821 BitmapBuffer* pBuffer = nullptr;
823 if( mhDIB )
825 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
826 PBITMAPINFOHEADER pBIH = &pBI->bmiHeader;
828 if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
830 Size aSizePix( pBIH->biWidth, pBIH->biHeight );
831 HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
833 if( hNewDIB )
835 PBITMAPINFO pNewBI = static_cast<PBITMAPINFO>(GlobalLock( hNewDIB ));
836 PBITMAPINFOHEADER pNewBIH = &pNewBI->bmiHeader;
837 const sal_uInt16 nColorCount = ImplGetDIBColorCount( hNewDIB );
838 const sal_uLong nOffset = pBI->bmiHeader.biSize + nColorCount * sizeof( RGBQUAD );
839 BYTE* pOldBits = reinterpret_cast<PBYTE>(pBI) + nOffset;
840 BYTE* pNewBits = reinterpret_cast<PBYTE>(pNewBI) + nOffset;
842 memcpy( pNewBI, pBI, nOffset );
843 pNewBIH->biCompression = 0;
844 ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
846 GlobalUnlock( mhDIB );
847 GlobalFree( mhDIB );
848 mhDIB = hNewDIB;
849 pBI = pNewBI;
850 pBIH = pNewBIH;
854 if( pBIH->biPlanes == 1 )
856 pBuffer = new BitmapBuffer;
858 pBuffer->mnFormat = pBIH->biBitCount == 1 ? ScanlineFormat::N1BitMsbPal :
859 pBIH->biBitCount == 4 ? ScanlineFormat::N4BitMsnPal :
860 pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
861 pBIH->biBitCount == 16 ? ScanlineFormat::N16BitTcLsbMask :
862 pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr :
863 pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcMask :
864 ScanlineFormat::NONE;
866 if( RemoveScanline( pBuffer->mnFormat ) != ScanlineFormat::NONE )
868 pBuffer->mnWidth = maSize.Width();
869 pBuffer->mnHeight = maSize.Height();
870 pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
871 pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
873 if( pBuffer->mnBitCount <= 8 )
875 const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
877 pBuffer->maPalette.SetEntryCount( nPalCount );
878 memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
879 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize + nPalCount * sizeof( RGBQUAD );
881 else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
883 sal_uLong nOffset = 0;
885 if( pBIH->biCompression == BI_BITFIELDS )
887 nOffset = 3 * sizeof( RGBQUAD );
888 ColorMaskElement aRedMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 0 ]));
889 aRedMask.CalcMaskShift();
890 ColorMaskElement aGreenMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 1 ]));
891 aGreenMask.CalcMaskShift();
892 ColorMaskElement aBlueMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 2 ]));
893 aBlueMask.CalcMaskShift();
894 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
896 else if( pBIH->biBitCount == 16 )
898 ColorMaskElement aRedMask(0x00007c00UL);
899 aRedMask.CalcMaskShift();
900 ColorMaskElement aGreenMask(0x000003e0UL);
901 aGreenMask.CalcMaskShift();
902 ColorMaskElement aBlueMask(0x0000001fUL);
903 aBlueMask.CalcMaskShift();
904 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
906 else
908 ColorMaskElement aRedMask(0x00ff0000UL);
909 aRedMask.CalcMaskShift();
910 ColorMaskElement aGreenMask(0x0000ff00UL);
911 aGreenMask.CalcMaskShift();
912 ColorMaskElement aBlueMask(0x000000ffUL);
913 aBlueMask.CalcMaskShift();
914 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
917 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize + nOffset;
919 else
920 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize;
922 else
924 GlobalUnlock( mhDIB );
925 delete pBuffer;
926 pBuffer = nullptr;
929 else
930 GlobalUnlock( mhDIB );
933 return pBuffer;
936 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
938 if( pBuffer )
940 if( mhDIB )
942 if( nMode == BitmapAccessMode::Write && !!pBuffer->maPalette )
944 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
945 const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount();
946 const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB );
947 memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), (std::min)( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
948 GlobalUnlock( mhDIB );
951 GlobalUnlock( mhDIB );
954 delete pBuffer;
958 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
959 const Size& rSizePixel, bool bRLE4 )
961 sal_uInt8 const * pRLE = pSrcBuf;
962 sal_uInt8* pDIB = pDstBuf;
963 sal_uInt8* pRow = pDstBuf;
964 sal_uLong nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
965 sal_uInt8* pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
966 sal_uLong nCountByte;
967 sal_uLong nRunByte;
968 sal_uLong i;
969 BYTE cTmp;
970 bool bEndDecoding = FALSE;
972 if( pRLE && pDIB )
974 sal_uLong nX = 0;
977 if( ( nCountByte = *pRLE++ ) == 0 )
979 nRunByte = *pRLE++;
981 if( nRunByte > 2 )
983 if( bRLE4 )
985 nCountByte = nRunByte >> 1;
987 for( i = 0; i < nCountByte; i++ )
989 cTmp = *pRLE++;
990 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
991 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
994 if( nRunByte & 1 )
995 ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
997 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
998 pRLE++;
1000 else
1002 memcpy( &pDIB[ nX ], pRLE, nRunByte );
1003 pRLE += nRunByte;
1004 nX += nRunByte;
1006 if( nRunByte & 1 )
1007 pRLE++;
1010 else if( !nRunByte )
1012 pDIB = ( pRow += nWidthAl );
1013 nX = 0;
1015 else if( nRunByte == 1 )
1016 bEndDecoding = TRUE;
1017 else
1019 nX += *pRLE++;
1020 pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1023 else
1025 cTmp = *pRLE++;
1027 if( bRLE4 )
1029 nRunByte = nCountByte >> 1;
1031 for( i = 0; i < nRunByte; i++ )
1033 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1034 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
1037 if( nCountByte & 1 )
1038 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1040 else
1042 for( i = 0; i < nCountByte; i++ )
1043 pDIB[ nX++ ] = cTmp;
1047 while( !bEndDecoding && ( pDIB <= pLast ) );
1051 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1053 bool bRet = false;
1054 if( mhDIB || mhDDB )
1056 bRet = true;
1057 rData.pDIB = mhDIB;
1058 rData.pDDB = mhDDB;
1059 const Size& rSize = GetSize ();
1060 rData.mnWidth = rSize.Width();
1061 rData.mnHeight = rSize.Height();
1063 return bRet;
1066 bool WinSalBitmap::ScalingSupported() const
1068 return false;
1071 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
1073 return false;
1076 bool WinSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uLong /*nTol*/ )
1078 return false;
1081 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */