calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / win / gdi / salbmp.cxx
blob18997f650a924882618102493e8a1dae6d16f519
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/BitmapAccessMode.hxx>
22 #include <vcl/BitmapBuffer.hxx>
23 #include <vcl/BitmapPalette.hxx>
24 #include <vcl/ColorMask.hxx>
25 #include <vcl/Scanline.hxx>
26 #include <com/sun/star/beans/XFastPropertySet.hpp>
27 #include <win/wincomp.hxx>
28 #include <win/salgdi.h>
29 #include <win/saldata.hxx>
30 #include <win/salbmp.h>
31 #include <string.h>
32 #include <vcl/timer.hxx>
33 #include <cppuhelper/basemutex.hxx>
34 #include <sal/log.hxx>
35 #include <tools/helpers.hxx>
36 #include <map>
38 #include <prewin.h>
39 #include <gdiplus.h>
40 #include <postwin.h>
42 #if defined _MSC_VER
43 #undef min
44 #undef max
45 #endif
47 WinSalBitmap::WinSalBitmap()
48 : SalBitmap(),
49 basegfx::SystemDependentDataHolder(),
50 maSize(),
51 mhDIB(nullptr),
52 mhDDB(nullptr),
53 mnBitCount(0)
57 WinSalBitmap::~WinSalBitmap()
59 Destroy();
62 void WinSalBitmap::Destroy()
64 if( mhDIB )
65 GlobalFree( mhDIB );
66 else if( mhDDB )
67 DeleteObject( mhDDB );
69 maSize = Size();
70 mnBitCount = 0;
73 namespace {
75 class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData
77 private:
78 std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap;
79 const WinSalBitmap* mpAssociatedAlpha;
81 public:
82 SystemDependentData_GdiPlusBitmap(
83 const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap,
84 const WinSalBitmap* pAssociatedAlpha);
86 const WinSalBitmap* getAssociatedAlpha() const { return mpAssociatedAlpha; }
87 const std::shared_ptr<Gdiplus::Bitmap>& getGdiPlusBitmap() const { return mpGdiPlusBitmap; }
89 virtual sal_Int64 estimateUsageInBytes() const override;
94 SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap(
95 const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap,
96 const WinSalBitmap* pAssociatedAlpha)
97 : basegfx::SystemDependentData(Application::GetSystemDependentDataManager()),
98 mpGdiPlusBitmap(rGdiPlusBitmap),
99 mpAssociatedAlpha(pAssociatedAlpha)
103 sal_Int64 SystemDependentData_GdiPlusBitmap::estimateUsageInBytes() const
105 sal_Int64 nRetval(0);
107 if(mpGdiPlusBitmap)
109 const UINT nWidth(mpGdiPlusBitmap->GetWidth());
110 const UINT nHeight(mpGdiPlusBitmap->GetHeight());
112 if(0 != nWidth && 0 != nHeight)
114 nRetval = nWidth * nHeight;
116 switch(mpGdiPlusBitmap->GetPixelFormat())
118 case PixelFormat1bppIndexed:
119 nRetval /= 8;
120 break;
121 case PixelFormat4bppIndexed:
122 nRetval /= 4;
123 break;
124 case PixelFormat16bppGrayScale:
125 case PixelFormat16bppRGB555:
126 case PixelFormat16bppRGB565:
127 case PixelFormat16bppARGB1555:
128 nRetval *= 2;
129 break;
130 case PixelFormat24bppRGB:
131 nRetval *= 3;
132 break;
133 case PixelFormat32bppRGB:
134 case PixelFormat32bppARGB:
135 case PixelFormat32bppPARGB:
136 case PixelFormat32bppCMYK:
137 nRetval *= 4;
138 break;
139 case PixelFormat48bppRGB:
140 nRetval *= 6;
141 break;
142 case PixelFormat64bppARGB:
143 case PixelFormat64bppPARGB:
144 nRetval *= 8;
145 break;
146 default:
147 case PixelFormat8bppIndexed:
148 break;
153 return nRetval;
156 std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
158 std::shared_ptr< Gdiplus::Bitmap > aRetval;
160 // try to access buffered data
161 std::shared_ptr<SystemDependentData_GdiPlusBitmap> pSystemDependentData_GdiPlusBitmap(
162 getSystemDependentData<SystemDependentData_GdiPlusBitmap>());
164 if(pSystemDependentData_GdiPlusBitmap)
166 // check data validity
167 if(pSystemDependentData_GdiPlusBitmap->getAssociatedAlpha() != pAlphaSource
168 || 0 == maSize.Width()
169 || 0 == maSize.Height())
171 // #122350# if associated alpha with which the GDIPlus was constructed has changed
172 // it is necessary to remove it from buffer, reset reference to it and reconstruct
173 // data invalid, forget
174 pSystemDependentData_GdiPlusBitmap.reset();
178 if(pSystemDependentData_GdiPlusBitmap)
180 // use from buffer
181 aRetval = pSystemDependentData_GdiPlusBitmap->getGdiPlusBitmap();
183 else if(!maSize.IsEmpty())
185 // create and set data
186 const WinSalBitmap* pAssociatedAlpha(nullptr);
188 if(pAlphaSource)
190 aRetval = const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource);
191 pAssociatedAlpha = pAlphaSource;
193 else
195 aRetval = const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap();
196 pAssociatedAlpha = nullptr;
199 // add to buffering mechanism
200 addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>(
201 aRetval,
202 pAssociatedAlpha);
205 return aRetval;
208 std::shared_ptr<Gdiplus::Bitmap> WinSalBitmap::ImplCreateGdiPlusBitmap()
210 std::shared_ptr<Gdiplus::Bitmap> pRetval;
211 WinSalBitmap* pSalRGB = this;
212 std::unique_ptr<WinSalBitmap> pExtraWinSalRGB;
214 if(!pSalRGB->ImplGethDIB())
216 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
217 pExtraWinSalRGB.reset(new WinSalBitmap());
218 pExtraWinSalRGB->Create(*pSalRGB, vcl::bitDepthToPixelFormat(pSalRGB->GetBitCount()));
219 pSalRGB = pExtraWinSalRGB.get();
222 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BitmapAccessMode::Read);
223 std::unique_ptr<BitmapBuffer> pExtraRGB;
225 if(pRGB && ScanlineFormat::N24BitTcBgr != RemoveScanline(pRGB->mnFormat))
227 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
228 SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
229 pExtraRGB = StretchAndConvert(
230 *pRGB,
231 aSalTwoRect,
232 ScanlineFormat::N24BitTcBgr);
234 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Write);
235 pRGB = pExtraRGB.get();
238 if(pRGB
239 && pRGB->mnWidth > 0
240 && pRGB->mnHeight > 0
241 && ScanlineFormat::N24BitTcBgr == RemoveScanline(pRGB->mnFormat))
243 const sal_uInt32 nW(pRGB->mnWidth);
244 const sal_uInt32 nH(pRGB->mnHeight);
246 pRetval = std::make_shared<Gdiplus::Bitmap>(nW, nH, PixelFormat24bppRGB);
248 if ( pRetval->GetLastStatus() == Gdiplus::Ok )
250 sal_uInt8* pSrcRGB(pRGB->mpBits);
251 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
252 const bool bTopDown(pRGB->mnFormat & ScanlineFormat::TopDown);
253 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
254 Gdiplus::BitmapData aGdiPlusBitmapData;
255 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &aGdiPlusBitmapData);
257 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
258 for(sal_uInt32 y(0); y < nH; y++)
260 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
261 sal_uInt8* targetPixels = static_cast<sal_uInt8*>(aGdiPlusBitmapData.Scan0) + (nYInsert * aGdiPlusBitmapData.Stride);
263 memcpy(targetPixels, pSrcRGB, nW * 3);
264 pSrcRGB += nW * 3 + nExtraRGB;
267 pRetval->UnlockBits(&aGdiPlusBitmapData);
269 else
271 pRetval.reset();
275 if(pExtraRGB)
277 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
278 // in its destructor, this *has to be done by hand*. Doing it here now
279 delete[] pExtraRGB->mpBits;
280 pExtraRGB.reset();
282 else
284 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
287 return pRetval;
290 std::shared_ptr<Gdiplus::Bitmap> WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
292 std::shared_ptr<Gdiplus::Bitmap> pRetval;
293 WinSalBitmap* pSalRGB = this;
294 std::unique_ptr<WinSalBitmap> pExtraWinSalRGB;
296 if(!pSalRGB->ImplGethDIB())
298 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
299 pExtraWinSalRGB.reset(new WinSalBitmap());
300 pExtraWinSalRGB->Create(*pSalRGB, vcl::bitDepthToPixelFormat(pSalRGB->GetBitCount()));
301 pSalRGB = pExtraWinSalRGB.get();
304 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BitmapAccessMode::Read);
305 std::unique_ptr<BitmapBuffer> pExtraRGB;
307 if(pRGB && ScanlineFormat::N24BitTcBgr != RemoveScanline(pRGB->mnFormat))
309 // convert source bitmap to canlineFormat::N24BitTcBgr format if not yet in that format
310 SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
311 pExtraRGB = StretchAndConvert(
312 *pRGB,
313 aSalTwoRect,
314 ScanlineFormat::N24BitTcBgr);
316 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
317 pRGB = pExtraRGB.get();
320 WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
321 std::unique_ptr<WinSalBitmap> pExtraWinSalA;
323 if(!pSalA->ImplGethDIB())
325 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
326 pExtraWinSalA.reset(new WinSalBitmap());
327 pExtraWinSalA->Create(*pSalA, vcl::bitDepthToPixelFormat(pSalA->GetBitCount()));
328 pSalA = pExtraWinSalA.get();
331 BitmapBuffer* pA = pSalA->AcquireBuffer(BitmapAccessMode::Read);
332 std::unique_ptr<BitmapBuffer> pExtraA;
334 if(pA && ScanlineFormat::N8BitPal != RemoveScanline(pA->mnFormat))
336 // convert alpha bitmap to ScanlineFormat::N8BitPal format if not yet in that format
337 SalTwoRect aSalTwoRect(0, 0, pA->mnWidth, pA->mnHeight, 0, 0, pA->mnWidth, pA->mnHeight);
338 const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
340 pExtraA = StretchAndConvert(
341 *pA,
342 aSalTwoRect,
343 ScanlineFormat::N8BitPal,
344 rTargetPalette);
346 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
347 pA = pExtraA.get();
350 if(pRGB
351 && pA
352 && pRGB->mnWidth > 0
353 && pRGB->mnHeight > 0
354 && pRGB->mnWidth == pA->mnWidth
355 && pRGB->mnHeight == pA->mnHeight
356 && ScanlineFormat::N24BitTcBgr == RemoveScanline(pRGB->mnFormat)
357 && ScanlineFormat::N8BitPal == RemoveScanline(pA->mnFormat))
359 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
360 const sal_uInt32 nW(pRGB->mnWidth);
361 const sal_uInt32 nH(pRGB->mnHeight);
363 pRetval = std::make_shared<Gdiplus::Bitmap>(nW, nH, PixelFormat32bppARGB);
365 if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
367 sal_uInt8* pSrcRGB(pRGB->mpBits);
368 sal_uInt8* pSrcA(pA->mpBits);
369 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
370 const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
371 const bool bTopDown(pRGB->mnFormat & ScanlineFormat::TopDown);
372 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
373 Gdiplus::BitmapData aGdiPlusBitmapData;
374 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
376 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
377 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
378 for(sal_uInt32 y(0); y < nH; y++)
380 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
381 sal_uInt8* targetPixels = static_cast<sal_uInt8*>(aGdiPlusBitmapData.Scan0) + (nYInsert * aGdiPlusBitmapData.Stride);
383 for(sal_uInt32 x(0); x < nW; x++)
385 *targetPixels++ = *pSrcRGB++;
386 *targetPixels++ = *pSrcRGB++;
387 *targetPixels++ = *pSrcRGB++;
388 *targetPixels++ = 0xff - *pSrcA++;
391 pSrcRGB += nExtraRGB;
392 pSrcA += nExtraA;
395 pRetval->UnlockBits(&aGdiPlusBitmapData);
397 else
399 pRetval.reset();
403 if(pExtraA)
405 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
406 // in its destructor, this *has to be done handish*. Doing it here now
407 delete[] pExtraA->mpBits;
408 pExtraA.reset();
410 else
412 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
415 pExtraWinSalA.reset();
417 if(pExtraRGB)
419 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
420 // in its destructor, this *has to be done by hand*. Doing it here now
421 delete[] pExtraRGB->mpBits;
422 pExtraRGB.reset();
424 else
426 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
429 pExtraWinSalRGB.reset();
431 return pRetval;
434 bool WinSalBitmap::Create( HANDLE hBitmap )
436 bool bRet = true;
438 mhDDB = static_cast<HBITMAP>( hBitmap );
440 if( mhDIB )
442 PBITMAPINFOHEADER pBIH = static_cast<PBITMAPINFOHEADER>(GlobalLock( mhDIB ));
444 maSize = Size( pBIH->biWidth, pBIH->biHeight );
445 mnBitCount = pBIH->biBitCount;
447 if( mnBitCount )
448 mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
450 GlobalUnlock( mhDIB );
452 else if( mhDDB )
454 BITMAP aDDBInfo;
456 if( GetObjectW( mhDDB, sizeof( aDDBInfo ), &aDDBInfo ) )
458 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
459 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
461 if( mnBitCount )
463 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
464 ( mnBitCount <= 4 ) ? 4 :
465 ( mnBitCount <= 8 ) ? 8 : 24;
468 else
470 mhDDB = nullptr;
471 bRet = false;
474 else
475 bRet = false;
477 return bRet;
480 bool WinSalBitmap::Create(const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal)
482 bool bRet = false;
484 mhDIB = ImplCreateDIB(rSize, ePixelFormat, rPal);
486 if( mhDIB )
488 maSize = rSize;
489 mnBitCount = vcl::pixelFormatBitCount(ePixelFormat);
490 bRet = true;
493 return bRet;
496 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
498 bool bRet = false;
499 const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
501 if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
503 HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
504 rSalBitmap.mhDIB != nullptr );
506 if ( hNewHdl )
508 if( rSalBitmap.mhDIB )
509 mhDIB = static_cast<HGLOBAL>(hNewHdl);
510 else if( rSalBitmap.mhDDB )
511 mhDDB = static_cast<HBITMAP>(hNewHdl);
513 maSize = rSalBitmap.maSize;
514 mnBitCount = rSalBitmap.mnBitCount;
516 bRet = true;
520 return bRet;
523 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
525 bool bRet = false;
527 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
528 WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
530 if( rSalBmp.mhDIB )
532 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( rSalBmp.mhDIB ));
533 HDC hDC = pGraphics->getHDC();
534 HBITMAP hNewDDB;
535 BITMAP aDDBInfo;
536 PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
537 ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
539 if( pBI->bmiHeader.biBitCount == 1 )
541 hNewDDB = CreateBitmap( pBI->bmiHeader.biWidth, pBI->bmiHeader.biHeight, 1, 1, nullptr );
543 if( hNewDDB )
544 SetDIBits( hDC, hNewDDB, 0, pBI->bmiHeader.biHeight, pBits, pBI, DIB_RGB_COLORS );
546 else
547 hNewDDB = CreateDIBitmap( hDC, &pBI->bmiHeader, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
549 GlobalUnlock( rSalBmp.mhDIB );
551 if( hNewDDB && GetObjectW( hNewDDB, sizeof( aDDBInfo ), &aDDBInfo ) )
553 mhDDB = hNewDDB;
554 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
555 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
557 bRet = true;
559 else if( hNewDDB )
560 DeleteObject( hNewDDB );
563 return bRet;
566 bool WinSalBitmap::Create(const SalBitmap& rSSalBmp, vcl::PixelFormat eNewPixelFormat)
568 bool bRet = false;
570 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
572 if( rSalBmp.mhDDB )
574 mhDIB = ImplCreateDIB( rSalBmp.maSize, eNewPixelFormat, BitmapPalette() );
576 if( mhDIB )
578 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
579 const int nLines = static_cast<int>(rSalBmp.maSize.Height());
580 HDC hDC = GetDC( nullptr );
581 PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
582 ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
583 SalData* pSalData = GetSalData();
584 HPALETTE hOldPal = nullptr;
586 if ( pSalData->mhDitherPal )
588 hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
589 RealizePalette( hDC );
592 if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
594 GlobalUnlock( mhDIB );
595 maSize = rSalBmp.maSize;
596 mnBitCount = vcl::pixelFormatBitCount(eNewPixelFormat);
597 bRet = true;
599 else
601 GlobalUnlock( mhDIB );
602 GlobalFree( mhDIB );
603 mhDIB = nullptr;
606 if( hOldPal )
607 SelectPalette( hDC, hOldPal, TRUE );
609 ReleaseDC( nullptr, hDC );
613 return bRet;
616 bool WinSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, Size& /*rSize*/, bool bMask )
618 css::uno::Reference< css::beans::XFastPropertySet >
619 xFastPropertySet( rBitmapCanvas, css::uno::UNO_QUERY );
621 if( xFastPropertySet ) {
622 css::uno::Sequence< css::uno::Any > args;
624 if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) {
625 sal_Int64 aHBmp64;
627 if( args[0] >>= aHBmp64 ) {
628 return Create( reinterpret_cast<HANDLE>(aHBmp64) );
632 return false;
635 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
637 sal_uInt16 nColors = 0;
639 if( hDIB )
641 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( hDIB ));
643 if ( pBI->bmiHeader.biSize != sizeof( BITMAPCOREHEADER ) )
645 if( pBI->bmiHeader.biBitCount <= 8 )
647 if ( pBI->bmiHeader.biClrUsed )
648 nColors = static_cast<sal_uInt16>(pBI->bmiHeader.biClrUsed);
649 else
650 nColors = 1 << pBI->bmiHeader.biBitCount;
653 else if( reinterpret_cast<PBITMAPCOREHEADER>(pBI)->bcBitCount <= 8 )
654 nColors = 1 << reinterpret_cast<PBITMAPCOREHEADER>(pBI)->bcBitCount;
656 GlobalUnlock( hDIB );
659 return nColors;
662 HGLOBAL WinSalBitmap::ImplCreateDIB(const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal)
664 HGLOBAL hDIB = nullptr;
666 if( rSize.IsEmpty() )
667 return hDIB;
669 const auto nBits = vcl::pixelFormatBitCount(ePixelFormat);
671 // calculate bitmap size in Bytes
672 const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes(nBits * rSize.Width());
673 const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
674 bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != static_cast<sal_uLong>(rSize.Height());
675 if( bOverflow )
676 return hDIB;
678 // allocate bitmap memory including header and palette
679 sal_uInt16 nColors = 0;
680 if (ePixelFormat <= vcl::PixelFormat::N8_BPP)
681 nColors = vcl::numberOfColors(ePixelFormat);
683 const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
684 bOverflow = (nHeaderSize + nImageSize) < nImageSize;
685 if( bOverflow )
686 return hDIB;
688 hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
689 if( !hDIB )
690 return hDIB;
692 PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
693 PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
695 pBIH->biSize = sizeof( BITMAPINFOHEADER );
696 pBIH->biWidth = rSize.Width();
697 pBIH->biHeight = rSize.Height();
698 pBIH->biPlanes = 1;
699 pBIH->biBitCount = nBits;
700 pBIH->biCompression = BI_RGB;
701 pBIH->biSizeImage = nImageSize;
702 pBIH->biXPelsPerMeter = 0;
703 pBIH->biYPelsPerMeter = 0;
704 pBIH->biClrUsed = 0;
705 pBIH->biClrImportant = 0;
707 if( nColors )
709 // copy the palette entries if any
710 const sal_uInt16 nMinCount = std::min( nColors, rPal.GetEntryCount() );
711 if( nMinCount )
712 memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
715 GlobalUnlock( hDIB );
717 return hDIB;
720 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
722 HANDLE hCopy = nullptr;
724 if ( bDIB && hHdl )
726 const sal_uLong nSize = GlobalSize( hHdl );
728 if ( (hCopy = GlobalAlloc( GHND, nSize )) != nullptr )
730 memcpy( GlobalLock( hCopy ), GlobalLock( hHdl ), nSize );
732 GlobalUnlock( hCopy );
733 GlobalUnlock( hHdl );
736 else if ( hHdl )
738 BITMAP aBmp;
740 // find out size of source bitmap
741 GetObjectW( hHdl, sizeof( aBmp ), &aBmp );
743 // create destination bitmap
744 if ( (hCopy = CreateBitmapIndirect( &aBmp )) != nullptr )
746 HDC hBmpDC = CreateCompatibleDC( nullptr );
747 HBITMAP hBmpOld = static_cast<HBITMAP>(SelectObject( hBmpDC, hHdl ));
748 HDC hCopyDC = CreateCompatibleDC( hBmpDC );
749 HBITMAP hCopyOld = static_cast<HBITMAP>(SelectObject( hCopyDC, hCopy ));
751 BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
753 SelectObject( hCopyDC, hCopyOld );
754 DeleteDC( hCopyDC );
756 SelectObject( hBmpDC, hBmpOld );
757 DeleteDC( hBmpDC );
761 return hCopy;
764 BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
766 std::unique_ptr<BitmapBuffer> pBuffer;
768 if( mhDIB )
770 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
771 PBITMAPINFOHEADER pBIH = &pBI->bmiHeader;
773 if( pBIH->biPlanes == 1 )
775 pBuffer.reset(new BitmapBuffer);
777 pBuffer->mnFormat = pBIH->biBitCount == 1 ? ScanlineFormat::N1BitMsbPal :
778 pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal :
779 pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr :
780 pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcMask :
781 ScanlineFormat::NONE;
783 if( RemoveScanline( pBuffer->mnFormat ) != ScanlineFormat::NONE )
785 pBuffer->mnWidth = maSize.Width();
786 pBuffer->mnHeight = maSize.Height();
787 pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
788 pBuffer->mnBitCount = static_cast<sal_uInt16>(pBIH->biBitCount);
790 if( pBuffer->mnBitCount <= 8 )
792 const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
794 pBuffer->maPalette.SetEntryCount( nPalCount );
795 memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
796 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize + nPalCount * sizeof( RGBQUAD );
798 else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
800 sal_uLong nOffset = 0;
802 if( pBIH->biCompression == BI_BITFIELDS )
804 nOffset = 3 * sizeof( RGBQUAD );
805 ColorMaskElement aRedMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 0 ]));
806 aRedMask.CalcMaskShift();
807 ColorMaskElement aGreenMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 1 ]));
808 aGreenMask.CalcMaskShift();
809 ColorMaskElement aBlueMask(*reinterpret_cast<UINT32*>(&pBI->bmiColors[ 2 ]));
810 aBlueMask.CalcMaskShift();
811 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
813 else if( pBIH->biBitCount == 16 )
815 ColorMaskElement aRedMask(0x00007c00UL);
816 aRedMask.CalcMaskShift();
817 ColorMaskElement aGreenMask(0x000003e0UL);
818 aGreenMask.CalcMaskShift();
819 ColorMaskElement aBlueMask(0x0000001fUL);
820 aBlueMask.CalcMaskShift();
821 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
823 else
825 ColorMaskElement aRedMask(0x00ff0000UL);
826 aRedMask.CalcMaskShift();
827 ColorMaskElement aGreenMask(0x0000ff00UL);
828 aGreenMask.CalcMaskShift();
829 ColorMaskElement aBlueMask(0x000000ffUL);
830 aBlueMask.CalcMaskShift();
831 pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask);
834 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize + nOffset;
836 else
837 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize;
839 else
841 GlobalUnlock( mhDIB );
842 pBuffer.reset();
845 else
846 GlobalUnlock( mhDIB );
849 return pBuffer.release();
852 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
854 if( pBuffer )
856 if( mhDIB )
858 if( nMode == BitmapAccessMode::Write && !!pBuffer->maPalette )
860 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( mhDIB ));
861 const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount();
862 const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB );
863 memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), std::min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
864 GlobalUnlock( mhDIB );
867 GlobalUnlock( mhDIB );
870 delete pBuffer;
872 if( nMode == BitmapAccessMode::Write )
873 InvalidateChecksum();
876 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
878 bool bRet = false;
879 if( mhDIB || mhDDB )
881 bRet = true;
882 rData.pDIB = mhDIB;
883 const Size& rSize = GetSize ();
884 rData.mnWidth = rSize.Width();
885 rData.mnHeight = rSize.Height();
887 return bRet;
890 bool WinSalBitmap::ScalingSupported() const
892 return false;
895 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
897 return false;
900 bool WinSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ )
902 return false;
905 const basegfx::SystemDependentDataHolder* WinSalBitmap::accessSystemDependentDataHolder() const
907 return this;
910 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */