xref: /trunk/main/vcl/win/source/gdi/salbmp.cxx (revision 5f27b83c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24 
25 #include <tools/svwin.h>
26 #include <vcl/bitmap.hxx> // for BitmapSystemData
27 #include <vcl/salbtype.hxx>
28 #include <win/wincomp.hxx>
29 #include <win/salgdi.h>
30 #include <win/saldata.hxx>
31 #include <win/salbmp.h>
32 #include <string.h>
33 #include <vcl/timer.hxx>
34 #include <comphelper/broadcasthelper.hxx>
35 #include <map>
36 
37 #ifndef min
38 #define min(a,b)	(((a) < (b)) ? (a) : (b))
39 #endif
40 #ifndef max
41 #define max(a,b)	(((a) > (b)) ? (a) : (b))
42 #endif
43 
44 #include <GdiPlus.h>
45 
46 // ------------------------------------------------------------------
47 // - Inlines -
48 
49 inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
50 {
51 	BYTE& rByte = pScanline[ nX >> 1 ];
52 
53 	( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
54 				 ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
55 }
56 
57 // ------------------------------------------------------------------
58 // Helper class to manage Gdiplus::Bitmap instances inside of
59 // WinSalBitmap
60 
61 struct Comparator
62 {
63     bool operator()(WinSalBitmap* pA, WinSalBitmap* pB) const
64     {
65         return pA < pB;
66     }
67 };
68 
69 typedef ::std::map< WinSalBitmap*, sal_uInt32, Comparator > EntryMap;
70 static const sal_uInt32 nDefaultCycles(60);
71 
72 class GdiPlusBuffer : protected comphelper::OBaseMutex, public Timer
73 {
74 private:
75     EntryMap        maEntries;
76 
77 public:
78     GdiPlusBuffer()
79     :   Timer(),
80         maEntries()
81     {
82         SetTimeout(1000);
83         Stop();
84     }
85 
86     ~GdiPlusBuffer()
87     {
88         Stop();
89     }
90 
91     void addEntry(WinSalBitmap& rEntry)
92     {
93         ::osl::MutexGuard aGuard(m_aMutex);
94         EntryMap::iterator aFound = maEntries.find(&rEntry);
95 
96         if(aFound == maEntries.end())
97         {
98             if(maEntries.empty())
99             {
100                 Start();
101             }
102 
103             maEntries[&rEntry] = nDefaultCycles;
104         }
105     }
106 
107     void remEntry(WinSalBitmap& rEntry)
108     {
109         ::osl::MutexGuard aGuard(m_aMutex);
110         EntryMap::iterator aFound = maEntries.find(&rEntry);
111 
112         if(aFound != maEntries.end())
113         {
114             maEntries.erase(aFound);
115 
116             if(maEntries.empty())
117             {
118                 Stop();
119             }
120         }
121     }
122 
123     void touchEntry(WinSalBitmap& rEntry)
124     {
125         ::osl::MutexGuard aGuard(m_aMutex);
126         EntryMap::iterator aFound = maEntries.find(&rEntry);
127 
128         if(aFound != maEntries.end())
129         {
130             aFound->second = nDefaultCycles;
131         }
132     }
133 
134     // from parent Timer
135     virtual void Timeout()
136     {
137         ::osl::MutexGuard aGuard(m_aMutex);
138         EntryMap::iterator aIter(maEntries.begin());
139 
140         while(aIter != maEntries.end())
141         {
142             if(aIter->second)
143             {
144                 aIter->second--;
145                 aIter++;
146             }
147             else
148             {
149                 EntryMap::iterator aDelete(aIter);
150                 WinSalBitmap* pSource = aDelete->first;
151                 aIter++;
152                 maEntries.erase(aDelete);
153 
154                 if(maEntries.empty())
155                 {
156                     Stop();
157                 }
158 
159                 // delete at WinSalBitmap after entry is removed; this
160                 // way it would not hurt to call remEntry from there, too
161                 if(pSource->maGdiPlusBitmap.get())
162                 {
163                     pSource->maGdiPlusBitmap.reset();
164                 }
165             }
166         }
167 
168         if(!maEntries.empty())
169         {
170             Start();
171         }
172     }
173 };
174 
175 // ------------------------------------------------------------------
176 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
177 // instances
178 
179 static GdiPlusBuffer aGdiPlusBuffer;
180 
181 // ------------------------------------------------------------------
182 // - WinSalBitmap -
183 
184 WinSalBitmap::WinSalBitmap()
185 :   maSize(),
186     mhDIB(0),
187     mhDDB(0),
188     maGdiPlusBitmap(),
189     mnBitCount(0)
190 {
191 }
192 
193 // ------------------------------------------------------------------
194 
195 WinSalBitmap::~WinSalBitmap()
196 {
197 	Destroy();
198 }
199 
200 // ------------------------------------------------------------------
201 
202 void WinSalBitmap::Destroy()
203 {
204     if(maGdiPlusBitmap.get())
205     {
206         aGdiPlusBuffer.remEntry(*this);
207     }
208 
209     if( mhDIB )
210 		GlobalFree( mhDIB );
211 	else if( mhDDB )
212 		DeleteObject( mhDDB );
213 
214 	maSize = Size();
215 	mnBitCount = 0;
216 }
217 
218 // ------------------------------------------------------------------
219 
220 GdiPlusBmpPtr WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
221 {
222     if(maGdiPlusBitmap.get())
223     {
224         aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this));
225     }
226     else
227     {
228         if(maSize.Width() > 0 && maSize.Height() > 0)
229         {
230             WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this);
231 
232             if(pAlphaSource)
233             {
234                 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource));
235             }
236             else
237             {
238                 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap());
239             }
240 
241             if(maGdiPlusBitmap.get())
242             {
243                 aGdiPlusBuffer.addEntry(*pThat);
244             }
245         }
246     }
247 
248     return maGdiPlusBitmap;
249 }
250 
251 // ------------------------------------------------------------------
252 
253 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap()
254 {
255     Gdiplus::Bitmap* pRetval(0);
256     WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
257     WinSalBitmap* pExtraWinSalRGB = 0;
258 
259     if(!pSalRGB->ImplGethDIB())
260     {
261         // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
262         pExtraWinSalRGB = new WinSalBitmap();
263         pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
264         pSalRGB = pExtraWinSalRGB;
265     }
266 
267     BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true);
268     BitmapBuffer* pExtraRGB = 0;
269 
270     if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
271     {
272         // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
273         SalTwoRect aSalTwoRect;
274 
275         aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
276         aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth;
277         aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight;
278 
279         pExtraRGB = StretchAndConvert(
280             *pRGB,
281             aSalTwoRect,
282             BMP_FORMAT_24BIT_TC_BGR,
283             0);
284 
285         pSalRGB->ReleaseBuffer(pRGB, true);
286         pRGB = pExtraRGB;
287     }
288 
289     if(pRGB
290         && pRGB->mnWidth > 0
291         && pRGB->mnHeight > 0
292         && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
293     {
294         const sal_uInt32 nW(pRGB->mnWidth);
295         const sal_uInt32 nH(pRGB->mnHeight);
296 
297         pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB);
298 
299         if(pRetval)
300         {
301             sal_uInt8* pSrcRGB(pRGB->mpBits);
302             const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
303             const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
304 
305             for(sal_uInt32 y(0); y < nH; y++)
306             {
307                 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
308 
309                 for(sal_uInt32 x(0); x < nW; x++)
310                 {
311                     const sal_uInt8 nB(*pSrcRGB++);
312                     const sal_uInt8 nG(*pSrcRGB++);
313                     const sal_uInt8 nR(*pSrcRGB++);
314 
315                     pRetval->SetPixel(x, nYInsert, Gdiplus::Color(nR, nG, nB));
316                 }
317 
318                 pSrcRGB += nExtraRGB;
319             }
320         }
321     }
322 
323     if(pExtraRGB)
324     {
325         delete pExtraRGB;
326     }
327     else
328     {
329         pSalRGB->ReleaseBuffer(pRGB, true);
330     }
331 
332     if(pExtraWinSalRGB)
333     {
334         delete pExtraWinSalRGB;
335     }
336 
337     return pRetval;
338 }
339 
340 // ------------------------------------------------------------------
341 
342 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
343 {
344     Gdiplus::Bitmap* pRetval(0);
345     WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
346     WinSalBitmap* pExtraWinSalRGB = 0;
347 
348     if(!pSalRGB->ImplGethDIB())
349     {
350         // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
351         pExtraWinSalRGB = new WinSalBitmap();
352         pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
353         pSalRGB = pExtraWinSalRGB;
354     }
355 
356     BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true);
357     BitmapBuffer* pExtraRGB = 0;
358 
359     if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
360     {
361         // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
362         SalTwoRect aSalTwoRect;
363 
364         aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
365         aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth;
366         aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight;
367 
368         pExtraRGB = StretchAndConvert(
369             *pRGB,
370             aSalTwoRect,
371             BMP_FORMAT_24BIT_TC_BGR,
372             0);
373 
374         pSalRGB->ReleaseBuffer(pRGB, true);
375         pRGB = pExtraRGB;
376     }
377 
378     WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
379     WinSalBitmap* pExtraWinSalA = 0;
380 
381     if(!pSalA->ImplGethDIB())
382     {
383         // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
384         pExtraWinSalA = new WinSalBitmap();
385         pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount());
386         pSalA = pExtraWinSalA;
387     }
388 
389     BitmapBuffer* pA = pSalA->AcquireBuffer(true);
390     BitmapBuffer* pExtraA = 0;
391 
392     if(pA && BMP_FORMAT_8BIT_PAL != (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
393     {
394         // convert alpha bitmap to BMP_FORMAT_8BIT_PAL format if not yet in that format
395         SalTwoRect aSalTwoRect;
396 
397         aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
398         aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pA->mnWidth;
399         aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pA->mnHeight;
400         const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
401 
402         pExtraA = StretchAndConvert(
403             *pA,
404             aSalTwoRect,
405             BMP_FORMAT_8BIT_PAL,
406             &rTargetPalette);
407 
408         pSalA->ReleaseBuffer(pA, true);
409         pA = pExtraA;
410     }
411 
412     if(pRGB
413         && pA
414         && pRGB->mnWidth > 0
415         && pRGB->mnHeight > 0
416         && pRGB->mnWidth == pA->mnWidth
417         && pRGB->mnHeight == pA->mnHeight
418         && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)
419         && BMP_FORMAT_8BIT_PAL == (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
420     {
421         // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
422         const sal_uInt32 nW(pRGB->mnWidth);
423         const sal_uInt32 nH(pRGB->mnHeight);
424 
425         pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB);
426 
427         if(pRetval)
428         {
429             sal_uInt8* pSrcRGB(pRGB->mpBits);
430             sal_uInt8* pSrcA(pA->mpBits);
431             const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
432             const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
433             const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
434 
435             for(sal_uInt32 y(0); y < nH; y++)
436             {
437                 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
438 
439                 for(sal_uInt32 x(0); x < nW; x++)
440                 {
441                     const sal_uInt8 nB(*pSrcRGB++);
442                     const sal_uInt8 nG(*pSrcRGB++);
443                     const sal_uInt8 nR(*pSrcRGB++);
444                     const sal_uInt8 nA(0xff - *pSrcA++);
445 
446                     pRetval->SetPixel(x, nYInsert, Gdiplus::Color(nA, nR, nG, nB));
447                 }
448 
449                 pSrcRGB += nExtraRGB;
450                 pSrcA += nExtraA;
451             }
452         }
453     }
454 
455     if(pExtraA)
456     {
457         delete pExtraA;
458     }
459     else
460     {
461         pSalA->ReleaseBuffer(pA, true);
462     }
463 
464     if(pExtraWinSalA)
465     {
466         delete pExtraWinSalA;
467     }
468 
469     if(pExtraRGB)
470     {
471         delete pExtraRGB;
472     }
473     else
474     {
475         pSalRGB->ReleaseBuffer(pRGB, true);
476     }
477 
478     if(pExtraWinSalRGB)
479     {
480         delete pExtraWinSalRGB;
481     }
482 
483     return pRetval;
484 }
485 
486 // ------------------------------------------------------------------
487 
488 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
489 {
490 	bool bRet = TRUE;
491 
492 	if( bDIB )
493 		mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
494 	else
495 		mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
496 
497 	if( mhDIB )
498 	{
499 		PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
500 
501 		maSize = Size( pBIH->biWidth, pBIH->biHeight );
502 		mnBitCount = pBIH->biBitCount;
503 
504 		if( mnBitCount )
505 			mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
506 
507 		GlobalUnlock( mhDIB );
508 	}
509 	else if( mhDDB )
510 	{
511 		BITMAP	aDDBInfo;
512 
513 		if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
514 		{
515 			maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
516 			mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
517 
518 			if( mnBitCount )
519 			{
520 				mnBitCount = ( mnBitCount <= 1 ) ? 1 :
521 							 ( mnBitCount <= 4 ) ? 4 :
522 							 ( mnBitCount <= 8 ) ? 8 : 24;
523 			}
524 		}
525 		else
526 		{
527 			mhDDB = 0;
528 			bRet = FALSE;
529 		}
530 	}
531 	else
532 		bRet = FALSE;
533 
534 	return bRet;
535 }
536 
537 // ------------------------------------------------------------------
538 
539 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
540 {
541 	bool bRet = FALSE;
542 
543 	mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
544 
545 	if( mhDIB )
546 	{
547 		maSize = rSize;
548 		mnBitCount = nBitCount;
549 		bRet = TRUE;
550 	}
551 
552 	return bRet;
553 }
554 
555 // ------------------------------------------------------------------
556 
557 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
558 {
559 	bool bRet = FALSE;
560     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
561 
562 	if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
563 	{
564 		HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
565 										   rSalBitmap.mhDIB != 0 );
566 
567 		if ( hNewHdl )
568 		{
569 			if( rSalBitmap.mhDIB )
570 				mhDIB = (HGLOBAL) hNewHdl;
571 			else if( rSalBitmap.mhDDB )
572 				mhDDB = (HBITMAP) hNewHdl;
573 
574 			maSize = rSalBitmap.maSize;
575 			mnBitCount = rSalBitmap.mnBitCount;
576 
577 			bRet = TRUE;
578 		}
579 	}
580 
581 	return bRet;
582 }
583 
584 // ------------------------------------------------------------------
585 
586 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
587 {
588 	bool bRet = FALSE;
589 
590     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
591     WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
592 
593 	if( rSalBmp.mhDIB )
594 	{
595 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
596 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
597 		HDC 				hDC  = pGraphics->getHDC();
598 		HBITMAP 			hNewDDB;
599 		BITMAP				aDDBInfo;
600 		PBYTE				pBits = (PBYTE) pBI + *(DWORD*) pBI +
601 							ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
602 
603 		if( pBIH->biBitCount == 1 )
604 		{
605 			hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
606 
607 			if( hNewDDB )
608 				SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
609 		}
610 		else
611 			hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
612 
613 		GlobalUnlock( rSalBmp.mhDIB );
614 
615 		if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
616 		{
617 			mhDDB = hNewDDB;
618 			maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
619 			mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
620 
621 			bRet = TRUE;
622 		}
623 		else if( hNewDDB )
624 			DeleteObject( hNewDDB );
625 	}
626 
627 	return bRet;
628 }
629 
630 // ------------------------------------------------------------------
631 
632 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
633 {
634 	bool bRet = FALSE;
635 
636     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
637 
638 	if( rSalBmp.mhDDB )
639 	{
640 		mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
641 
642 		if( mhDIB )
643 		{
644 			PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
645 			const int	nLines = (int) rSalBmp.maSize.Height();
646 			HDC 		hDC = GetDC( 0 );
647 			PBYTE		pBits = (PBYTE) pBI + *(DWORD*) pBI +
648 								ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
649 			SalData*	pSalData = GetSalData();
650 			HPALETTE	hOldPal = 0;
651 
652 			if ( pSalData->mhDitherPal )
653 			{
654 				hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
655 				RealizePalette( hDC );
656 			}
657 
658 			if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
659 			{
660 				GlobalUnlock( mhDIB );
661 				maSize = rSalBmp.maSize;
662 				mnBitCount = nNewBitCount;
663 				bRet = TRUE;
664 			}
665 			else
666 			{
667 				GlobalUnlock( mhDIB );
668 				GlobalFree( mhDIB );
669 				mhDIB = 0;
670 			}
671 
672 			if( hOldPal )
673 				SelectPalette( hDC, hOldPal, TRUE );
674 
675 			ReleaseDC( 0, hDC );
676 		}
677 	}
678 
679 	return bRet;
680 }
681 
682 // ------------------------------------------------------------------
683 
684 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
685 {
686 	sal_uInt16 nColors = 0;
687 
688 	if( hDIB )
689 	{
690 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( hDIB );
691 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
692 
693 		if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
694 		{
695 			if( pBIH->biBitCount <= 8 )
696 			{
697 				if ( pBIH->biClrUsed )
698 					nColors = (sal_uInt16) pBIH->biClrUsed;
699 				else
700 					nColors = 1 << pBIH->biBitCount;
701 			}
702 		}
703 		else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
704 			nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
705 
706 		GlobalUnlock( hDIB );
707 	}
708 
709 	return nColors;
710 }
711 
712 // ------------------------------------------------------------------
713 
714 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
715 {
716 	DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
717 
718 	HGLOBAL hDIB = 0;
719 
720 	if( rSize.Width() <= 0 || rSize.Height() <= 0 )
721 		return hDIB;
722 
723 	// calculate bitmap size in Bytes
724 	const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
725 	const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
726 	bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != rSize.Height();
727 	if( bOverflow )
728 		return hDIB;
729 
730 	// allocate bitmap memory including header and palette
731 	const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
732 	const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
733 	bOverflow = (nHeaderSize + nImageSize) < nImageSize;
734 	if( bOverflow )
735 		return hDIB;
736 
737 	hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
738 	if( !hDIB )
739 		return hDIB;
740 
741 	PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
742 	PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
743 
744 	pBIH->biSize = sizeof( BITMAPINFOHEADER );
745 	pBIH->biWidth = rSize.Width();
746 	pBIH->biHeight = rSize.Height();
747 	pBIH->biPlanes = 1;
748 	pBIH->biBitCount = nBits;
749 	pBIH->biCompression = BI_RGB;
750 	pBIH->biSizeImage = nImageSize;
751 	pBIH->biXPelsPerMeter = 0;
752 	pBIH->biYPelsPerMeter = 0;
753 	pBIH->biClrUsed = 0;
754 	pBIH->biClrImportant = 0;
755 
756 	if( nColors )
757 	{
758 		// copy the palette entries if any
759 		const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
760 		if( nMinCount )
761 			memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
762 	}
763 
764 	GlobalUnlock( hDIB );
765 
766 	return hDIB;
767 }
768 
769 // ------------------------------------------------------------------
770 
771 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
772 {
773 	HANDLE	hCopy = 0;
774 
775 	if ( bDIB && hHdl )
776 	{
777 		const sal_uLong nSize = GlobalSize( hHdl );
778 
779 		if ( (hCopy = GlobalAlloc( GHND, nSize  )) != 0 )
780 		{
781 			memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
782 
783 			GlobalUnlock( hCopy );
784 			GlobalUnlock( hHdl );
785 		}
786 	}
787 	else if ( hHdl )
788 	{
789 		BITMAP aBmp;
790 
791 		// Source-Bitmap nach Groesse befragen
792 		WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
793 
794 		// Destination-Bitmap erzeugen
795 		if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
796 		{
797 			HDC 	hBmpDC = CreateCompatibleDC( 0 );
798 			HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
799 			HDC 	hCopyDC = CreateCompatibleDC( hBmpDC );
800 			HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
801 
802 			BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
803 
804 			SelectObject( hCopyDC, hCopyOld );
805 			DeleteDC( hCopyDC );
806 
807 			SelectObject( hBmpDC, hBmpOld );
808 			DeleteDC( hBmpDC );
809 		}
810 	}
811 
812 	return hCopy;
813 }
814 
815 // ------------------------------------------------------------------
816 
817 BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
818 {
819 	BitmapBuffer* pBuffer = NULL;
820 
821 	if( mhDIB )
822 	{
823 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( mhDIB );
824 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
825 
826 		if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
827 		{
828 			Size	aSizePix( pBIH->biWidth, pBIH->biHeight );
829 			HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
830 
831 			if( hNewDIB )
832 			{
833 				PBITMAPINFO 		pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
834 				PBITMAPINFOHEADER	pNewBIH = (PBITMAPINFOHEADER) pNewBI;
835 				const sal_uInt16		nColorCount = ImplGetDIBColorCount( hNewDIB );
836 				const sal_uLong 		nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
837 				BYTE*				pOldBits = (PBYTE) pBI + nOffset;
838 				BYTE*				pNewBits = (PBYTE) pNewBI + nOffset;
839 
840 				memcpy( pNewBI, pBI, nOffset );
841 				pNewBIH->biCompression = 0;
842 				ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
843 
844 				GlobalUnlock( mhDIB );
845 				GlobalFree( mhDIB );
846 				mhDIB = hNewDIB;
847 				pBI = pNewBI;
848 				pBIH = pNewBIH;
849 			}
850 		}
851 
852 		if( pBIH->biPlanes == 1 )
853 		{
854 			pBuffer = new BitmapBuffer;
855 
856 			pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
857 								( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
858 								  pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
859 								  pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
860 								  pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
861 								  pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
862 								  pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
863 
864 			if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
865 			{
866 				pBuffer->mnWidth = maSize.Width();
867 				pBuffer->mnHeight = maSize.Height();
868 				pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
869 				pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
870 
871 				if( pBuffer->mnBitCount <= 8 )
872 				{
873 					const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
874 
875 					pBuffer->maPalette.SetEntryCount( nPalCount );
876 					memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
877 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
878 				}
879 				else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
880 				{
881 					sal_uLong nOffset = 0UL;
882 
883 					if( pBIH->biCompression == BI_BITFIELDS )
884 					{
885 						nOffset = 3 * sizeof( RGBQUAD );
886 						pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
887 														  *(UINT32*) &pBI->bmiColors[ 1 ],
888 														  *(UINT32*) &pBI->bmiColors[ 2 ] );
889 					}
890 					else if( pBIH->biBitCount == 16 )
891 						pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
892 					else
893 						pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
894 
895 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
896 				}
897 				else
898 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
899 			}
900 			else
901 			{
902 				GlobalUnlock( mhDIB );
903 				delete pBuffer;
904 				pBuffer = NULL;
905 			}
906 		}
907 		else
908 			GlobalUnlock( mhDIB );
909 	}
910 
911 	return pBuffer;
912 }
913 
914 // ------------------------------------------------------------------
915 
916 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
917 {
918 	if( pBuffer )
919 	{
920 		if( mhDIB )
921 		{
922 			if( !bReadOnly && !!pBuffer->maPalette )
923 			{
924 				PBITMAPINFO 	pBI = (PBITMAPINFO) GlobalLock( mhDIB );
925 				const sal_uInt16	nCount = pBuffer->maPalette.GetEntryCount();
926 				const sal_uInt16	nDIBColorCount = ImplGetDIBColorCount( mhDIB );
927 				memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
928 				GlobalUnlock( mhDIB );
929 			}
930 
931 			GlobalUnlock( mhDIB );
932 		}
933 
934 		delete pBuffer;
935 	}
936 }
937 
938 // ------------------------------------------------------------------
939 
940 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
941 									 const Size& rSizePixel, bool bRLE4 )
942 {
943 	HPBYTE			pRLE = (HPBYTE) pSrcBuf;
944 	HPBYTE			pDIB = (HPBYTE) pDstBuf;
945 	HPBYTE			pRow = (HPBYTE) pDstBuf;
946 	sal_uLong			nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
947 	HPBYTE			pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
948 	sal_uLong			nCountByte;
949 	sal_uLong			nRunByte;
950 	sal_uLong			nX = 0;
951 	sal_uLong			i;
952 	BYTE			cTmp;
953 	bool			bEndDecoding = FALSE;
954 
955 	if( pRLE && pDIB )
956 	{
957 		do
958 		{
959 			if( ( nCountByte = *pRLE++ ) == 0 )
960 			{
961 				nRunByte = *pRLE++;
962 
963 				if( nRunByte > 2UL )
964 				{
965 					if( bRLE4 )
966 					{
967 						nCountByte = nRunByte >> 1UL;
968 
969 						for( i = 0; i < nCountByte; i++ )
970 						{
971 							cTmp = *pRLE++;
972 							ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
973 							ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
974 						}
975 
976 						if( nRunByte & 1 )
977 							ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
978 
979 						if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
980 							pRLE++;
981 					}
982 					else
983 					{
984 						memcpy( &pDIB[ nX ], pRLE, nRunByte );
985 						pRLE += nRunByte;
986 						nX += nRunByte;
987 
988 						if( nRunByte & 1 )
989 							pRLE++;
990 					}
991 				}
992 				else if( !nRunByte )
993 				{
994 					pDIB = ( pRow += nWidthAl );
995 					nX = 0UL;
996 				}
997 				else if( nRunByte == 1 )
998 					bEndDecoding = TRUE;
999 				else
1000 				{
1001 					nX += *pRLE++;
1002 					pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1003 				}
1004 			}
1005 			else
1006 			{
1007 				cTmp = *pRLE++;
1008 
1009 				if( bRLE4 )
1010 				{
1011 					nRunByte = nCountByte >> 1;
1012 
1013 					for( i = 0; i < nRunByte; i++ )
1014 					{
1015 						ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1016 						ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
1017 					}
1018 
1019 					if( nCountByte & 1 )
1020 						ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1021 				}
1022 				else
1023 				{
1024 					for( i = 0; i < nCountByte; i++ )
1025 						pDIB[ nX++ ] = cTmp;
1026 				}
1027 			}
1028 		}
1029 		while( !bEndDecoding && ( pDIB <= pLast ) );
1030 	}
1031 }
1032 
1033 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1034 {
1035     bool bRet = false;
1036     if( mhDIB || mhDDB )
1037     {
1038         bRet = true;
1039         rData.pDIB = mhDIB;
1040         rData.pDDB = mhDDB;
1041         const Size& rSize = GetSize ();
1042         rData.mnWidth = rSize.Width();
1043         rData.mnHeight = rSize.Height();
1044     }
1045     return bRet;
1046 }
1047